Steg 5: spis epler og bli stor
I dette steget skal vi implementere funksjonalitet som gjør at slangen vokser når den spiser et eple.
før spising | etter spising |
I før/etter -bildene over, legg merke til at når slangen spiser:
- økes verdien
app.snake_size
fra 3 til 4,- posisjonen hvor hodet flytter til (1, 6) endrer verdi fra -1 til 4, som er den nye verdien til
app.snake_size
, og- ingen verdier tilhørende slangen (positive verdier) i
app.board
synker.
For å gjennomføre dette steget, må vi modifisere koden vi skrev i move_snake
tidligere:
- Etter at app.head_pos er oppdatert men før det er gjort noen endringer i app.board, sjekk om det er et eple på posisjonen hvor slangens hode skal flytte seg.
- Dersom det er et eple der (app.board har -1 i den gitte posisjonen): øk app.snake_size med 1, og opprett et nytt eple på et tilfeldig sted som er ledig.
- For å opprette et eple på et tilfeldig ledig sted, er det klokt å utføre dette i en hjelpefunksjon
add_apple_at_random_location(grid)
som muterer brettet, og så kalle på denne funksjonen med app.board som argument.
- For å opprette et eple på et tilfeldig ledig sted, er det klokt å utføre dette i en hjelpefunksjon
- Hvis det ikke er et eple der hodet skal flytte seg: utfør kallet til
subtract_one_from_all_positives
i stedet.
- Dersom det er et eple der (app.board har -1 i den gitte posisjonen): øk app.snake_size med 1, og opprett et nytt eple på et tilfeldig sted som er ledig.
import random
# Et tilfeldig tall mellom 0 og 10 (ikke inkludert 10)
print(random.choice(range(10)))
# Et tilfeldig element i en liste
print(random.choice(["a", "b", "c"]))
Test hjelpefunksjonen din ved å kopiere denne testen inn i snake.py (legg testen inn før kallet til run_app, men etter at funksjonen add_apple_at_random_location er definert)
print("Tester add_apple_at_random_location...", end="")
for _ in range(100):
a = [[2, 3, -1, 0], [1, 0, 0, 0]]
add_apple_at_random_location(a)
legal_results = [
[[2, 3, -1, -1], [1, 0, 0, 0]],
[[2, 3, -1, 0], [1, -1, 0, 0]],
[[2, 3, -1, 0], [1, 0, -1, 0]],
[[2, 3, -1, 0], [1, 0, 0, -1]],
]
assert(a in legal_results)
print("OK")
Legg merke til at funksjonen kun skal opprette epler på steder som er ledige, altså har verdien 0. Siden vi her tester en funksjon som produserer tilfeldige resultater, sjekker vi i assert-setningen at resultatet er ett av de fire lovlige resultatene for test-casen vår. Vi kjører også testen mange ganger slik at vi ikke bare passerer testen på grunn av flaks.
Det finnes i hovedsak to måter å løse add_apple_at_random_location
på. Velg selv hvilken strategi du ønsker å bruke.
Alternativ A. Denne tilnærmingen er som regel rask og effektiv så lenge slangen er relativt kort, men man har ingen øvre grense for hvor lang tid som kreves i verste fall.
- Velg en tilfeldig rad mellom 0 og antall rader i
grid
- Velg en tilfeldig kolonne mellom 0 og antall kolonner i
grid
- Sjekk om det er ledig plass (altså verdien 0) i
grid
på den gitte posisjonen:- Hvis ja, legg inn et eple (verdien -1) i posisjonen og avslutt så funksjonen med
return
- Hvis ikke, begynn på nytt (f. eks. ha all koden inn i en
while True
-løkke)
- Hvis ja, legg inn et eple (verdien -1) i posisjonen og avslutt så funksjonen med
Alternativ B. Denne tilnærmingen er ikke spesielt effektiv i gjennomsnitt, men har en øvre grense for hvor lang tid den tar. Dersom det ikke er plass til et nytt eple i det hele tatt vil denne algoritmen kunne avsløre det (f. eks. ved å krasje, eller håndtere det på annen måte), mens alternativ A aldri vil terminere, og programmet vil fryse (som tross alt er et dårligere alternativ).
- Opprett først en liste med alle posisjonene hvor det er mulig å opprette et eple.
- Velg en tilfeldig posisjon fra listen over muligheter.
- Legg inn et eple i den valgte posisjonen
For de ambisiøse: det er mulig å kombinere alternativene A og B ved å prøve alternativ A noen få iterasjoner først, og deretter hoppe over til alternativ B dersom ingen gode alternativer ble funnet. Da får vi det beste fra begge verdener.
Guide til snake av Torstein Strømme er lisensiert under CC-NC-SA 4.0.