Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Oppdatert ødelagt link
Excerpt

Oppgaven handler om en Sokoban-klasse som holder representasjon, logikk og funksjonalitet for å spille spilllet Sokoban gjennom konsollen.

...

spillet Sokoban (prøv spillet her). Sokoban består av et brett med vegger, tomme ruter, målruter, bokser og en spiller. Spilleren skal forsøke å flytte

...

boksene til

...

hver sine målrute. Spilleren

...

har klart brettet når alle boksene står på

...

Oppgaven omfatter tre klasser, Cell, Sokoban og SokobanProgramCell-klassen representer hvert enkelt felt på brettet og dekkes av del 1. Del 2 omfatter Sokoban-klassen, som kapsler inn brettet og har metoder for å utføre trekk og sjekke om spillet er avsluttet. Begge disse dele har har JExercise-tester. SokobanProgram-klassen lages i del 3 og håndterer tekstbasert interaksjon og bruker Sokoban-klassen. Her skal spilleren taste inn ønsket trekk etter tur helt til man har vunnet eller gir opp. 

Del 1 - Representasjon av felter (15 %)

Denne klassen er en hjelpeklasse for å holde styr på verdien til hvert enkelt felt på brettet.

Tilstanden til en Cell er et tegn, e.g. ’#’ for vegg eller ’+’ for spiller, samt posisjon på brettet, angitt som x- og y- koordinater.

Tegnene for de forskjellige felt-verdiene er:

TegnBetydning

'#'

vegg
'.'mål
'$'boks
'*'boks på mål
'@'spiller
'+'spiller på mål
' 'tomt felt

Cell-klassen må ha følgende metoder:

  • void RemoveBox() - fjerner en boks fra feltet.
  • void RemovePlayer() –fjerner spilleren fra feltet.
  • void AddPlayer() – setter spilleren på feltet.
  • boolean isTarget() – returnerer hvorvidt feltet er et mål eller ikke.
  • boolean isFree()  - returnerer hvorvidt det er mulig å flytte en boks eller spilleren til feltet.
  • boolean containsPlayer() -  returnerer om spilleren står på feltet.
  • boolean containsBox()  - returnerer om en boks står på feltet.
  • String toString() – skriver tegnet på feltet til en streng.
  • int getX(), getY() - returnerer henholdsvis x- og y- koordinatene til feltet

Merk at man i alle metoder må sikre at det spillet er i gyldig tilstand før man og etter man utfører en operasjon. Ved behov kan også andre tilgangsmetoder legges til.

Implementer støtte for tilstand og metoder beskrevet over slik at JExercise-testkoden fullfører feilfritt. Testkoden finner du her: 

Del 2 – Logikk og representasjon av brett (60 %)

en målrute.

Sokoban forklares enklest ved demonstrasjon:

Brett som bildeBrett som tekstForklaring
Image Added
#######
#.@ # #
#$* $ #
#   $ #
# ..  #
#  *  #
#######

Utgangsposisjon for et brett, med tomme ruter (' '), vegger ('#'), målruter ('.'), bokser ('$' og '*') og spilleren ('@'). En boks som står på en tom rute er rød ('$'), en boks på en målrute er grønn ('*').

Image Added
#######
#. # #
#$* $ #
#  $@ #
# ..

Tilstanden i Sokoban-klassen må holde rede på flere ting. Man må håndtere hvordan brettet ser ut til enhver tid. Videre må man holde styr på hvor målene på brettet befinner seg. Spillerens posisjon må også lagres.

Det finnes mange ulike brett av forskjellig størrelse. Tilstanden bør derfor lagre størrelsen på brettet, både høyde og bredde. Brettet utgjør et koordinatsystem med følgende innhold:

*###########*
#           #
#  ... ...  #
#  *$$ $.$ $*$$*$$@$$.$  .. .  
#           #
*###########*
*###########*
#           #
#  ... ...
  #
#  *
$$ $.$ 
  #
#######

Spilleren har beveget seg og dyttet en boks mot venstre / vest.

Image Added
#######
#*$ # #
#
$*+$
@ $
*$$
 #
# 
*$$
  $
.$ 
 #
# ..
.
  
.  
#
#          
 
#*###########
*
  #

 

 

 

Et trekk ned (sør) gir følgende brett

#######

Spilleren har skjøvet en boks mot en vegg og kan ikke lenger flytte den. Spillet er låst og tapt (ihvertfall uten angre-mulighet).

Image Added
#######
#* # #
# * #
#
  
 
 #
# **
@ 
#
*
 
 #

Sokoban-klassen må ha følgende metoder:

  • Sokoban(String[]) – konstruktøren skal ta inn en array med strenger som utgjør brettet. Strengene må leses og angi starttilstanden for hvert felt på brettet.
  • boolean canMove(int) – denne metoden tar inn en retning og angir om spilleren kan bevege seg i denne retningen eller ikke.
  • void doMove(int) – denne metoden tar inn en retning og flytter spilleren og en eventuell boks i den angitte retningen på brettet.
  • boolean hasWon() – denne metoden returnerer hvorvidt spilleren har vunnet eller ikke; med andre ord om alle målene har bokser på.
  • String toString() – denne metoden returnerer brettet som en streng, hvor hver linje er adskilt med ”\n”.

Implementer støtte for tilstand og metoder beskrevet over slik at JExercise-testkoden fullfører feilfritt. Testkoden finner du her: 

Del 3 - Fullt fungerende spill, med tekstlig interaksjon (25 %)

Lag SokobanProgram klasse som lar deg spille spillet gjennom konsollen. Programmet må:

  • skrive ut brettet.
  • be om og lese inn retningen spilleren skal bevege seg med en Scanner. Vanlig spillkutyme er at ’w’, ’s’, ’a’ og ’d’ representerer henholdsvis bevegelse fremover (nord), bakover (sør), venstre (vest) og høyre (øst). Hvis spilleren forsøker et ulovlig trekk, e.g. gå inn i en vegg eller skyve en boks på en annen boks, skal det skrives ut en beskjed om at trekket er ulovlig.
  • utføre trekket.
  • gjenta dette helt til spilleren har vunnet eller valgt å avslutte. Hvis spilleren vinner må dette skrives ut til konsollen.

Eksempel på fungerende spill (input er vist i grønt):

Image RemovedImage RemovedImage Removed

 

...

#######

Spilleren har plassert boksene på hvert sitt mål og har klart brettet.

Implementasjon av Sokoban

Sokoban-oppgaven er en åpen oppgave, hvor man selv velger løsninger for hvordan spillet skal implementeres. Det stilles likevel følgende krav:

  • Programmet må bestå av minst to klasser; en klasse for å representere (innholdet i) en rute på brettet, og en spillklasse for brettet med ruter. Disse skal være ordentlig innkapslet.
  • Spillet må kunne spilles via JavaFX-applikasjonen som spesifisert under.
  • Spillklassen må kunne initialiseres med en String på standard-formatet , som beskrevet i tabellen under.
  • Spillklassen må ha en toString()-metode som returnerer en String på samme format som brettet initialiseres med.
Standard-formatet
TegnBetydningUtskrift

'#'

vegg
#######
#.  # #
#$* $ #
#  $@ #
# ..  #
#  *  #
#######
'.'mål
'$'boks
'*'boks på mål
'@'spiller
'+'spiller på mål
' 'tomt felt
Hint:
  • I representasjonen av brettet kan det være lurt å skille mellom de faste (tomme ruter, målruter og vegger) og de flyttbare (bokser og spiller) delene av brettet.
  • Det er vanlig å bevege en spiller med tastene a, s, d og w, for henholdsvis venstre (vest), ned (sør), høyre (øst) og opp (nord).
Det ligger fire testbrett du kan bruke i filen: SokobanSampleLevels.java. Ved å kalle Sokoban(SampleLevels.SAMPLE_LEVEL3) vil du opprette brettet vist i tabellen over.

JavaFX-applikasjon

Det er laget en JavaFX-applikasjon som i praksis gjør to ting: den tar inn tekstlig input fra brukeren og endrer tilstanden i spillklasse-objektet basert på dette, og den viser spillklassens toString()-metode i applikasjonsvinduet. For at applikasjonen skal være kjørbar med spillklassen, må følgende gjøres:

  • GameController, deklarer spillet ditt og initialiser det slik kommentarene i koden forklarer. 
  • I spillklassen, lag en metode void getInput(String in), som tar inn bruker-input (som kommer fra applikasjonen), og endrer tilstanden på spillet tilsvarende. Her kommer det altså inn posisjonen for neste trekk, som så skal bli utført. Formatet på strengen er valgfritt, men det er anbefalt å bruke standarden, som er a, s, d og w.
  • Når spillet er ferdig, skal spilleren få vite dette. GameController bruker spillklassens toString()-metode for å vise spillets tilstand. Oppdater denne metoden slik at den også gir beskjed om at spillet er over når dette skjer.

Du kan nå kjøre applikasjonen (Game.fxml > Run As > FXML Application) og teste spillet ditt.

Hjelp til kjøring av JavaFX og generelt om øvinger finner du i Hjelp til øvinger.

Vurdering

Oppgaven blir vurdert etter hvorvidt spillet kan

  • Nivå 0 (10%): skrive ut brettet ved oppstart.
  • Nivå 1 (30%): flytte spilleren (med input fra brukeren) i et tomt brett; altså ingen vegger, bokser eller mål.
  • Nivå 2 (40%): utvide med vegger, men fortsatt ingen bokser eller mål.
  • Nivå 3 (60%): utvide med bokser som kan flyttes, men ingen mål.
  • Nivå 4 (80%): full støtte for alt ruteinnhold.
  • Nivå 5 (100%): logikk for spillets gang, dvs. oppdage at alle målrutene er dekket av bokser.

Hvert nivå innbærer at all funksjonalitet i de lavere nivåene fungerer som beskrevet.

...