From 0400df0edeb5057fa479ef0512864681dd6a7204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C5=A1per=20Dobrovoljc?= Date: Thu, 7 Dec 2023 22:54:18 +0100 Subject: [PATCH] 07_kronometer --- .idea/.gitignore | 8 + .idea/domace_naloge.iml | 8 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + 07_kronometer/__init__.py | 0 07_kronometer/naloga.py | 391 ++++++++++++++++++ 8 files changed, 434 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/domace_naloge.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 07_kronometer/__init__.py create mode 100644 07_kronometer/naloga.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/domace_naloge.iml b/.idea/domace_naloge.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/domace_naloge.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6b8be7e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f547b2d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/07_kronometer/__init__.py b/07_kronometer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/07_kronometer/naloga.py b/07_kronometer/naloga.py new file mode 100644 index 0000000..d892bd2 --- /dev/null +++ b/07_kronometer/naloga.py @@ -0,0 +1,391 @@ +import operator +from itertools import pairwise, groupby + + +def cas_za_povezavo(povezava, pribitki): + return 4 + sum(pribitki[vescina] for vescina in zemljevid[povezava]) + + +def cas(pot, pribitki): + return sum(cas_za_povezavo(povezava, pribitki) for povezava in pairwise(pot)) + + +def povezava_spotike(pribitki): + return max(reversed(zemljevid), key=lambda povezava: cas_za_povezavo(povezava, pribitki)) + + +def urnik(pot, pribitki): + cas_od_zacetka = 0 + urnik_dict = dict() + urnik_dict[pot[0]] = 0 + for povezava in pairwise(pot): + cas_od_zacetka += cas_za_povezavo(povezava, pribitki) + if povezava[1] not in urnik_dict: + urnik_dict[povezava[1]] = cas_od_zacetka + return urnik_dict + + +def skupinski_sport(pot, pribitkii): + return sum(max(cas_za_povezavo(povezava, pribitki) for pribitki in pribitkii) for povezava in pairwise(pot)) + + +def tekma(pot, pribitkii): + _, kol = min( + [(k, list(v)) for k, v in + groupby(sorted(((i, sum(cas_za_povezavo(povezava, pribitki) for povezava in pairwise(pot))) for i, pribitki in + enumerate(pribitkii)), key=operator.itemgetter(1)), key=operator.itemgetter(1))], + key=lambda x: x[0]) + + if len(kol) > 1: + return None + + return kol[0][0] + + +def cas_za_povezavo_trening(povezava, pribitki): + s = 4 + for vescina in zemljevid[povezava]: + s += pribitki[vescina] + pribitki[vescina] *= 0.95 + return s + + +def trening(pot, pribitki): + return sum(cas_za_povezavo_trening(povezava, pribitki) for povezava in pairwise(pot)) + + +def zastavice(pot, pribitkii): + tocke = dict() + + for i, pribitki in enumerate(pribitkii): + for tocka, time in urnik(pot, pribitki).items(): + if tocka in tocke: + (_, prev_time) = tocke[tocka] + if prev_time <= time: + continue + tocke[tocka] = (i, time) + + return [len([i for a, _ in tocke.values() if a == i]) for i, _ in enumerate(pribitkii)] + + +def najkrajsa_povezava(tocka, prejsnja, pribitki): + povezave = [povezava for povezava in zemljevid if povezava[0] == tocka and povezava[1] != prejsnja] + return min(povezave, key=lambda povezava: cas_za_povezavo(povezava, pribitki)) + + +def cikel(zacetna_tocka, pribitki): + prevozene = [] + tocka = zacetna_tocka + prejsnja = None + while True: + povezava = najkrajsa_povezava(tocka, prejsnja, pribitki) + if povezava in prevozene: + return len(prevozene) - prevozene.index(povezava) + prevozene.append(povezava) + prejsnja = tocka + tocka = povezava[1] + + +def urnik2(pot, pribitki): + cas_od_zacetka = 0 + urnik_list = [(pot[0], 0)] + for povezava in pairwise(pot): + cas_od_zacetka += cas_za_povezavo(povezava, pribitki) + urnik_list.append((povezava[1], cas_od_zacetka)) + return urnik_list + + +def izpadanje(poti, pribitkii): + timetable = dict() + + for kolesar, pot in enumerate(poti): + for tocka, time in urnik2(pot, pribitkii[kolesar]): + if time not in timetable: + timetable[time] = dict() + if tocka not in timetable[time]: + timetable[time][tocka] = set() + timetable[time][tocka].add(kolesar) + + pobrane = set() + izpadli = [] + + for time, tocke in sorted(timetable.items()): + for tocka, kolesarji in tocke.items(): + # Odstrani kolesarje, ki so že izpadli + kolesarji = [kolesar for kolesar in kolesarji if kolesar not in izpadli] + if len(kolesarji) == 0: + # Ni kolesarja, ki bi pobral zastavico (vsi so izpadli) + continue + if tocka in pobrane: + # Izpadejo vsi na tej točki + izpadli.extend(kolesarji) + else: + # Poberi zastavico + pobrane.add(tocka) # Dodaj točko v pobrane zastavice + izpadli.extend(kolesarji[1:]) # Izpadi vse kolesarje razen prvega + + return izpadli + + +import unittest + +A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, R, S, T, U, V = "ABCDEFGHIJKLMNOPRSTUV" + +zemljevid = { + (A, B): {'trava', 'gravel'}, + (B, A): {'trava', 'gravel'}, + (A, V): {'lonci', 'pešci'}, + (V, A): {'lonci', 'pešci'}, + (B, C): {'lonci', 'bolt'}, + (C, B): {'lonci', 'bolt'}, + (B, V): set(), + (V, B): set(), + (C, R): {'lonci', 'pešci', 'stopnice'}, + (R, C): {'lonci', 'pešci', 'stopnice'}, + (D, F): {'pešci', 'stopnice'}, + (F, D): {'pešci', 'stopnice'}, + (D, R): {'pešci'}, + (R, D): {'pešci'}, + (E, I): {'lonci', 'trava'}, + (I, E): {'lonci', 'trava'}, + (F, G): {'črepinje', 'trava'}, + (G, F): {'črepinje', 'trava'}, + (G, H): {'pešci', 'črepinje'}, + (H, G): {'pešci', 'črepinje'}, + (G, I): {'avtocesta'}, + (I, G): {'avtocesta'}, + (H, J): {'bolt', 'robnik'}, + (J, H): {'bolt', 'robnik'}, + (I, M): {'avtocesta'}, + (M, I): {'avtocesta'}, + (I, P): {'gravel'}, + (P, I): {'gravel'}, + (I, R): {'stopnice', 'robnik'}, + (R, I): {'stopnice', 'robnik'}, + (J, K): set(), + (K, J): set(), + (J, L): {'bolt', 'gravel'}, + (L, J): {'bolt', 'gravel'}, + (K, M): {'bolt', 'stopnice'}, + (M, K): {'bolt', 'stopnice'}, + (L, M): {'pešci', 'robnik'}, + (M, L): {'pešci', 'robnik'}, + (M, N): {'rodeo'}, + (N, M): {'rodeo'}, + (N, P): {'gravel'}, + (P, N): {'gravel'}, + (O, P): {'gravel'}, + (P, O): {'gravel'}, + (P, S): set(), + (S, P): set(), + (R, U): {'pešci', 'trava'}, + (U, R): {'pešci', 'trava'}, + (R, V): {'lonci', 'pešci'}, + (V, R): {'lonci', 'pešci'}, + (S, T): {'robnik', 'trava'}, + (T, S): {'robnik', 'trava'}, + (T, U): {'trava', 'gravel'}, + (U, T): {'trava', 'gravel'}, + (U, V): {'lonci', 'robnik', 'trava'}, + (V, U): {'lonci', 'robnik', 'trava'} +} + +pribitki1 = dict(gravel=2, trava=3, lonci=1, bolt=2, pešci=4, + stopnice=3, avtocesta=5, črepinje=1, robnik=1, + rodeo=4) + +pribitki2 = dict(gravel=2, trava=3, lonci=1, bolt=100, pešci=4, + stopnice=3, avtocesta=5, črepinje=1, robnik=1, + rodeo=4) + +pribitki3 = dict(gravel=2, trava=3, lonci=100, bolt=2, pešci=4, + stopnice=3, avtocesta=5, črepinje=1, robnik=1, + rodeo=4) + +pribitki4 = dict(gravel=2, trava=3, lonci=1, bolt=2, pešci=100, + stopnice=3, avtocesta=5, črepinje=1, robnik=1, + rodeo=4) + + +class Test06(unittest.TestCase): + def test_01_cas_za_povezavo(self): + self.assertEqual(4 + 1 + 2, cas_za_povezavo((A, B), dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2))) + self.assertEqual(4 + 2 + 2, cas_za_povezavo((H, J), dict(gravel=1, trava=2, robnik=2, avtocesta=5, bolt=2))) + self.assertEqual(4 + 5, cas_za_povezavo((G, I), dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2))) + self.assertEqual(4, cas_za_povezavo((S, P), dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2))) + self.assertEqual(4 + 2 + 3, cas_za_povezavo((A, B), pribitki1)) + self.assertEqual(4 + 2 + 1, cas_za_povezavo((B, C), pribitki1)) + self.assertEqual(4 + 3 + 5, cas_za_povezavo((C, R), pribitki1)) + self.assertEqual(4 + 4, cas_za_povezavo((R, D), pribitki1)) + self.assertEqual(4 + 3 + 4, cas_za_povezavo((D, F), pribitki1)) + self.assertEqual(4 + 3 + 1, cas_za_povezavo((F, G), pribitki1)) + + def test_02_cas(self): + self.assertEqual(9 + 7 + 3 * 12 + 8 + 11 + 8, cas("ABCRCRDFG", pribitki1)) + self.assertEqual(9, cas("AB", pribitki1)) + self.assertEqual(7, cas("AB", dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2))) + self.assertEqual(7 + 21, cas("ABC", dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2, lonci=15))) + self.assertEqual(8, cas("SPS", dict(gravel=1, trava=2, robnik=3, avtocesta=5, bolt=2, lonci=15))) + + def test_03_povezava_spotike(self): + self.assertEqual((R, C), povezava_spotike(pribitki1)) + pribitki = pribitki1.copy() + pribitki["avtocesta"] = 100 + self.assertEqual((M, I), povezava_spotike(pribitki)) + + pribitki = dict.fromkeys(pribitki1, 0) # vsi pribitki so 0, razen: + pribitki["staopnice"] = pribitki["bolt"] = 1 + self.assertEqual((M, K), povezava_spotike(pribitki)) + + +class Test07(unittest.TestCase): + def test_01_urnik(self): + self.assertEqual(dict(A=0, B=9, C=16, R=28, D=60, F=71, G=79), urnik("ABCRCRDFG", pribitki1)) + + pribitki = dict.fromkeys(pribitki1, 0) # vsi pribitki so 0, razen: + self.assertEqual(dict(A=0, B=4, C=8, R=12, D=24, F=28, G=32), urnik("ABCRCRDFG", pribitki)) + + pribitki["lonci"] = 1 + self.assertEqual(dict(A=0, B=4, C=9, R=14, D=28, F=32, G=36), urnik("ABCRCRDFG", pribitki)) + + def test_02_skupinski_sport(self): + self.assertEqual(9 + 7 + 3 * 12 + 8 + 11 + 8, skupinski_sport("ABCRCRDFG", [pribitki1])) + self.assertEqual(177, skupinski_sport("ABCRCRDFG", [pribitki1, pribitki2])) + self.assertEqual(177, skupinski_sport("ABCRCRDFG", [pribitki1, pribitki2, pribitki2])) + self.assertEqual(475, skupinski_sport("ABCRCRDFG", [pribitki1, pribitki2, pribitki2, pribitki3])) + + def test_03_tekma(self): + # pribitki1 je hitrejši od pribitki2, pribitki2 je hitrejši od pribitki3 + self.assertEqual(0, tekma("ABCRDF", [pribitki2])) + self.assertEqual(0, tekma("ABCRDF", [pribitki2, pribitki3])) + self.assertEqual(1, tekma("ABCRDF", [pribitki3, pribitki2])) + self.assertEqual(2, tekma("ABCRDF", [pribitki3, pribitki2, pribitki1])) + self.assertIsNone(tekma("ABCRDF", [pribitki1, pribitki2, pribitki1])) + self.assertIsNone(tekma("ABCRDF", [pribitki3, pribitki1, pribitki2, pribitki1])) + self.assertIsNone(tekma("ABCRDF", [pribitki3, pribitki1, pribitki1, pribitki2])) + self.assertEqual(0, tekma("ABCRDF", [pribitki1, pribitki2, pribitki2])) + self.assertEqual(1, tekma("ABCRDF", [pribitki2, pribitki1, pribitki2])) + self.assertEqual(2, tekma("ABCRDF", [pribitki2, pribitki2, pribitki1])) + + +class Test08(unittest.TestCase): + def test_01_trening(self): + pribitki = pribitki1.copy() + self.assertAlmostEqual(4 + 2 + 3, trening("AB", pribitki)) + + pribitki = pribitki1.copy() + self.assertAlmostEqual(4 + 2 + 3 + 4 + 2 * 0.95 + 3 * 0.95, trening("ABA", pribitki)) + + pribitki = pribitki1.copy() + self.assertAlmostEqual(4 + 2 + 3, trening("AB", pribitki)) + self.assertAlmostEqual(4 + 2 * 0.95 + 3 * 0.95, trening("BA", pribitki), + "Je nekdo pozabil spremeniti `pribitki`?") + + pribitki = pribitki1.copy() + self.assertAlmostEqual(75.787025, trening("ABCRCRDFG", pribitki)) + + def test_02_zastavice(self): + # pribitki1 je hiter + # pribitki2 zmrzne na BC zaradi bolta, potem je hiter + # pribitki3 zmrzne na BC in CR zaradi loncev + # pribitki4 je hitro čez BC, na CR, CD, DF ga ustavijo pešci + self.assertEqual([7], zastavice("ABCRCRDFG", [pribitki1])) + self.assertEqual([7], zastavice("ABCRCRDFG", [pribitki2])) + self.assertEqual([7, 0], zastavice("ABCRCRDFG", [pribitki1, pribitki1])) + self.assertEqual([7, 0], zastavice("ABCRCRDFG", [pribitki1, pribitki2])) + self.assertEqual([2, 5], zastavice("ABCRCRDFG", [pribitki2, pribitki1])) + self.assertEqual([5, 2], zastavice("ABCRCRDFG", [pribitki2, pribitki4])) + self.assertEqual([4, 3], zastavice("ABCRCRDFG", [pribitki3, pribitki4])) + self.assertEqual([5, 2], zastavice("ABCRCRDFG", [pribitki4, pribitki3])) + self.assertEqual([5, 2, 0], zastavice("ABCRCRDFG", [pribitki2, pribitki4, pribitki3])) + self.assertEqual([2, 3, 2], zastavice("ABCRCRDFG", [pribitki3, pribitki2, pribitki4])) + + +class Test09(unittest.TestCase): + def test_01_cikel(self): + try: + zemljevid2 = zemljevid.copy() + for p in ((O, P), (I, E)): + del zemljevid[p] + del zemljevid[p[::-1]] + + self.assertEqual(3, cikel("A", pribitki1)) # cikel je ABV + self.assertEqual(3, cikel("B", pribitki1)) # cikel je BVA + self.assertEqual(16, cikel("R", pribitki1)) # RDFGHJKMNPSTUVBC + self.assertEqual(16, cikel("U", pribitki1)) # isti + self.assertEqual(16, cikel("L", pribitki1)) # isti; pazi, ne vsebuje L-ja! + self.assertEqual(16, cikel("I", pribitki1)) # isti; pazi, ne vsebuje I-ja! + + pribitki = {v: i for i, v in enumerate(sorted(pribitki1))} + self.assertEqual(3, cikel("B", pribitki)) # cikel je BVA + self.assertEqual(3, cikel("C", pribitki)) # isti cikel - iz C gre v B + self.assertEqual(11, cikel("A", pribitki)) # cikel je RDFGIMNPSTU, do njega pride po ABVC + self.assertEqual(11, cikel("V", pribitki)) # isto + self.assertEqual(6, cikel("J", pribitki)) # JKMIGH + self.assertEqual(6, cikel("L", pribitki)) # isto, iz L gre v JKMIGH + + finally: + zemljevid.update(zemljevid2) + + +class Test10(unittest.TestCase): + def test_01_izpadanje(self): + ni_pribitkov = dict.fromkeys(pribitki1, 0) + self.assertEqual([], izpadanje(["UVB", "SPIM"], [ni_pribitkov] * 2)) + self.assertEqual([], izpadanje(["UVBCR", "SP"], [ni_pribitkov] * 2)) + + # 0 izloči 1 v I + self.assertEqual([1], izpadanje(["URIE", "TSPIG"], [ni_pribitkov] * 2)) + # 1 izloči 0 v I + self.assertEqual([0], izpadanje(["TSPIG", "URIE"], [ni_pribitkov] * 2)) + # hkrati v I, vendar je izločen tisti z večjim indeksom + self.assertEqual([1], izpadanje(["SPIG", "URIE"], [ni_pribitkov] * 2)) + self.assertEqual([1], izpadanje(["URIE", "SPIG"], [ni_pribitkov] * 2)) + + # 2 prehiti ostala dva v I + self.assertEqual([0, 1], izpadanje(["URIE", "SPIG", "GIM"], [ni_pribitkov] * 3)) + self.assertEqual([1, 0], izpadanje(["VURIE", "SPIG", "GIM"], [ni_pribitkov] * 3)) + + # 2 ju ne prehiti, ker obstane na avtocesti + avtocesta = ni_pribitkov.copy() + avtocesta["avtocesta"] = 100 + self.assertEqual([0, 2], izpadanje(["VURIE", "SPI", "GIM"], [ni_pribitkov, ni_pribitkov, avtocesta])) + self.assertEqual([0, 1, 2], izpadanje(["VURIE", "SPIG", "GIM"], [ni_pribitkov, ni_pribitkov, avtocesta])) + self.assertEqual([1, 2, 0], izpadanje(["GIM", "SPIG", "VURIE"], [avtocesta, ni_pribitkov, ni_pribitkov])) + + # ničti izrine prvega (na P), zato prvi na izrine zadnjega, čeprav je ta na I precej pozneje + self.assertEqual([1], izpadanje(["PNMKJ", "SPI", "GIE"], [ni_pribitkov, ni_pribitkov, avtocesta])) + # ... isto, s premešanimi mesti + self.assertEqual([0], izpadanje(["SPI", "PNMKJ", "GIE"], [ni_pribitkov, ni_pribitkov, avtocesta])) + self.assertEqual([1], izpadanje(["GIE", "SPI", "PNMKJ"], [avtocesta, ni_pribitkov, ni_pribitkov])) + self.assertEqual([2], izpadanje(["GIE", "PNMKJ", "SPI"], [avtocesta, ni_pribitkov, ni_pribitkov])) + # ničti izrine prvega na P, drugega na I + self.assertEqual([1, 2], izpadanje(["PNMIR", "SPI", "GIE"], [ni_pribitkov, ni_pribitkov, avtocesta])) + # ... isto, s premešanimi mesti + self.assertEqual([0, 2], izpadanje(["SPI", "PNMIR", "GIE"], [ni_pribitkov, ni_pribitkov, avtocesta])) + self.assertEqual([2, 0], izpadanje(["GIE", "PNMIR", "SPI"], [avtocesta, ni_pribitkov, ni_pribitkov])) + self.assertEqual([2, 1], izpadanje(["PNMIR", "GIE", "SPI"], [ni_pribitkov, avtocesta, ni_pribitkov])) + self.assertEqual([2, 1], izpadanje(["SPI", "GIE", "SPI"], [ni_pribitkov, avtocesta, ni_pribitkov])) + # ničti izrine prvega, zatem pa drugi ničtega na I (ker nima pribitka na avtocesti!) + self.assertEqual([1, 0], izpadanje(["PNMIR", "SPI", "GIE"], [ni_pribitkov, ni_pribitkov, ni_pribitkov])) + + # vmes se še tretji ustreli v nogo + self.assertEqual([1, 3, 0], izpadanje(["PNMIR", "SPI", "GIE", "DFD"], [ni_pribitkov] * 4)) + # ničti izrine prvega na P, drugega na I + self.assertEqual([1, 3, 2], izpadanje(["PNMIR", "SPI", "GIE", "DFD"], + [ni_pribitkov, ni_pribitkov, avtocesta, ni_pribitkov])) + + pribitki5 = dict(gravel=4, trava=1, lonci=5, bolt=0, pešci=2, + stopnice=4, avtocesta=1, črepinje=3, robnik=3, + rodeo=2) + pribitki6 = dict(gravel=1, trava=1, lonci=2, bolt=3, pešci=1, + stopnice=1, avtocesta=3, črepinje=1, robnik=2, + rodeo=4) + self.assertEqual([1, 3, 4, 0], izpadanje(["ABCRVUTSP", "DRCBVUT", "EI", "GHJKMNPOPS", "SPNMK"], + [pribitki1, pribitki5, pribitki1, pribitki6, pribitki1])) + self.assertEqual([1, 4, 3, 0], izpadanje(["ABCRVUTSP", "DRCBVUT", "EI", "GHJKMNPOPS", "SPNMK"], + [pribitki5, pribitki5, pribitki6, pribitki1, pribitki1])) + + +if __name__ == "__main__": + unittest.main()