Lektion 2: Sökagenter Robin Keskisärkkä
Lektionens innehåll Introduktion till laboration 2 Implementation av en sökalgoritm Livekodning Konfrontera ett liknande problem själva Extra: Heuristisk sökning
Laboration 2 Del 1 Uppdatera agentens State för att kunna representera agentens och omgivningens tillstånd i en fullt observerbar värld Generera nya tillstånd baserat på handlingar Del 2 Implementera en bredden-först sökning Diskussion VG-uppgift Implementera en heuristik (A* sökning)
Kartan Dictionary med koordinater (x, y) som nycklar Pacman börjar på (1,1) med riktning öst (1,0) Möjliga värden är w (vägg) och * (mat) Varning: Tomma koordinater finns inte med i kartan!
Position Position API:t kan användas för att arbeta med riktningar och koordinatförflyttningar Returnerar den koordinat som skulle bli resultatet av en viss handling Varning: Kan returnera otillåtna positioner! Tips: Kör help(position) i ett skalfönster/shell
Live kodning
Problem: Tower of Hanoi Flytta alla brickor från pinne A till pinne C. Endast en bricka får flyttas i taget och en större bricka får aldrig placeras på en mindre. Bilder hämtade ifrån: http://www.mclelun.com/blog/2011/07/tower-of-hanoi-flash-game-fla-source/
Hur formaliserar vi problemet? 1. Hur representerar vi tillstånd i världen? 2. Hur vet vi när vi har nått målet? 3. Vilka drag är tillåtna?
Hur representerar vi tillstånd i världen? Vad behöver representeras? Pinnar Brickor Utförda drag Hur ska vi representera tillstånden? Klasser, listor, tuplar, dictionaries, strängar?
Hur representerar vi tillstånd i världen? node = { roda : [3, 2, 1], rodb : [], rodc : [], moves : []} # (rod A, rod B, rod C, moves) node = ([3, 2, 1], [], [], []) class Node: def init (self, roda, rodb, rodc, moves): self.roda = roda self.rodb = rodb self.rodc = rodc self.moves = moves
Hur vet vi att vi har nått målet? Olika formuleringar När alla brickor på pinne A har flyttats till pinne C När alla brickor ligger på pinne C (eller när inga brickor finns på pinne A eller B) När pinne C ser ut som pinne A gjorde från början
Hur vet vi när vi har nått målet? Olika formuleringar När alla brickor på pinne A har flyttats till pinne C När alla brickor ligger på pinne C (eller när inga brickor finns på pinne A eller B) När pinne C ser ut som pinne A gjorde från början def goal_test(node): if node[ roda ] == [] and node[ rodb ] == []: return True else: return False
Hur vet vi när vi har nått måltillståndet? Måltillståndet har uppnåtts när inga brickor finns på vare sig pinne A och B. def goal_test(node): if node[ roda ] == [] and node[ rodb ] == []: return True else: return False
Hur vet vi när vi har nått måltillståndet? Måltillståndet har uppnåts när alla brickor på pinne A i startnoden har flyttats till pinne C. def goal_test(node): return node[ rodc ] == [3,2,1] eller mer generellt: def goal_test(node): return node[ rodc ] == start_node[ roda ]
Vilka handlingar är tillåtna? Den översta brickan får förflyttas från en pinne till en annan om den senare är tom eller har en större bricka högst upp. def movefromto(node, x, y): if node[x] == []: return None # om ingen bricka if node[y] == [] or node[x][-1] < node[y][-1]: brick = node[x].pop(-1) node[y].append(brick) node[ actions ].append(x + to + y) return node return None
Vilka handlingar är tillåtna? (forts) Nu kan vi beskriva alla möjliga förflyttningar. Expand returnerar en lista med alla tillstånd som vi kan nå från nuvarande tillstånd. def expand(node): nodes= [] for x in [ roda, rodb, rodc ]: for y in [ roda, rodb, rodc ]: if x == y: continue # hoppa över onödig förflyttning new_node = movefromto(copy.deepcopy(node), x, y) if new_node!= None: nodes.append(new_node) return nodes Kopiera noden!
Sökningsloopen En bredden först sökning består av att gå igenom alla möjliga noder ett djup i taget tills vi har hittat en lösning. Vi lägger alla noder i en kö, om ingen lösning hittats expanderar nuvarande nod och lägger till de nya noderna sist i kön. frontier = [start_node] # kö while len(frontier) > 0: node = frontier.pop(0) # ta noden som ligger först i kön if goal_test(node): print( Lösning hittad:, node[ actions ]) break else: frontier.extend(expand(node))
Möjliga förbättringar Loopkontroll Många tillstånd upprepas flera gånger Heuristik Sortera kölistan efter störst potential
Enkel loopkontroll Spara alla expanderade noder i en lista Om den aktuella noden redan expanderats så explored = [] frontier = [start_node] # kö while len(frontier) > 0: node = frontier.pop(0) # ta noden som ligger först i kön if node in explored: continue if goal_test(node): print( Lösning hittad:, node[ actions ]) break frontier.extend(expand(node)) expanded.append(node) # vad bestämmer om två noder är likadana?
www.liu.se