Oppgaven handler om en realisering av TicTacToe-spillet med en tydelig oppdeling i klasser for brett og spill-logikk.

I spillet Tripp-trapp-tresko skal to spillere legge hver sine brikker i et rutenett på 3x3 ruter og prøve å få tre på rad før brettet er fullt. Oppgaven fokuserer på å realisere dette ved bruk av to klasser, med en tydelig rollefordering: TicTacToe-klassen håndterer selve brettet og hvem sin tur det er, mens TicTacToeProgram-klassen håndterer tekst-basert interaksjon med spillerne gjennom konsollet. Denne tydelige oppdelingen i logikk og interaksjon (også kalt brukergrensesnitt) vil gjøre det lettere å senere lage et grafisk brukergrensesnitt uten å måtte programmere alt på nytt, siden logikk-klassen vil kunne gjenbrukes. For å gjøre klassene noenlunde uavhengig av hverandre brukes prinsippet om Innkapsling.

Oppgaven er åpen i den forstand at den ikke spesifiserer akkurat hvilke metoder hver klasse skal ha, men sier noe om hvordan det skal ta seg ut for brukeren. Dette gjør det vanskeligere å teste enkeltmetoder, så istedenfor testes teksten som kommer ut, basert på hva brukeren (eller testprogrammet) gir inn.

Det er ofte lurt å løse slike oppgaver i mindre trinn, og derfor har vi nedenfor spesifisert hvilke funksjoner vi tror er lurt å lage i hvert trinn.

  • Trinn 1 - kunne vise frem brettet med og uten brikker. I dette trinnet lager du TicTacToe-klassen med en toString()-metode som viser brettet med de brikkene som er satt (f.eks. av et enkelt test-hovedprogram du lager selv). TicTacToe-klassen skal være ordentlig innkapslet.
  • Trinn 2 - spillerne kan legge brikker. I dette trinnet lages en enkel versjon av TicTacToeProgram-klassen, slik at spillerne etter tur kan legge brikker ved å angi x,y-posisjonen til ruta som brikken skal legges i. TicTacToeProgram-klassen skal ta seg av all input og utskrift. For interaksjon med brukeren kan det være lurt å bruker Scanner-klassen.
  • Trinn 3 - et helt fungerende spill, hvor TicTacToe-klassen kan si fra til TicTacToeProgram-klassen hvilken spiller som har turen, om spillet er ferdig og hvilken spiller som evt. har vunnet.

Nedenfor har vi vist en mulig spillsekvens som både illustrerer brett-formatet og dialogen mellom spillet og spillerne. Output til brukeren er i svart, mens input fra brukeren er i grønt.

Som nevnt kan ikke koden din testes metode for metode, siden det ikke er spesifisert hvilke metoder hver klasse skal inneholde. Imidlertid er det mulig å teste at spillet kan brukes, hvis tekstformatet for både input og output er spesifisert. Dersom du følger formatet angitt i tabellen under og som tilsvarer eksemplet over, så kan du bruke testen som vi har lenket til.

Output til brukerenInput fra brukere

Før den første runden og etter hvert legg må brettet skrives ut, f.eks.

-------
|x| | |
-------
| |o| |
-------
| | | |
-------

En bruker altså x, o eller mellomrom inni hver rute, bindestrek over, mellom og under radene og vertikale streker før, mellom og etter kolonnene.

Programmet kan godt skrive ut andre ting også, men ikke begynn noen linje med bindestrek, fordi det vil forvirre testen.

Spilleren skriver inn x,y-koordinatene til ruta hvor brikken skal legges, med mellomrom mellom.
Den venstre kolonnen er nr. 0, den midterste 1 og den høyre 2. Den øverste raden er nr. 0, den andre 1 og den tredje 2.

Ekstraoppgave - Utvidelse til M-på-rad spill på NxN-brett

Skriv om TicTacToe-klassen slik at spillet kan spilles på brett av størrelse NxN og hvor seiersbetingelsen oppdateres til at M brikker er lagt på rad. Dette kan gjøres ved å legge til felter i TicTacToe-klassen som holder størrelsen på brettet, i tillegg til seierbetingelsen, og disse settes i konstruktøren når en ny instans av TicTacToe-klassen opprettes. Modifiser også TicTacToeProgram-klassen slik at brukeren før spillet starter kan taste inn hvort stor brett hun ønsker å spille på og hva seiersbetingelsen skal være. 

JavaFX-app

Konsollbasert IO er greit for å teste spillet, men det er kanskje artigere å lage en ordentlig app, med grafisk visning av rutenettet og bruk av piltastene for styring av spilleren. Vi har laget en JavaFX-basert app, som du kan laste ned og koble til din TicTacToe-klasse. App-koden forutsetter at spill-logikken er implementert i en klasse som implementerer ITicTacToe-grensesnittet (i pakken games.tictactoe.tictactoe1). Når brukeren starter spillet, så lages det en instans av spillklassen din i app-en, og det er denne som holder rede på spill-tilstanden, dvs. hvilke brikker som er i hvilke ruter. Med bruk av grensesnitt, så gjøres det klart hvilke metoder appen trenger og som du må implementere.

Last først ned ITicTacToe-grensesnittet fra /games/tictactoe/tictactoe1/ITicTacToe.java, og programmer din spill-klasse slik at den implementerer dette grensesnittet. Så laster du ned app-klassene (og filene), så du kan prøve om det virker:

Fil-tre som må lastes ned evt. importeres med Digital Compendium-panelet
emfs
/games/ #java #package
    FxmlApp.java                 @ git@github.com:hallvard/javafx/games/src/games/FxmlApp.java;
    FxmlBuilderFactory.java     @ git@github.com:hallvard/javafx/games/src/games/FxmlBuilderFactory.java;
    FxmlGame.java                @ git@github.com:hallvard/javafx/games/src/games/FxmlGame.java;
    imagegrid/ #java #package
        ImageGrid.java        @ git@github.com:hallvard/javafx/games/src/games/imagegrid/ImageGrid.java;
        ImageGridGame.java        @ git@github.com:hallvard/javafx/games/src/games/imagegrid/ImageGridGame.java;
    ;
    tictactoe/ #java #package
        tictactoe1/ #java #package
            TicTacToeFX.java    @ git@github.com:hallvard/javafx/games/src/games/tictactoe/tictactoe1/TicTacToeFX.java;
            TicTacToeFX.fxml    @ git@github.com:hallvard/javafx/games/src/games/tictactoe/tictactoe1/TicTacToeFX.fxml;

Merk at du godt kan la være bruke å ITicTacToe-grensesnittet, men da må du omprogrammere appen, så den bruker andre metoder enn vi har forutsatt. Det er nok mer arbeid, men kanskje enda mer lærerikt?

Testing med JExercise

Selv om dette er ment å være en litt åpen oppgave, så har vi laget tester som sjekker at spillet kan spilles slik som vist over, altså med riktig input og output. Testen trenger filene tictactoe/example1.txt, tictactoe/example2.txt og tictactoe/AbstractExampleTest.java og selve testen ligger her: tictactoe/TicTacToeTest.java


JExercise lar deg sjekke din egen kode vha. forhåndslagde JUnit-tester og JExercise-panelet

Bruk av JExercise:

  1. Sørg for at jexercise-standalone.jar er lagt til i ditt prosjekts Build Path. Dette må gjøres hver gang du oppretter et nytt prosjekt, og det er derfor lurt å gjenbruke samme prosjekt til alle oppgaver.
  2. JExercise-tillegget må være installert. Installer tillegget fra følgende oppdateringsadresse: http://folk.ntnu.no/hal/dev/updatesite.
  3. Åpne JExercise-panelet via Window -> Show View -> Other, og navigere deg fram til JExercise i vinduet som kommer opp, velge det og klikke OK.
  4. Klikke og dra oppgavens testklasse, <oppgavenavn>Test.java fra pakkeoversikten og slippe den i JExercise panelet. 
  5. Testene kan så kjøres ved å dobbeltklikke på testen som ønskes kjørt.

Ved trøbbel, se først om du finner løsningen i Løsninger på trøbbel med JExercise.

Unknown macro: {html}

Twitre gjerne om oppgaven når du er ferdig: <a href="https://twitter.com/share" class="twitter-share-button" data-hashtags="jexercise">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>