#!/usr/bin/python import sys import collections # otočení 0 = vodorovně, 1 = svisle # Načti pozici a cíl # x, y, délka, otočení vstup = list(sys.stdin) start = list(map(int, vstup[0].split())) # x, y cil = tuple(map(int, vstup[1].split())) # Zbytek mapy mapa = list(map(lambda l: l.strip(), vstup[2:])) fronta = collections.deque() # Počáteční pozice. Máme pozici, délku, otočení, žádnou zastávku, žádná předchozí pozice pocatecni_pozice = (tuple(start[:2]), start[2], start[3], None, None) fronta.append(pocatecni_pozice) # Označení již spatřených pozic spatrene = set() spatrene.add(pocatecni_pozice[:4]) # Políčka, na kterých sedí autobus def policka(pozice): vysledek = [] policko = list(pozice[0]) for i in range(0, pozice[1]): vysledek.append(tuple(policko)) policko[pozice[2]] += 1 return vysledek # Dostal se autobus do cile? def v_cili(pozice): for policko in policka(pozice): if policko == cil: return True return False # Rozměry (předpokládáme obdélníkovou mapu) v = len(mapa) s = len(mapa[0]) # Pro každé políčko mapy 4 položky (4 různé směry čtverců) policko = lambda x: [0, 0, 0, 0] radek = lambda y: list(map(policko, range(0, s + 1))) ctverce = list(map(radek, range(0, v + 1))) # Každý rozměr je o 1 větší - abychom nemuseli řešit přetékání # přes okraj, dáme si tam nuly. Index -1 přeteče do nejvyššího, # což je také ten přidaný. def ctvercuj(x, y, maxx, maxy, difx, dify, index): origx = x while y != maxy: x = origx while x != maxx: if mapa[y][x] == '#': # Tady je zeď, žádný čtverec se sem nevejde. ctverce[y][x][index] = 0 else: ctverce[y][x][index] = 1 + min( ctverce[y - dify][x][index], ctverce[y - dify][x - difx][index], ctverce[y][x - difx][index]) x += difx y += dify ctvercuj(0, 0, s, v, 1, 1, 0) # Doleva nahoru ctvercuj(0, v - 1, s, -1, 1, -1, 1) # Doleva dolů ctvercuj(s - 1, 0, -1, v, -1, 1, 2) # Doprava nahoru ctvercuj(s - 1, v - 1, -1, -1, -1, -1, 3) # Doprava dolů # Posuň pozici o kolik v dané souřadnici. def posun(pozice, souradnice, kolik): return tuple(map(lambda index, hodnota: (index==souradnice) * kolik + hodnota, [0, 1], pozice)) # Zkus popojet autobusem, zkontroluj, že to v tom směru jde # (s omezením na okraje mapy, zdi, zastávky a tak). Pokud ano, # přidej novou pozici do seznamu. def popojed(celo, pozice, delka, otoceni, smer, zastavka, predchozi, vysledek): celo = posun(celo, otoceni, smer) for i in [0, 1]: if celo[i] < 0: return # Mimo mapu try: policko = mapa[celo[1]][celo[0]] except IndexError: return # Vyběhli jsme z mapy if policko == '#': return # Do zdi nejezdi if policko == '-' and delka == 1: return # Nemá kdo vystoupit if policko != '.': # Zastávka if celo == zastavka: return # Snažíme se vjet do poslední navštívené zastávky zastavka = celo if policko == '+': delka += 1 else: delka -= 1 if smer == -1 or policko == '.': # Pokud jedeme nahoru nebo doleva, posouváme pozici vždy. # Pokud je to obyč políčko, tak i při cestě dolů/doprava pozice = posun(pozice, otoceni, smer) elif policko == '-': # Pozice se posune dvakrát, protože se zkrátí pozice = posun(pozice, otoceni, 2 * smer) # Při prodloužení zůstane na stejném místě vysledek.append((pozice, delka, otoceni, zastavka, predchozi)) # Zkusí, jestli jde daným způsobem otočit autobus (nic tomu nepřekáží) # a pokud ano, nageneruje do výsledku pozici po otočení. def otoc(aktualni_pozice, nova_pozice, delka, otoceni, zastavka, predchozi, ctverec, vysledek): print(aktualni_pozice) if ctverce[aktualni_pozice[1]][aktualni_pozice[0]][ctverec] >= delka: # Zde bychom také mohli řešit zastávky. Ale pro jednoduchost předpokládejme, # že do zastávky se jezdí ukázněně a ne točením. vysledek.append((nova_pozice, delka, 1-otoceni, zastavka, predchozi)) # Sousední pozice (nemusí znamenat jen políčka) # Vždy máme až 6 možností - přesun do obou směrů, rotace okolo obou # konců na obě strany. Ne všechny musí fungovat. # # Tohle sice vypadá složitě, ale je to jen technická pasáž. Jde o to # probrat všechny možnosti, co lze udělat a zkontrolovat, že to opravdu # jde udělat. def sousedi(cela_pozice): print(cela_pozice) vysledek = [] (pozice, delka, otoceni, zastavka, predchozi) = cela_pozice # Doleva/nahoru popojed(pozice, pozice, delka, otoceni, -1, zastavka, cela_pozice, vysledek) # Doprava/dolu (konec uvazujeme ten dolni) popojed(posun(pozice, otoceni, delka - 1), pozice, delka, otoceni, 1, zastavka, cela_pozice, vysledek) # Otočení (po/proti směru, kolem obou konců) if otoceni: # Jsme svisle otoc(pozice, pozice, delka, otoceni, zastavka, cela_pozice, 3, vysledek) # Proti směru okolo horního konce otoc(pozice, posun(pozice, 0, - delka + 1), delka, otoceni, zastavka, cela_pozice, 1, vysledek) # Po směru okolo horního konce otoc(pozice, posun(pozice, 1, delka - 1), delka, otoceni, zastavka, cela_pozice, 3, vysledek) # Po směru okolo dolního otoc(pozice, posun(posun(pozice, 0, - delka + 1), 1, delka - 1), delka, otoceni, zastavka, cela_pozice, 1, vysledek) # Proti směru okolo dolního else: # Jsme vodorovně otoc(pozice, pozice, delka, otoceni, zastavka, cela_pozice, 3, vysledek) # Po směru okolo levého konce otoc(pozice, posun(pozice, 1, - delka + 1), delka, otoceni, zastavka, cela_pozice, 2, vysledek) # Proti směru okolo levého konce otoc(pozice, posun(posun(pozice, 0, delka - 1), 1, - delka + 1), delka, otoceni, zastavka, cela_pozice, 2, vysledek) # Po směru kolem pravého otoc(pozice, posun(pozice, 0, delka - 1), delka, otoceni, zastavka, cela_pozice, 3, vysledek) # Proti směru kolem pravého return vysledek # Jednoduché BFS s frontou a značením navštívených pozic nalezeno = None while not nalezeno: try: pozice = fronta.popleft() except IndexError: # Došla fronta, nejde to :-( print("Cesta neexistuje") sys.exit() if v_cili(pozice): nalezeno = pozice else: # Přidej všechny sousedy, co jsme ještě nepotkali for soused in sousedi(pozice): if not soused[:4] in spatrene: spatrene.add(soused[:4]) fronta.append(soused) # Zrekonstruuj cestu, pozpátku cesta = [] while nalezeno: cesta.append(nalezeno[:3]) nalezeno = nalezeno[4] # Vypiš ji ve správném pořadí cesta.reverse() print(cesta)