Steg 4: flytt på slangen
I dette steget skal vi la slangen gå ett steg hver gang brukeren trykker på mellomromstasten. Senere skal vi få programmet til å flytte slangen av seg selv; men i utviklingsfasen er det fint å kunne jobbe i «sakte film» og da er det fint å bruke mellomromstasten til å kontrollere tiden.
Steg 4a: utvidelse av modellen
Først må vi utvide modellen vår slik at den inneholder informasjon om slangens lengde og slagehodet sin posisjon. I funksjonen app_started
:
- Opprett en variabel
app.snake_size
og initialiser den med verdien3
(dette er slangen sin initielle størrelse slik den er i app.board). - Opprett en variabel
app.head_pos
og initialiser den med verdien(3, 4)
(dette er den initielle posisjonen (rad, kolonne) til slangen sitt hode slik slangen ligger i app.board).
En tuple er en liste som ikke kan muteres. De aller fleste ikke-destruktive operasjoner på lister fungerer helt likt for tupler. Les også om tupler i kursnotater om lister.
# Opprett en tuple
pos = (3, 4)
print(pos) # (3, 4)
# "Pakk ut" en tuple i variabler
row, col = pos
print(f'{row} {col}') # 3 4
Når vi er i debug-modus, er det fint om vi kan se verdiene til disse variablene.
- I
redraw_all
, endre strengen som skriver ut debug-informasjon slik at den også inkluderer de nye variablene i app vi nettopp opprettet. Se bilder under.
Steg 4b: selve forflyttningen
før forflyttning | etter forflytning |
Nå kommer vi til selve forflyttningen; bildene over viser tilstanden før og etter en forflytning i retning «east». Vi oppretter en egen funksjon move_snake(app)
for å utføre flyttingen. Denne funksjonen skal utføre følgende:
- Oppdater
app.head_pos
: finn hva som er neste posisjon for slangen sitt hode. - Oppdater
app.board
: for alle positive verdier, trekk fra 1. - Oppdater
app.board
: la den nye posisjonen til slangen sitt hode få verdi lik slangen sin størrelse
Det er klokt å skille dette ut som en egen hjelpefunksjon get_next_head_position(head_pos, direction)
som returnerer en tuple med rad og kolonne for neste posisjon.
- I move_snake, gjør et kall til denne hjelpefunksjonen med app.head_pos og app.direction som argumenter.
- La retur-verdien fra dette funksjonskallet bli den nye verdien til app.head_pos.
I før/etter -bildene over ser vi at verdien
app.head_pos
endres fra (3, 4) til (3, 5). Den endringen gjør vi her.
Test hjelpefunksjonen din ved å kopiere denne testen inn i snake.py (legg testen inn før kallet til run_app, men etter at funksjonen get_next_head_position er definert)
print("Tester get_next_head_position...", end="")
assert((3, 9) == get_next_head_position((3, 8), "east"))
assert((3, 7) == get_next_head_position((3, 8), "west"))
assert((2, 8) == get_next_head_position((3, 8), "north"))
assert((4, 8) == get_next_head_position((3, 8), "south"))
assert((1, 6) == get_next_head_position((1, 5), "east"))
assert((1, 4) == get_next_head_position((1, 5), "west"))
assert((0, 5) == get_next_head_position((1, 5), "north"))
assert((2, 5) == get_next_head_position((1, 5), "south"))
print("OK")
- Husk at en tuple (akkurat som en liste) kan «pakkes opp» til individuelle variabler (se kursnotater om lister). For eksempel:
foo = (3, 4) # foo er en tuple med to elementer
x, y = foo # nå er x lik 3 og y lik 4
- Benytt if-setninger og sjekk hva
direction
er. Legg til eller trekk fra1
på row eller col alt ettersom. Se «test deg selv underveis» over.
Det er klokt å skille også dette ut som en egen hjelpefunksjon subtract_one_from_all_positives(grid)
som muterer en 2D-liste med tall gitt som input.
- I move_snake, gjør et kall til denne hjelpefunksjonen med app.board som argument.
I før/etter -bildene over ser vi at verdien i rute (3, 2) endres fra 1 til 0, verdien i rute (3, 3) endres fra 2 til 1 og verdien i rute (3, 4) endres fra 3 til 2. Disse endringene gjør vi her.
PS: Vi sier at en verdi er positiv dersom den er strengt større enn 0; altså er 0 ikke en positiv verdi.
Test hjelpefunksjonen din ved å kopiere denne testen inn i snake.py (legg testen inn før kallet til run_app, men etter at funksjonen subtract_one_from_all_positives er definert)
print("Tester subtract_one_from_all_positives...", end="")
a = [[2, 3, 0], [1, -1, 2]]
subtract_one_from_all_positives(a)
assert [[1, 2, 0], [0, -1, 1]] == a
b = [[2, 0], [0, -1]]
subtract_one_from_all_positives(b)
assert [[1, 0], [0, -1]] == b
print("OK")
Husk at slangen sin størrelse befinner seg i variabelen app.snake_size
.
I før/etter -bildene over ser vi at verdien i ruten (3, 5) endres fra 0 til 3. Den endringen gjør vi her.
- Har du husket å oppdatere
app.head_pos
med returverdien fra kallet tilget_next_head_position
? - Slangehodet sin posisjon som rad og kolonne er
row, col = app.head_pos
. - Muter
app.board[row][col]
slik at verdien blirapp.snake_size
.
Til slutt gjenstår det å gjøre et kall til move_snake når brukeren trykker på mellomrom.
- I
key_pressed
: hvisevent.key
er lik'Space'
, utfør et funksjonskall tilmove_snake
.
Du skal nå kunne flytte slangen ved å trykke på mellomrom, og du skal også kunne endre hvilken retning slangen flytter seg ved å benytte piltastene.
Guide til snake av Torstein Strømme er lisensiert under CC-NC-SA 4.0.