Cleans up project

This commit is contained in:
Kristian Knarvik 2020-02-14 01:01:38 +01:00
parent de6607442b
commit dfa7a142c3
126 changed files with 147 additions and 825 deletions

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<accessrules>
<accessrule kind="accessible" pattern="javafx/**"/>
</accessrules>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="bin"/>
</classpath>

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.DS_Store
*.xml
*.iml
target

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>inf101.v18.sem1</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

View File

@ -1,3 +0,0 @@
cleanup_settings_version=2
eclipse.preferences.version=1
formatter_settings_version=13

View File

@ -1,6 +0,0 @@
# Authors
* Anya Helene Bagge, UiB (graphics, maintenance)
* Lars Jaffke, UiB (Langton's Ant)
* *you*, UiB (the rest!)

120
SEM-1.md
View File

@ -1,120 +0,0 @@
# [Semesteroppgave 1: “Rogue One Oh One”](https://retting.ii.uib.no/inf101.v18.sem1/blob/master/SEM-1.md)
* [README](README.md)
* **Oversikt** Praktisk informasjon 5%
* [Del A: Bakgrunn, modellering og utforskning 15%](SEM-1_DEL-A.md)
* [Del B: Fullfør basisimplementasjonen 40%](SEM-1_DEL-B.md)
* [Del C: Videreutvikling 40%](SEM-1_DEL-C.md)
# Praktisk informasjon
* **For å forstå hvordan du skal levere inn oppgaven må du ha gjort labbene** (spesielt Lab 1 og Lab 3).
* **Semesteroppgaven vil være mye lettere å løse når du har ferdighetene og teorien fra labbene** (spesielt Lab 3 og 4) det er best å ta seg tid til å løse disse først!
* For poengsummen teller generell oversikt og ryddighet i innleveringen ca. 5%.
## Om semesteroppgaven
Semesteroppgaven er *obligatorisk*, og er ment å gi innsikt i og erfaring med
teknikkene vi har lært hittil i semesteret, og å teste en del praktiske
ferdigheter som ikke er så lette å teste på eksamen. Se under angående
karakter.
*Les helst all den kjedelige teksten før du begynner. Si ifra om noe er veldig uklart.*
### Læringsmål
Målene for denne semesteroppgaven er:
* Å kunne sette seg inn i et eksisterende program/rammeverk, og utvide det ut ifra spesifikasjoner (beskrivelsen i oppgavene).
* Å bruke grensesnitt (interface) til å kommunisere mellom objekter.
* Å lage programmer hvor objektene selv styrer sin egen oppførsel, basert på *hendelser* i systemet.
* Å beskrive komplekse objekt-orienterte systemer på en forståelig måte.
### Retting og poeng
Semesteroppgaven blir rettet av en gruppeleder, som gir tilbakemeldinger på
innleveringen. For semesteroppgavene blir det satt poeng, og til sammen teller
semesteroppgavene 30 % på karakteren i faget. Ved poengsetting legger vi vekt
på følgende:
* At du har fungerende løsninger på de forskjellige deloppgavene
* At koden din er ryddig og at eventuelle deler som er vanskelig å forstå er forklart i kommentarer
* At du har laget tester for koden din
* Kreativitet, og at du gjør mer enn minimum for å fullføre oppgaven
Du kan regne med en godt gjennomført innlevering som oppfyller minimumskravene gir en
poengsum ca. tilsvarende C. For høyere poengsum må man ha gjort en del av bonusoppgavene. Manglende /
svært mangelfull innlevering gir 0 poeng.
### Samarbeid
Innleveringen er *individuell* og kan ikke løses i grupper. Dere står likevel fri
til å samarbeide om utarbeiding av ideer, diskutere løsninger og å hjelpe
hverandre med å finne og løse problemer (vi oppfordrer faktisk til det!) men programmeringen må du gjøre selv, og du er selv ansvarlig for din egen kode og at du vet og kan forklare hvordan den virker.
Hvis du har diskutert ideer eller løsninger med noen, gi en kort redegjørelse for det i `README.md` og evt. i commit-meldingen hvis det er relatert til en konkret commit. F.eks. *“Kaniner-og-aliens-konseptet er tenkt ut sammen med Helene Harepus, men vi har kodet det hver for oss”; “Implementert telljeløkkjer til regnbuepromp for einhjørningar (takk til Dag H. for tips om dette)”; “Sorter elementene i riktig rekkefølge (fixes #23, takk til bestemor som la merke til feilen)”.*
### Fusk og opphavsrett
Forøvrig gjelder [UiBs regler om fusk og plagiat](http://www.uib.no/studiekvalitet/77864/fusk-hva-er-det-og-hvilke-konsekvenser-f%C3%A5r-det-deg-som-student). Akademisk uredelighet og (forsøk på) fusk reguleres av Universitetsloven, og mulige konsekvenser er blant annet annullering av eksamen og utestenging (evt. tilbaketrekking av vitnemålet om ting blir oppdaget i ettertid).
(*Men:* Så lenge det er klart og tydelig hvem som har skrevet hva, hva kilden er og hvem som evt. har hjulpet til med hva, er det *ikke* fusk eller plagiat men du får selvfølgelig bare poeng for ting du har gjort selv.)
Opphavsrett er et separat spørsmål du kan generelt ikke klippe kode eller bruke bilder/lyd/media fra nettet [uten at du har tillatelse](https://retting.ii.uib.no/inf101/inf101.v18/wikis/opphavsrett-lisenser). Hvis du bruker ting du har funnet på nettet e.l. må du opplyse i `README.md` om hva det er, hvem som har laget det og hvor du har funnet det. For grafikk/lyd som du har rett til å gjenbruke, se gjerne etter ting med [Creative Commons lisens](https://creativecommons.org/licenses/). Vi har en liste med greie kilder på slutten av oppgaven. (Og om du er nysgjerrig, finner du lisensen for koden du har fått utlevert i filen [LICENSE](LICENSE).)
### Innlevering
Du finner koden din i repositoriet med URIen:
https://retting.ii.uib.no/<brukernavn>/inf101.v18.sem1.git
Oppgaven leveres inn ved å pushe til retting.ii.uib.no, [slik du har gjort med alle tidligere INF101-oppgaver](https://retting.ii.uib.no/inf101/inf101.v18/wikis/hente-levere-oppgaver). Husk å få med eventuelle nye filer du har opprettet (hvis testene virker hos deg, men ikke i innleveringssystemet, er det gjerne det som er feil).
**VIKTIG:** *Sjekk kvitteringssiden som kommer opp når du pusher, i tilfelle det skjer feil!* Du må evt. gjøre Pull før Push, slik du så i Lab 3.
Vi anbefaler at du gjør commit hver dag, eller hver gang du er ferdig med en
større endring. Da går det alltid an å lete seg tilbake i historien til en
tidligere versjon hvis du har havnet på villspor.
* Du kan levere inn så mye og ofte du vil. Versjonen som teller er den siste du
pushet før innleveringsfristen.
* *VIKTIG:* Hvis du ikke allerede har prøvd ut GitLab / https://retting.ii.uib.no/ og pushing av
innleveringer, må du gjøre det *med en gang* (gjør labbene!). Du kan ikke regne med å få hjelp til
dette på innleveringsdagen, men på gruppetimene vil du få rikelig med hjelp
til dette.
* Alle testene bør passere (være grønne). Det blir i tillegg lagt betydelig
vekt på kodekvalitet og dokumentasjon. Dvs. koden din skal ikke bare *virke*,
den være lett å forstå og å endre.
* Du kan selv sjekke status i
[innleveringssystemet](http://retting.ii.uib.no:81/) det vil gi rask
tilbakemelding hver gang du pusher til Gitlab, også før innleveringsfristen.
Alt skal være *grønt* der. Hvis du ser feil der som du ikke finner ut av, er det bare å spørre om hjelp.
## Sjekkliste:
* [ ] Gjøre Del A
* [ ] Oppdatere README.md, commit og push!
* [ ] Gjøre Del B
* [ ] Oppdatere README.md, commit og push!
* [ ] Gjøre Del C
* [ ] Commit og push ofte!
* [ ] Beskrive hva du har gjort i README.md, fortell om eventuelt idé-samarbeid
* [ ] Sørge for at du har rettigheter til evt. mediafiler du bruker
* [ ] Gjøre klar innlevering
* [ ] Sjekke at alle filer som skal være med er med når du commiter
* [ ] Sjekk *Commits* siden på Retting, og se at ting du har pushet har dukket opp
* [ ] Sjekk teststatus på https://retting.ii.uib.no:81/me
* [ ] Sjekk at du har skrevet JavaDoc for nye metoder / typer du har lagt til
* [ ] Sjekk at du har formattert koden (bruk Source → Format i Eclipse, f.eks.)
* [ ] Sjekk at all bruk av kilder, bilder, lyd, annen kode er spesifisert i README.md
* [ ] Sjekk [README.md](README.md), commit og push!
* [ ] *Things to do*
* [ ] *More things to do*
### Tips
* Selv om det kanskje bare er litt mer å gjøre enn i en vanlig ukeoppgave, er
det *veldig mye* å sette seg inn i. Du bør begynne tidlig og jobbe jevnt. Du må
også regne med å jobbe utenom labtimene.

View File

@ -1,186 +0,0 @@
# [Semesteroppgave 1: “Rogue One oh one”](https://retting.ii.uib.no/inf101.v18.sem1/blob/master/SEM-1_DEL-A.md) Del A: Bakgrunn, modellering og utforskning *(15%)*
* [README](README.md)
* [Oversikt](SEM-1.md) [Praktisk informasjon 5%](SEM-1.md#praktisk-informasjon)
* **Del A: Bakgrunn, modellering og utforskning 15%**
* [Del B: Fullfør basisimplementasjonen 40%](SEM-1_DEL-B.md)
* [Del C: Videreutvikling 40%](SEM-1_DEL-C.md)
## Kunnskap/konsepter du har bruk for til denne delen
* *Abstraksjon* å se bort fra uvesentlige detaljer og konsentrere seg om de tingene som er viktig (for det vi holder på med / fra vårt synspunkt)
* *Modellering* en modell er en (som regel forenklet) representasjon av noe. Vi bruker modeller for å
* prøve ut / leke med / teste ting når vi ikke kan/vil gjøre direkte med det vi modellerer (f.eks.: en klimamodell lar oss forstå hvordan klimaet kan utvikle seg i forskjellige scenarier uten at vi trenger å teste det i virkeligheten; en prototype lar deg se hvordan at produkt kan bli; en modell lar deg se hvordan klær ser ut uten å måtte prøve dem på deg selv; et dataspill lar deg gjøre ting du ikke kunne gjort (eller hatt lov til) i virkeligheten; lek lar barn bygge “romskip” og utføre medisinsk behandling på “spedbarn” uten å svi av plenen eller skade lillebror).
* ha et eksempel som vi kan bruke når vi skal lage flere ting (f.eks.: [kilogramprototypen](https://en.wikipedia.org/wiki/Kilogram#International_prototype_kilogram), arkitekttegninger, 3D designmodeller (CAD/CAM))
* *Objekter* (`new C()`) med oppførsel (metoder) og innkapslet tilstand (feltvariabler), og relasjoner til og interaksjon med andre objekter.
* *Interface* (`interface I`, `class C implements I`) hvordan du kan bruke objekter som du har (og hvilke metoder objektenes klasse må implementere)
Ting som (kanskje) er nytt:
* `interface I extends J` både `I` og `J` må være grensesnitt
* Alle metodene i `J` er også med i `I` (som om du hadde listet dem opp i `I`)
* `I` blir en *subtype* av `J` hvis noe er en `I` (er av en klasse som implementerer `I`) så kan det også brukes som en `J` (i en variabel av type `J`, f.eks.). (Det motsatte er *ikke* tilfelle ikke alle `J`-er er `I`-er.)
* `default`-metoder i `interface`/grensesnitt disse gir deg kode for en metode så du slipper å implementere den selv i klassen din.
* Default-metodene har ikke tilgang til feltvariabler, og de kan bare bruke metodene i grensesnittet.
* Typiske default-metoder er ekstrametoder som bygger på de andre metodene (metoder som er praktisk for bruk uten å være helt nødvendige). Det er også praktisk når man senere skal legge til flere metoder i et grensesnitt, for å slippe å måtte oppdatere en hel haug med klasser.
## Rogue 101
Semesteroppgaven er en naturlig videreutvikling av Labyrint-oppgaven i stedet for å bare gå rundt i en kjedelig labyrint, skal vi nå kunne gå rundt, plukke opp ting og interagere med ting.
### Bakgrunn
Et eksempel på et slikt labyrint-spill er [Rogue](https://en.wikipedia.org/wiki/Rogue_(video_game)), som er et gammel [dungeon crawl](https://en.wikipedia.org/wiki/Dungeon_crawl)-spill med “tekst-grafikk”, der du går rundt i en labyrint, plukker opp ting og dreper monstre. De første slike spillene dukket opp på slutten av 1970-tallet; *Rogue* (1980) var et av de første, og har gitt navn til hele sjangeren ([“Roguelike”](https://en.wikipedia.org/wiki/Roguelike)). Dungeon crawls og roguelike spill har vært veldig populære opp gjennom tidene (ikke minst på grunn av fancy 2D-grafikk med tekst-symboler, som var et betydelig steg opp fra [tidligere adventure/fantasy spill](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure) som hvor alt var bare tekst), inkludert gamle klassikere som [NetHack](https://en.wikipedia.org/wiki/NetHack), [Moria](https://en.wikipedia.org/wiki/Moria_(video_game)) og [Larn](https://en.wikipedia.org/wiki/Larn_(video_game)). Ofte har disse spillene vært laget som hobbyprosjekter av programmører (informatikk-studenter, for eksempel) og vært mer kompliserte (og mye vanskeligere) enn spill fra kommersielle spillprodusenter, selv om de gjerne ikke har hatt spesielt fancy grafikk.
Moderne roguelike spill (og moderne utgaver av de gamle) kommer gjerne med mer fancy grafikk og er ofte laget av uavhengige utviklere. I de litt bredere kategoriene “dungeon crawls” og “adventure” finner du en haug med vanlige, populære spill f.eks. [Zelda-serien](https://en.wikipedia.org/wiki/The_Legend_of_Zelda_(video_game)) (startet i 1986 med “gå rundt på et 2D-grid/kart, plukk opp ting, sloss med monstre og løs puzzles”; de nyeste versjonene tilbyr en åpen 3D-verden med detaljert fysikk, grafikk og lyd).
Vi har tenkt å holde det relativt enkelt (mer som 1980 enn som 2020), siden det antakelig er få av dere som er fulltids spilldesignere/spillprogrammører (og om du er det, har du neppe tid til å gjøre denne semesteroppgaven!).
“Rogue101” (du kan selvfølgelig finne på et eget navn) skal
* være [*turn-based*](https://en.wikipedia.org/wiki/Turn-based_strategy) dvs., spillet venter på at spilleren skal gjøre et trekk
* foregå på et [todimensjonalt rutenett/kart](https://en.wikipedia.org/wiki/Tile-based_video_game) basert på samme måte som Labyrint-labben, og sett ovenfra / i fuglepersektiv
* ha ting som spilleren kan plukke opp / gjøre noe med / legge fra seg
* ha andre aktører som går rundt på samme kartet og er styrt av datamaskinen (f.eks., monstre, kaniner, flyvende regnbueenhjørninger, zombier, amerikanske politikere, etc)
Om du nå er fristet til å gjøre litt [“research”](http://larn.org/larn/larn.html?mode=amiga) på [“problem](http://store.steampowered.com/tags/en/Rogue-like)-[domenet”](http://www.roguebasin.com/index.php?title=Main_Page), så trenger du ikke det oppgaven kommer med beskrivelse av reglene du skal implementere, og en del tips til mulige varianter. I siste del av semesteroppgaven kan du designe ting sånn som du selv har lyst til; du får gjerne litt ideer selv etterhvert som du blir kjent med systemet.
Det er altså *ikke* et mål å lage en kopi av Rogue eller et annet spill, og ting trenger overhodet ikke ha noe med dungeons, monstre og sverd å gjøre du kan f.eks. lage spill der du er korrupt saksbehandler i et kontorlandskap som må plukke opp alle sakspapirene og putte de i makuleringsmaskinen før FBI-agenten tar deg...
![original game screen shot](https://upload.wikimedia.org/wikipedia/commons/1/17/Rogue_Screen_Shot_CAR.PNG)
## Oversikt Modellering
Vi kan tenke på programmet vårt som en “modell” av et dungeon crawler spill.
For å finne ut hvilke klasser og interfaces vi trenger, må vi
* a) først tenke oss hvilke elementer som inngår i spill-verdenen;
* b) finne ut hvordan vi representerer og implementerer disse på datamaskinen.
Dette er likende til prosessen vi snakket om på de første forelesningene:
1. Vi har et problemdomene, *dungeon crawling*
2. Vi analyserer domenet, og lager en abstrakt beskrivelse av det, f.eks. spillreglene skrevet på papir.
3. Vi designer programmet, og prøver å lage en konkret implementasjon.
4. Vi tester programmet vårt mot forventingene, og justerer på ting og gjentar prosessen.
Mesteparten av denne jobben er allerede gjort for deg. Din jobb er nå å sette deg inn i koden og vår dungeon crawling modell. Vi har gjort analyse og design og en god del implementasjon, så vi er ca. på slutten av punkt 3. Du må bli kjent med koden og komfortabel med å gjøre endringer, og så gå videre med implementasjonen. I siste del av oppgaven er det du som er “sjefen”, og kan gjøre (nesten) som du vil med design og regler.
### Analyse hva er de essensielle bitene av Rogue-101?
Basert på tidligere erfaringer med slike spill, samt grunding tenking og lesing av de relevante Wikipedia-sidene, ser vi for oss følgende:
* Alt foregår på et ruteformet kart (2D grid)
* Hver celle/rute på kartet kan inneholde enten:
* en vegg
* 0 eller flere ting
* En “ting” i denne sammenhengen er:
* et objekt som spilleren/noen kan plukke opp og bruke til noe f.eks. en gulrot, et papirark, et sverd, en brunostskive, osv.
* *eller* en aktør en “levende” ting som kan bevege seg rundt på kartet
* For enkelhets skyld sier vi at det bare kan være maks én aktør i hver kartrute men en aktør kan dele plass med andre ting.
* Aktørene er enten styrt av datamaskinen, eller styrt av spilleren.
* For å gjøre ting litt mer spill-aktig, har vi følgende regler for ting og aktører:
* alle ting (inkl aktører) har “helse-poeng” som indikerer i hvor god form/stand aktøren/tingen er; negative helsepoeng betyr at tingen er helt ødelagt og skal fjernes fra brettet
* alle ting (inkl aktører) har “forsvars-poeng” som indikerer hvor god den er til å forsvare seg (mot å bli angrepet, plukket opp, vasket bak ørene, e.l.)
* alle aktører har "angreps-poeng" som indikerer hvor god den er til å overgå andres forsvar (og f.eks. skade dem, plukke dem opp, vaske dem bak ørene, e.l.)
* merk deg at alle ting har helse og forsvar, selv ting som er ikke er levende dette kan vi f.eks. bruke til å gjøre det mulig å ødelegge ting eller gjøre enkelte ting vanskelige å plukke opp
### Design hvordan lager vi dette i Java?
Basert på dette tenker vi oss følgende typer objekter:
* [IMapView](src/inf101/v18/rogue101/map/IMapView.java), [IGameMap](src/inf101/v18/rogue101/map/IGameMap.java) spillkartet
* [IGame](src/inf101/v18/rogue101/game/IGame.java) selve spillet, som styrer reglene i spillverdenen
* [IItem](src/inf101/v18/rogue101/objects/IItem.java) en ting. Siden både småobjekter (sverd og gulrøtter), aktører og vegger er ting som befinner seg på kartet, er det praktisk å gjøre alle til `IItem`:
* [Wall](src/inf101/v18/rogue101/objects/Wall.java) en `IItem` som ikke kan dele plass med noe annet
* [IActor](src/inf101/v18/rogue101/objects/IActor.java) en `IItem` som bevege seg og ikke kan dele plass med en annen `IActor`
* [IPlayer](src/inf101/v18/rogue101/objects/IPlayer.java) en `IActor` som styres ved at brukeren trykker på tastene
* [INonPlayer](src/inf101/v18/rogue101/objects/INonPlayer.java) en `IActor` som styrer seg selv (datamaskinen styrer)
Vi har også et par andre mer abstrakte ting vi bør tenke på f.eks. koordinater. Det går an å bruke heltall som koordinater / indekser (`int x`, `int y`), men det er generelt ganske praktisk med en egen abstraksjon for grid-plasseringer; blant annet kan vi da slippe å gjøre kompliserte utregninger på koordinatene for å finne frem til andre koordinater. Vi har derfor også:
* [ILocation](src/inf101/v18/grid/ILocation.java) en lovlig (x,y)-koordinat på kartet. Hver ILocation har opptil åtte andre ILocations som naboer, og har metoder for å finne alle eller noen av naboene, og for å finne nabo i en spesifikk retning.
* [GridDirection](src/inf101/v18/grid/GridDirection.java) en retning (NORTH, SOUTH, ...), til bruk sammen med ILocation
* [IArea](src/inf101/v18/grid/IArea.java) et rektangulært sett med ILocations. Brukes f.eks. av spillkartet for å lettvint gå gjennom alle cellene/rutene i kartet.
* ([IGrid<T>](src/inf101/v18/grid/IGrid.java) og [IMultiGrid<T>](src/inf101/v18/grid/IMultiGrid.java) IGrid<T> er tilsvarende til den du har brukt i labbene tidligere; IMultiGrid<T> er et grid der hver celle er en liste av T-er. Den blir brukt av spillkartet, men du trenger neppe bruke den selv.)
UML:
<a href="https://retting.ii.uib.no/inf101/inf101.v18/wikis/img/RogueInterface.png">
<img src="https://retting.ii.uib.no/inf101/inf101.v18/wikis/img/RogueInterface.png" width="200">
</a>
### *(4%)* Deloppgave A1: Tilstand, oppførsel og grensesnitt for objektene
*Du vil sikkert finne på lurere svar på spørsmålene etterhvert som du jobber med oppgaven. Det er fint om du lar de opprinnelige svarene stå (det er helt OK om de er totalt feil eller helt på jordet) og heller gjør tilføyelser. Du kan evt. bruke ~~overstryking~~ (putt dobbel tilde rundt teksten, `~~Rabbit.java funker fordi det bor en liten kanin inni datamaskinen~~`) for å markere det du ikke lenger synes er like lurt.*
Alle grensesnittene beskriver *hvordan du kan håndtere objekter* (dvs. objekter som er av klasser som implementerer grensesnittene). Selv om tilstanden til objektene er innkapslet (du vet ikke om feltvariablene), så lar metodene deg *observere* tilstanden, så ut fra de tilgjengelige metodene kan du spekulere litt rundt hvordan tilstanden må være.
Les gjennom grensesnittene vi har nevnt over ([IGame](src/inf101/v18/rogue101/game/IGame.java), [IMapView](src/inf101/v18/rogue101/map/IMapView.java), [IItem](src/inf101/v18/rogue101/objects/IItem.java), [IActor](src/inf101/v18/rogue101/objects/IActor.java), [INonPlayer](src/inf101/v18/rogue101/objects/INonPlayer.java), [IPlayer](src/inf101/v18/rogue101/objects/IPlayer.java) vent med å se på klassene) og svar på spørsmålene (skriv svarene i [README.md](README.md), det holder med én eller noen få setninger):
* **a)** Hva vil du si utgjør tilstanden til objekter som implementerer de nevnte grensesnittene? *(F.eks. hvis du ser på `ILocation` så vil du gjerne se at ILocation-objekter må ha en tilstand som inkluderer `x`- og `y`-koordinater selv om de sikkert kan lagres på mange forskjellige måter. De må også vite om eller være koblet til et `IArea`, siden en `ILocation` ser ut til å “vite” hvilke koordinater som er gyldige.)*
* **b)** Hva ser ut til å være sammenhengen mellom grensesnittene? Flere av dem er f.eks. laget slik at de utvider (extends) andre grensesnitt. Hvem ser ut til å ta imot / returnere objekter av de andre grensesnittene?
* **c)** Det er to grensesnitt for kart, både [IGameMap](src/inf101/v18/rogue101/map/IGameMap.java) og [IMapView](src/inf101/v18/rogue101/map/IMapView.java). Hvorfor har vi gjort det slik?
* **d)** Hvorfor tror du [INonPlayer](src/inf101/v18/rogue101/objects/INonPlayer.java) og [IPlayer](src/inf101/v18/rogue101/objects/IPlayer.java) er forskjellige? Ville du gjort det annerledes?
### *(3%)* Deloppgave A2: Eksempler på IItem og IActor
Til denne deloppgaven kan du se først på [Carrot](src/inf101/v18/rogue101/objects/Carrot.java) og [Rabbit](src/inf101/v18/rogue101/objects/Rabbit.java). Svar på spørsmålene (skriv svarene i [README.md](README.md), det holder med én eller noen få setninger):
* **e)** Stemmer implementasjonen overens med hva du tenkte om tilstanden i Spørsmål 1 (over)? Hva er evt. likt / forskjellig?
Se på [Game](src/inf101/v18/rogue101/game/Game.java) og [GameMap](src/inf101/v18/rogue101/map/GameMap.java) også.
`Rabbit` trenger å vite hvor den er, fordi den skal prøve å spise gulroten (hvis den finner en) og fordi den må finne seg et gyldig sted å hoppe videre til.
* **f)** Hvordan finner Rabbit ut hvor den er, hvilke andre ting som er på stedet og hvor den har lov å gå?
* **g)** Hvordan vet `Game` hvor `Rabbit` er når den spør / hvordan vet `Game` *hvilken* `Rabbit` som kaller `getLocation()`?
### *(8%)* Deloppgave A3: Litt endringer
* Du kan kjøre programmet ved å kjøre `inf101.v18.rogue101.Main`. Hendige tastetrykk (du skal få lov å legge til flere selv senere):
* *Return* gjør ett steg (selv om vi foreløpig ikke har en IPlayer på brettet)
* Ctrl-Q / Cmd-Q avslutt
* F11 eller Ctrl/Cmd-F bytt til/fra fullskjerm
* Ctrl-R / Cmd-R bytt mellom forskjellige varianter av 40- og 80-tegn tekstskjerm
Hvis du kjører programmet og trykker litt på returtasten vil du se at kaninene (merket med `r`) hopper rundt litt, at gulrøttene (oransje dingser med grønn topp) forsvinner og at kaninene så etterhvert forsvinner.
#### Smart kanin
Hvis du ser på koden for [Rabbit.java](src/inf101/v18/rogue101/examples/Rabbit.java) finner du gjerne også ut hvorfor ting oppfører seg slik: kaninenes helse er avhengig av at de finner noe å spise, og bevegelsene er helt tilfeldige. Prøv ut noen forskjellige endringer:
* **a)** Juster maksimale helsepoeng på kaninene (evt. også på gulrøttene), og om du merker noen forskjell (husk at programmet foreløpig ikke gjør noe før du trykker retur/enter)
* **b)** La kaninene alltid gå i samme retning (f.eks. `game.move(GridDirection.NORTH` kommenter ut den gamle koden). Prøv ut hva som skjer når de treffer vegger.
* **c)** En annen mulighet er å alltid gå i første tilgjengelige retning; dvs. samme som den opprinnelige implementasjonen, men plukk første retning i stedet for en tilfeldig en. Prøv dette. Ser det ut som de blir bedre eller dårligere til å finne gulrøtter?
* **d)** En enda bedre strategi er å sjekke alle nabofeltene, se om det ligger en gulrot der, og såfall gå dit (hvis den ikke ser en gulrot kan den f.eks. gå tilfeldig). Implementer dette. Tips:
* når du har funnet ut hvilke retninger (GridDirection) du kan gå i, kan du finne nabofeltene med `ILocation loc = game.getLocation(dir)` (evt `game.getLocation().go(dir)`).
* du kan finne ut hva som ligger i nabofeltet ved hjelp av kartet (`game.getMap()`); f.eks. med metoden `getItems()`.
* kaninen har allerede kode for å sjekke gjennom tingene og se om den finner en `Carrot` du kan kopiere og tilpasse denne
* hvis kaninen finner en gulrot kan den gjøre `game.move(...)` og så returnere med en gang
* **e)** Kaninens jobb blir litt enklere om den får litt hjelp fra `Game` med å finne ut hvor den kan gå. Implementer metoden `getPossibleMoves()` i `Game`.
#### Bedre gulrøtter
Prøv også å justere gulrøttene litt ([Carrot](src/inf101/v18/rogue101/examples/Carrot.java)):
* **a)** Gulrøttene får helsen satt til -1 når de blir spist etter helsereglene våre vil de derfor bli fjernet fra kartet. Prøv å sette helsen til 0 i stedet. Hvorfor går det ikke bedre med kaninene selv om gulrøttene nå blir værende på kartet?
* **b)** Det hadde kanskje vært praktisk (ihvertfall for kaninene) om gulrøttene vokste seg store og fine igjen etter en stund; for eksempel ved at de “helbreder” ett helsepoeng for hver runde som går men `Carrot` har ingen `doTurn()` metode slik `Rabbit` har, så den får ikke med seg at rundene går eller at kaninene hopper rundt (rent bortsett fra at det går an å “jukse” ved å regne med / håpe på at `draw()` blir kalt en gang per runde).
* ~~Lag en `doTurn()`-metode i `Carrot` som øker `hp` med 1 for hver runde (opp til `getMaxHealth()`).~~ (Denne fulgte med fra før.)
* Hva skjer, ser det ut til å virke?
* Hvis det ikke virker, hva må du eventuelt gjøre for å få `Carrot` til å gjøre noe hver runde?
* **c)** Du kan også prøve å la `Game` legge til nye, tilfeldig plasserte gulrøtter av og til:
* `random.nextInt(100) < 20` er en grei test hvis du f.eks. vil gjøre noe med 20% sannsynlighet
* For å finne en tilfeldig `ILocation` kan du bruke `map.getLocation(x, y)` med tilfeldig x og y (innenfor `getWidth()`/`getHeight()`). Du kan også plukke et tilfeldig element fra `map.getArea().locations()`.
* Før du evt. putter en `new Carrot()` på kartet må du også passe på at kartruten du har funnet er ledig (ihvertfall at den ikke inneholder en vegg).
### *(0%*) Deloppgave A4: Oversikt
**Tegn en liten oversikt over det du tenker er de viktigste grensesnittene/klassene i programmet.**
* Hvis noe `implements`/`extends` noe, tegn en pil til det det implementerer/utvider.
* Du kan skrive ned f.eks. de viktigste metodenavnene eller noen stikkord om rollen til den aktuelle typen.
* Tegn også en liten oversikt over objekter i forskjellige situasjoner (f.eks. Rabbit, Carrot, Game, GameMap og hvordan de (evt) kommuniserer når kaninen holder på å gjøre noe).
(Du trenger ikke legge ved tegningen din, men du kan gjerne lage og legge ved en oppdatert utgave når du har fått bedre/full forståelse av systemet.)
### *(0%)* Deloppgave A5: Ting du ikke trenger å se på
* Du trenger ikke se på koden i `gfx` (grafikkbibliotek), `grid` (utvidet IGrid) eller `util` (generering av testdata).
* Hvis du lager grafikk selv, vil du gjerne komme til å *bruke* [`ITurtle`](src/inf101/v18/gfx/gfxmode/ITurtle.java) (fra `gfx`), men du trenger ikke se på implementasjone.
* GameMap gjør bruk av `grid`-pakken, men du trenger antakelig ikke gjøre noe med den selv.
# Gå videre til [**DEL B**](SEM-1_DEL-B.md)

View File

@ -1,155 +0,0 @@
# [Semesteroppgave 1: “Rogue One oh one”](https://retting.ii.uib.no/inf101.v18.sem1/blob/master/SEM-1_DEL-B.md) Del B: Fullfør basisimplementasjonen
* [README](README.md)
* [Oversikt](SEM-1.md) [Praktisk informasjon 5%](SEM-1.md#praktisk-informasjon)
* [Del A: Bakgrunn, modellering og utforskning 15%](SEM-1_DEL-A.md)
* **Del B: Fullfør basisimplementasjonen 40%**
* [Del C: Videreutvikling 40%](SEM-1_DEL-C.md)
I denne delen av semesteroppgaven skal du implementere en del konkrete metoder.
### Konsepter
* *Factory pattern* *fabrikk-metoder* brukes til å lage nye objekter; ofte ved at du velger hva du vil ha med parameterne, uten at du trenger å kjenne til klassen. Passer veldig bra sammen med `interface` hvor du vet hvordan du skal bruke objektene men ikke hvordan du kan lage dem.
* (*Design pattern* er en vanlig måte å løse noe på uten at det finnes noen egen mekanisme for det i programmerinsspråket. Å bruke fabrikk-metoder og fabrikk-objekter til å lage objekter av en interface type er en vanlig design pattern.)
* *Event-drevet kjøring* du har ingen løkke i en `main`-metode som leser inn input fra brukeren; i stedet blir programmet vårt kalt opp når det skjer noe. Vanligvis vil datamaskinen da “sove” eller gjøre noe annet i mellomtiden. Dette kan også gjøre det litt lettere å teste spiller-objektet vårt vil ikke merke forskjell på om det er en faktisk bruker som har trykket en tast, eller vi bare simulerer et tastetrykk.
## *(3%)* Deloppgave B1: Objekt-fabrikk
* a) Se på konstruktøren i Game-klassen, og se hvordan kartet blir fylt inn. Finn metoden som lager nye objekter basert på strenger (`"#"`, `"."`, `"R"`, osv) dette er en såkalt [factory/fabrikk-metode](https://en.wikipedia.org/wiki/Factory_method_pattern). Det er vanlig å bruke når vi har mange klasser som implementerer det samme grensesnittet, og vi vil gjøre det lett for andre deler av programmet å opprette objekter uten å kjenne til klassene.
* **b)** Lag deg en ny klasse som implementerer [IItem](src/inf101/v18/rogue101/objects/IItem.java). Du kan ta utgangspunkt i en av klassene du har fra før (f.eks. `Carrot`) og du kan velge navn selv (f.eks. `CarrotCake`). Funksjonaliteten kan (foreløpig) være helt lik.
* **c)** Legg klassen til i fabrikk-metoden. Du må velge et tegn som skal representere objekter av klassen (f.eks. `"c"`). Bruk dette tegnet både i fabrikk-metoden i `Game` og i `getSymbol()`-metoden i den nye klassen din (det er ingen direkte sammenheng mellom disse, men greit om de stemmer overens).
* **d)** Legg til det nye tegnet ditt i standard-kartet (ligger i [src/inf101/v18/rogue101/map/maps/level1.txt](src/inf101/v18/rogue101/map/maps/level1.txt) eventuelt ligger det et innebygget kart i `Main`-klassen hvis vi av en eller annen grunn ikke finner kartfilen; vi bruker forøvrig samme kartformat som [semesteroppgave 1 i fjor](https://retting.ii.uib.no/inf101.v17.oppgaver/inf101.v17.sem1/)), og se at gulrotkaken (eller det du har laget) dukker opp på skjermen.
Symbolene på skjermen blir hentet fra `getSymbol()` (evt. `getPrintSymbol()` om du har definert den). I tillegg til å kunne tegne tekst-tegn kaller programmet `draw()`-metoden hvor du kan legge inn egen grafikk; hvis denne returnerer `true` blir tegnet fra `getSymbol()` ikke tegnet på skjermen. Så hvis du bare ser ekstra `X`-er, så har du kopiert `ExampleItem` uten å endre `getSymbol()`, og hvis du bare ser ekstra gulrøtter, så har du kopiert `Carrot` uten å oppdatere grafikken (du kan bare slette draw-metoden og returnere false).
*(Avansert mulighet (ikke del av oppgaven): i stedet for å lage en stor fabrikk med `switch` går det an å bygge en oversikt over fabrikkene mens programmet kjører. Du kan registrere symbolet for den nye klassen + en kodesnutt som lager objekt i `itemFactories` i `Game`: f.eks. `itemFactories.put("R", () -> new Rabbit())`. `default`-tilfellet i `switch`en vil prøve å slå opp i `itemFactories` og kalle kodesnutten hvis den finner noe. Registreringen kan gjøres i konstruktøren til `Game`, eller du kan lage en ekstra `addFactory`-metode.)*
## *(7%)* Deloppgave B2: Minimal Player
Du er sikkert lei av at det bare er kaninene som får lov til å ha det gøy.
* **a)** Lag en klasse `Player implements` [`IPlayer`](src/inf101/v18/rogue101/objects/IPlayer.java) (putt den i `objects` eller en egen ny `player` pakke). Du kan følge mønsteret fra de andre IItem-klassene, men du trenger litt andre metoder. Der hvor `Rabbit` har `doTurn()` skal `Player` ha `keyPressed()`. Du kan la denne være tom til å begynne med.
* **b)** Du må oppdatere fabrikken i `Game` så den også lager `Player`-objekter; de har tradisjonelt symbolet `@` (i utlevert kode gir det deg en `ExampleItem`).
* **c)** Metoden `keyPressed()` i `IPlayer` tar et `KeyCode`-object, og kalles hver gang spilleren
trykker på en tast. Knappen indikeres med KeyCode-en (en for hver tast på tastaturet + at man kan sjekke f.eks. om *Ctrl*-tasten er trykket inn). F.eks. vil følgende kode sjekke om
venstre-tasten ble trykket, og kalle `tryToMove()` (denne metoden er ikke implementert ennå):
```
public void keyPressed(IGame game, KeyCode key) {
if (key == KeyCode.LEFT) {
tryToMove(game, GridDirection.WEST);
}
}
```
Gjør ferdig denne metoden så den kaller `tryToMove` med `GridDirection.EAST`, `GridDirection.NORTH`, eller `GridDirection.SOUTH` når spilleren trykker `KeyCode.RIGHT`, `KeyCode.UP`, eller `KeyCode.DOWN`.
(Dette er typisk enkel *event-drevet programmering* hvor metoder i programmet vårt blir kalt når
ting skjer utenfor programmet. Dette er vanlig for spill, nettverkstjenere og programmer med grafiske brukergrensesnitt man har en metode som blir kalt for hvert tidssteg, og metoder som blir kalt når tastatur eller mus brukes eller det kommer inn en ny forespørsel over nettet. Legg merke til at det ikke er slik at Player gjør noe for å sjekke om brukeren har trykket på en tast derimot blir metoden `keyPressed` kalt når tasten trykkes, og Player vet ingenting om hvordan det skjer eller hvor tastetrykkene kommer fra.)
* **d)** Du trenger også metoden `tryToMove()` (du kan kalle den hva du vil, men det er greit å ha den som en egen metode, siden du gjør nesten det samme for alle retningene).
* Den må spørre `game` om det er lov å gå i den aktuelle retningen, og i såfall kalle `game.move()` for å flytte i den gitte retningen. Du kan se hvordan `Rabbit` løser dette hos Player slipper du heldigvis å tenke på hvor det er *lurt* å flytte, siden brukeren alt har bestemt det.
* Hvis det ikke er lov å flytte (det er en vegg der eller en kanin), kan du f.eks. gi en tilbakemelding til brukeren med `game.displayMessage("Ouch!")`. Hvis du er ekstra streng, kan du også la spilleren tape litt helse på å stange hodet i veggen.
* **e)** Brukeren trenger sikkert også litt statusinformasjon, f.eks. om antall helsepoeng. Lag en metode `showStatus(game)` i `Player`-klassen din. Den kan f.eks. bruke `game.displayStatus("...")` eller `game.formatStatus("... %d ...", verdi)` (hvis du er komfortabel med `printf`-liknende strengformattering). Begge disse printer en linje med tekst på skjermen (Main-klassen holder rede på de passende linjene, status havner på linjen `Main.LINE_STATUS` som er 21 (rett under kartet hvis kartet er 20 linjer høyt)). Kall `showStatus()` på slutten av `keyPressed()` (hvis du senere lager andre metoder som kan endre tilstanden til spilleren, bør du kalle `showStatus()` på slutten av disse også).
* **f)** Lag noen tester for Player-klassen din, som sjekker bevegelsene. Du kan ta utgangspunkt i den lille testen som ligger i [PlayerTest.java](src/inf101/v18/rogue101/tests/PlayerTest.java); test at det funker å flytte seg i forskjellige retninger, og at det *ikke* funker å flytte seg inn i veggen.
## *(5%)* Deloppgave B3: Sortering av items
Vi er ikke så veldig lure med hvordan vi samler en mengde IItems i en List i kart-cellene. F.eks. blir grafikken antakelig veldig rotete om vi prøver å tegne opp mer én ting i hver rute så vi trenger gjerne en bedre måte å bestemme rekkefølgen de ligger i listen på (eller evt. hvordan vi velger hvilken ting vi skal tegne). I den utleverte koden tegner vi alltid bare den første tingen i hver celle, uavhengig av om den er interessant eller ikke. Du har kanskje lagt merke til at kaninene “forsvinner” når de står på et felt med en gulrot (hvis ikke, kan du prøve å flytte spilleren til en gulrot og se hva som skjer).
En grei løsning er å si at vi vil se den *største* tingen alle IItems har en `getSize()` metode som forteller hvor “stor” den er (uten at vi har brukt dette til noe hittil). IItems er også `Comparable` det følger med en `default` `compareTo()`-metode i `IItem` som sammenlikner størrelse (`getSize()`).
For å fikse dette vil vi at kartet skal ha tingene liggende i sortert rekkefølge i listene for hver celle. Vi kunne sortert listen hver gang vi hentet den (f.eks. hver gang kaninen kaller `game.getLocalItems()`, slik at den største gulroten kommer først), men det er både raskere og ca. like lettvint å passe på at vi legger ting inn i sortert rekkefølge: Hvis vi skal legge et element *e* inn i listen *l*, så vil vi ha det på den første posisjonen *i* slik at *e.compareTo(l.get(i)) >= 0* (altså, sett inn *e* foran det første elementet *e* er større enn).
* **a)** Legg til alternativet for `"."` i `Game.createItem()` den skal produsere et [`Dust`-objekt](src/inf101/v18/rogue101/objects/Dust.java).
* Hvis du kjører programmet nå, vil du antakelig se at mange av kaninenen “gjemmer seg” de ligger altså under støvet (Dust-objektene; sees som litt mørkere felter).
* **b)** Endre `add`-metoden i `GameMap` slik at nye items blir lagt til i sortert rekkefølge (største først).
* Husk at `a.compareTo(b)` er `< 0` hvis `a` er mindre `b`, `== 0` hvis `a` er lik `b` og `> 0` hvis `a` er større `b`.
* Du kan legge element foran det nåværende elementet på posisjon `i` med `list.add(i, e)` (det er også OK om `i == list.size()`, da legger du til et nytt element på slutten av listen)
* Det holder å kalle `add` på listen, siden `list` refererer til samme objektet som ligger inne i kart-cellen.
* `Dust`-objektene er ganske små (størrelse 1), så hvis du har gjort det riktig, vil kaninene (og spilleren) bli tegnet i stedet for støvet.
* **c)** Test `add`-metoden.
* Finn testklassen [GameMapTest](src/inf101/v18/rogue101/tests/GameMapTest.java) og testmetoden vi har begynt på (`testSortedAdd`).
* Du må sette opp et test-scenario:
* du trenger et nytt GameMap (det trenger ikke være fylt med noe)
* du trenger også en ILocation, siden de fleste kart-metodene bruker det (kall `getLocation(x,y)` med en kjent, lovlig posisjon)
* så må du opprette noen IItems og legge dem til på kartposisjonen ved å kalle `add()` på kartet
* Til slutt kan du teste at tingene ligger i den rekkefølgen du forventer (`getAll()`, og sjekk listeelementene med `get()`)
* *(Litt mer avansert:)* Hvis du vil teste med litt større mengder data er det gjerne upraktisk å sjekke nøyaktig hvordan elementene er plassert da kan du i stedet gå gjennom listen og sjekke at `list.get(i).compareTo(list.get(i+1)) >= 0` for `0 <= i < list.size()-1`. Et godt utvalg data kan du få ved å lage deg en metode som lager tilfeldige IItems den kan uansett være nyttig for å lage tilfeldige kart og slikt. (Du skal lære dette mer grundig i neste lab-oppgave.)
*(Avansert mulighet (ikke del av oppgaven): En mer generell løsning er å lage en sortert liste (kanskje helst `IList/MyList` fra Lab 2/3/4, men evt `List/ArrayList`) og så bruke den i stedet for vanlig liste i `IMultiGrid` og `MultiGrid`. Du trenger litt mer avansert Java-kunnskap for å få det til å funke, du må bla. si at elementtypen er sammenliknbar (f.eks. `ISortedList<T extends Comparable<T>>`) vi ser mer på dette senere i semesteret. )*
## *(5%)* Deloppgave B4: Plukk opp / dropp ting
Vi vil gjerne la brukeren kunne plukke opp og legge fra seg ting på kartet halvspiste gulrøtter, for eksempel.
* **a)** For å få til dette må du legge til flere tastetrykk til `keyPressed`-metoden i `Player` du kan f.eks. bruke `KeyCode.P` og `KeyCode.D`. Lag gjerne egne metoder for å plukke opp/droppe ting i spilleren.
* *Legg merke til:* andre metoder i `Player` er laget slik at de tar et `IGame`-argument. Det trenger du nok her også fordi du må snakke med spill-objektet for å interagere med kartet og andre ting. Du *kan* lagre `game` som en feltvariabel, så du slipper å sende den rundt som argument. Vi har latt være å gjøre det fordi: a) det er lettere å opprette og teste Player (og andre IItems/IActors) hvis man ikke trenger å lage gi dem et game-objekt (f.eks. kunne du teste GameMap/sortert add uten å bruke `Game`/`IGame` i det hele tatt); og b) det kan være litt forvirrende med sykliske avhengigheter mellom objekter (ikke minst når forholdet endrer seg f.eks. når ting fjernes fra spillet).
* **b)** `Game` har tilsvarende `pickUp()` og `drop()` metoder du kan bruke for å plukke et objekt fra kartet og for å etterlate et objekt på kartet. Metoden `pickUp()` returnerer `null` om du av en eller annen grunn ikke kunne plukke opp tingen. Implementér “plukke opp”-funksjonaliteten. Hint:
* `game.pickUp()` plukker opp et spesifikt objekt som ligger i kartruten du står i, så du er nødt til å finne ut *hvilket objekt* du vil prøve å plukke opp hvis det er flere mulighetre (foreløpig har brukeren ingen måte å be om et spesifikt IItem på);
* du finner alle tingene som ligger i kartruten med `game.getLocalItems()`, og du kan f.eks. prøve å ta den første. Du kan også finne tingene ved å få tak i kartet (game.getMap()) og undersøke det direkte bare pass på at spilleren ikke ender opp med å plukke opp seg selv! (getLocalItems() gir deg bare items som ikke er IActor, så den er “trygg”)
* husk at ruten kan være tom, dvs at `game.getLocalItems()` gir tom liste da kan du f.eks. gi bruken beskjed om at det ikke er noe å plukke opp.
* **c)** For å kunne legge fra deg ting må du ha lagret objektet du plukket opp, f.eks. i en feltvariabel i `Player`. Foreløpig går det greit å tenke seg at du bare kan holde på én ting, så da er det lett å vite hva du skal legge fra deg. Implementér “dropp / legg fra deg”-funksjonaliteten. Hint:
* Du kan gi en passende melding til brukeren om du ikke har noe å legge fra deg.
* Pass på at når du har lagt fra deg objektet (med `game.drop()`) så sletter du det fra `Player`-objektet ellers kan du massekopiere ting ved å plukke opp én ting og så legge den fra deg mange ganger.
* `game.drop()` kan i prinsippet feile (fullt på bakken, kanskje?), i såfall returnerer den `false` og du bør *ikke* slette tingen fra `Player`-objektet
* **d)** Det er praktisk for brukeren å vite hva man bærer på, så legg inn navnet på objektet i status-meldingen (fra B2.e)
## *(5%)* Deloppgave B5: Finne synlige ting / ting i nærheten
[IGame](src/inf101/v18/rogue101/game/IGame.java) spesifiserer en metode `getVisible()` som skal gi deg alle locations i nærheten som du kan se. Denne er foreløpig ikke skikkelig implementert. Den kaller `map.getNeighbourhood(currentLocation, dist)`, som mangler implementasjon for dist > 0.
* **a)** Lag en enkel versjon av `getNeighbourhood()` i [GameMap](src/inf101/v18/rogue101/map/GameMap.java) som bare returnerer alle de direkte naboene til lokasjonen. ILocation har metoder som kan hjelpe deg (men du må kanskje flytte resultatet over i en liste). Med *naboer* mener vi her alle de åtte cellene som er rundt cellene i midten, *unntatt* de av naboene som er utenfor kartet (du vil uansett ikke få tak i ILocations for dissse); og med *nabolag* tenker også på naboene til naboene osv.
* **b)** Det er litt dumt å bare kunne se de aller nærmeste cellene. Endre din `getNeighbourhood()` slik at den finner alle locations som er innenfor <code>dist</code> cellers avstand. (Dette er gjerne mye vanskeligere. Du kan sette begrensninger på <code>dist</code> om vil, men du bør håndtere minst 3.)
* **c)** Du bør lage tester for dette også, slik som i B3. Du trenger et GameMap, og en ILocation på kartet.
* Du kan sjekke at resultatet fra `getNeighbourhood()` er riktig ved å gå gjennom hele listen og så sjekke at `centre.gridDistanceTo(element) <= dist`.
* Du må også teste at du får det forventede antall naboer (f.eks. så lenge du er midt inne i kartet skal du ha 8 naboer for `dist=1`, 24 for `dist=2`). Sjekk også at du får riktig antall naboer når du er ute i kanten eller hjørnene av kartet. Du bør gjerne ha tester for minst 3 scenarier.
* *d)* *(Ekstra:)* nabolagslisten er litt mer praktisk hvis de nærmeste naboenen kommer først. Det kan være din versjon allerede funker slik men i såfall bør du også teste det.
* Gjør om nødvendig om på `getNeighbourhood()` slik at de nærmeste cellene kommer først i listen.
* Lag en test / juster testene over, slik at du sjekker avstanden (med `gridDistanceTo()`) til senere elementer i listen alltid er like eller større en avstanden til de tidligere elementene (du kan bruke liknende teknikk som når du testet at items var sortert etter størrelse).
Du vil kanskje ha lyst på en annen (mer fornuftig) `getVisible()` senere; du kan endre denne så den bruker noe annet enn `getNeighbourhood()` (eller evt. gjør justeringer på resultatet). Du kan bruke `getVisible()`/`getNeighbourhood()` til å gjøre kaninens gulrot-leting mer effektiv, f.eks.
Hvis du vil ha *skikkelig* synlighet, f.eks. slik at aktørene ikke kan oppdage det som er bak vegger, trenger du en [betydelig mer komplisert synlighetsalgoritme](http://ncase.me/sight-and-light/). Den går an å lage en veldig simplistisk synlighetstest ved hjelp av `ILocation.gridLineTo(ILocation)`, som gir deg alle locations om ligger på en linje mellom denne og en annen location men dette er ikke en del av oppgaven (du kan selvfølgelig likevel prøve deg i Del C!).
## *(5%)* Deloppgave B6: Enkelt “Angrep”
Tradisjonelle roguelikes er *veldig* opptatt av slossing (kan med rette kalles “[hack-and-slash](https://en.wikipedia.org/wiki/Hack_and_slash)”), så vi bør ha med en eller annen slik mekanikk. Du kan selvfølgelig velge selv (i del C) hva slags betydning dette skal ha for historien i spillet (om du har en historie).
Kampmekanikken er en forenkling av vanlige regler fra liknende dataspill og bord-rollespill:
* A *gjør et angrep* på B
* A har en *attack score* og B har en *defence score*
* Vi tilsetter litt tilfeldighet, og hvis *attack* > *defence* har A vunnet, ellers har B vunnet.
* Hvis A vinner, blir B skadet A har en “damage score” som sier hvor mye og B sine “health points” holder rede på skade som har skjedd og hvor alvorlig den er
* Hvis B vinner, skjer det ingen ting bortsett fra at det nå antakelig er B sin tur, og B kan angripe A (eller løpe sin vei)
En grei formel for angrep er f.eks.: `attack+random.nextInt(20)+1 >= defence+10` (brukt i et populert bordrollespill basert på 20-sidede terninger).
* **a)** Du må implementere ferdig metoden `Game.attack(dir, target)` (vi har lagt den i Game-klassen, slik at den kan håndtere spillereglene uten at aktørene "jukser"). Du kan justere reglene litt etter hva du ønsker selv, men formelen over er at bra utgangspunkt.
* Når du har avgjort vinneren kan du gi en passende melding på skjermen. F.eks., `formatMessage("%s hits %s for %d damage", currentActor.getName(), target.getName(), damage);` og en tilsvarende hvis angrepet mislykkes.
* Du skal også kalle `handleDamage()` på target-objektet. Denne metoden returnerer skaden som *faktisk* skjedde det kan f.eks. brukes i tilfeller hvor forsvareren hadde en eller annen form for beskyttelse.
* **b)** Selv om Game nå kan avgjøre hva som skjer med angrep, er det foreløpig ingen som vil prøve seg på å angrip.! Oppdater `Rabbit` slik at `doTurn()` metoden kaller `attack()` i stedet for `move()` (enten når det er mulig, eller når spilleren ved siden av):
* Du trenger å sjekke alle gyldige naboer, ikke bare de du kan gå til du er kanskje særlig interessert i å angripe andre IActors, og de befinner seg i felter du ikke kan gå inn i (ja, i prinsippet vil det også være mulig å angripe og ødelegge veggene men de har ganske mange helsepoeng!).
* I prinsippet kan du angripe et hvilket som helst `IItem` så lenge det er i et nabofelt (evt. kan du oppgi `GridDirection.CENTER` og angripe noe i samme felt), men du har kanskje lyst til å sjekke mot `instanceof IActor` eller `instanceof IPlayer`.
* Du må kalle `attack()`-metoden med et spesifikk `IItem` som mål, og med en spesifikk retning.
* En mulighet er f.eks.: gå gjennom alle nabocellene; hvis du ser en gulrot, flytt dit, hvis du ser en IPlayer, angrip og eller beveg i en tilfeldig retning.
* Prøv spillet og se hva som skjer.
* **c)** Spilleren bør også kunne angripe. En grei mekanikk for det er at når spilleren prøver å “gå på” en annen aktør, så telles det som angrip (i stedet for å resultere i en “Ouch!”, eller enda verre IllegalMoveException). Går helt fint å la spilleren få lov å angripe veggene også. Siden du må velge et spesifikt item å angripe, kan du f.eks. velge det første fra `game.getLocalItems()` (evt. finne noe som er en IActor hvis mulig).
* Prøv spillet og se hva som skjer.
*MERK:* det er forskjell om en kartcelle er “lovlig”, “lovlig og opptatt” og “ulovlig”. Hvis du prøver å gå `NORTH` fra (0,0) vil du f.eks. havne utenfor kartet, så dette er en ulovlig celle (egentlig ikke en celle i det hele tatt). Hvis du antar at du har en location `loc` (f.eks. din nåværende plassering fra `game.getLocation()`):
* Hvis du gjør `loc.canGo(GridDirection.NORTH)`, så får du vite om det finnes en lovlig location nord for nåværende location; tilsvarende med `game.getMap().hasNeighbour(loc, GridDirection.NORTH)`. Det kan likevel godt være at du ikke får lov til å gjøre `game.move(GridDirection.NORTH)`, f.eks. fordi det er en vegg der.
* Hvis du gjør `game.canGo(GridDirection.NORTH)` eller `map.canGo(GridDirection.NORTH)` får du vite om det går an å gå nordover, altså at naboen i nord ikke er ulovlig og ikke er opptatt (av en vegg eller en aktør). Litt forskjellige deler av systemet har altså litt forskjellig oppfatning av “canGo” og om man skal sjekke om ting er opptatt eller ikke.
* For angrep er du antakelig særlig interessert i feltene som er lovlige men opptatte.
## *(5%)* Deloppgave B7: Spørsmål
* **a)** Du har måttet gjøre en del arbeid med nabo-celler og slikt. Håndterer du dette på en annen måte enn vi gjorde i labbene (f.eks. cell-automatene og labyrinten)? Hva synes du er mest praktisk?
* **b)** Hvorfor går de fleste av spill-"trekkene" (slik som at noen flytter seg, plukker en ting, legger ned en ting, angriper naboen, etc.) gjennom Game? Kan du se for deg fordeler / ulemper ved dette?
* **c)** I en del av metodene burde vi kanskje vært litt mer presise på hva som er “forkravene” hva må være oppfylt for at det skal gå bra å kalle denne metoden? Vi har nevnt litt at `game.move()` krever at feltet i retningen er lovlig og ledig. Se gjennom de andre metodene i `Game` og `GameMap` og se om de har spesielle antakelser rundt parameterne. Ser du noe som burde endres? F.eks., enten metoder som sjekker for ting som kan gå galt, men ikke sier noe om forutsetningene i dokument eller metoder som *burde* sjekket parameterne sine / andre forutsetninger. F.eks., hva med `Game.addItem()` (og `drop()` også, forsåvidt) bør den f.eks. sjekke at feltet ikke allerede er opptatt (f.eks. legge til ny IActor når det allerede er en IActor der, e.l.)?
* **d)** Tenker du annerledes om noen av spørsmålene fra Del A nå?
## *(5%)* generelt
*Ca. 5% for generell ryddighet og kvalitet.*
# Gå videre til [**DEL C**](SEM-1_DEL-C.md)

View File

@ -1,123 +0,0 @@
# [Semesteroppgave 1: “Rogue One oh one”](https://retting.ii.uib.no/inf101.v18.sem1/blob/master/SEM-1_DEL-C.md) Del C: Videreutvikling
* [README](README.md)
* [Oversikt](SEM-1.md) [Praktisk informasjon 5%](SEM-1.md#praktisk-informasjon)
* [Del A: Bakgrunn, modellering og utforskning 15%](SEM-1_DEL-A.md)
* [Del B: Fullfør basisimplementasjonen 40%](SEM-1_DEL-B.md)
* **Del C: Videreutvikling 40%**
## Videreutvikling av Rogue-101
Vi overlater nå ansvaret for utviklingen til deg du finner noen forslag under som du kan jobbe ut ifra, eller så kan du finne på din egen utvikdelse av koden. For å få maks poengsum på oppgaven må du gjøre to av forslagene, eventuelt erstatte ett eller begge med noe du kommer på selv, som er tilsvarende stort i omfang.
Når du nå er ferdig med Del A og B skal du ha et dungeon crawler (evt. rabbit hopping) spill med en spiller som kan
* bevege seg rundt på kartet
* se synlige ting rundt seg
* plukke opp ting
* bære én ting
* legge fra seg ting
* angripe
Du har også gulrøtter som kan plukkes opp, og kaniner som kan spise gulrøtter og angripe ting.
Herfra kan du enten fortsette å legge på funksjonalitet på koden du har, eller brette opp ermene og lage ditt eget spill med andre klasser enn de vi har gitt her det kanskje mest aktuelt å bytte ut item-klassene. Du kan gjerne skrive en “intro” til spillet, og “flavour” i `displayMessage`. Uansett om du vil bruke klassene vi har gitt deg eller lage dine egne, må du huske å levere klassene du jobbet med i del A og B.
Du må selv bestemme hva mer som skal legges til av funksjonalitetet, og hva du evt. vil gjøre for å gi spillet litt mer stemning (grafikk, kanskje?). Som nevnt tidligere kan du velge “setting” og “storyline” som du vil du trenger ikke å lage huleutforskning med magi, sverd, orker og hobbiter eller med kaniner og gulrøtter. Skriv ned forklaring til det du gjør i README.md både funksjonalitet som du legger til, og kreative ting du finner på vi legger ikke nødvendigvis merke til alt når vi prøvekjører ting, så det er greit å vite hva vi skal se etter.
Siden vi ikke vet hva slags lure ting dere kommer på å implementere, skriver vi de følgende forslagene ut ifra koden vi har gitt dere. Du står fritt til å i stedet lage tilsvarende funksjonalitet for klasser i spillet du lager selv. Når vi skriver “spilleren”, kan det altså være at du vil bruke en annen klasse enn `Player`-klassen, eller at du vil gi denne funksjonaliteten til en `INonPlayer`.
Følgende er forslag til hva du kan gjøre, ikke nødvendigvis i den rekkefølgen.
### C1: Ting/items som påvirker spillet
Spilleren vår vil gjerne kunne finne andre ting i labyrinten enn gulrøtter. I denne delen kan du lage flere ting, for eksempel noe som gjør spilleren flinkere til å angripe, eller øker helsen den har. Du kan lage “healings potions” som øker helsepoengene til spilleren. Dersom du vil at spilleren skal kunne slåss bedre, kan du lage våpen, for eksempel av typen langkost. Dersom du angriper en kanin med en langkost gir det deg kanskje en høyere attack score enn uten. (Du kan selv velge hvordan type ting påvirker angrep, helsepoeng, og kanskje også hverandre).
Det kan være at tingen tar effekt når du plukker den opp, eller kanskje spilleren må trykke på en tast (klassiske roguelikes bruker gjerne `q` for “quaff a potion” eller `w` for “wield a weapon”).
For å implementere disse tingene må du lage klasser for dem og extende IItem. De vil likne på gulrot-klassen. Du må selv finne ut hvordan de skal tegnes. Se styling-seksjonen for tips til grafikk.
### C2: Inventory - bærenett
Dersom spilleren kan finne flere forskjellige typer ting i labyrinten, er det kjekt å kunne bære mer enn én ting av gangen. Hvis labyrinten enda bare har gulrøtter, vil spilleren kanskje kunne samle mange av dem, og bære dem med seg og alt du trenger å holde rede på er antall gulrøtter. Men for varierende typer ting, trenger vi en bedre løsning.
I objektorientering er vi opptatt av abstraksjon og forståelig kode, så selv om vi kunne ha latt spilleren få flere feltvariabler for å holde styr på alle tingene den bærer, så vil vi heller implementere en egen klasse for en *samling* (eller Collection) av ting. Java har standard lister, men her trenger vi kanskje noe litt annet: det bør jo gjerne ha en begrensning på hvor mye man kan bære med seg.
* Samlingen bør lagre `IItem`-objekter, eventuelt at den er generisk med `<T extends IItem>`.
* Du kan velge om begrensningen er på antall elementer, eller på total størrelse (`getSize()`) for alle elementene i samlingen.
* Du må ha metoder for å putte noe inn i samlingen, hente noe ut, sjekke om det er ledig plass, osv. Du trenger ikke ha indekser det holder å kunne putte inn og hente ut.
* Hvis noen prøver å putte noe inn i en full samling (eller noe det ikke er plass til i samlingen) bør du kaste en exception.
For tips til implementasjon av samling kan du se på [IList/MyList-listene fra tidligere labber](https://retting.ii.uib.no/inf101.v18.oppgaver/inf101.v18.lab4/tree/master/src/inf101/v18/datastructures). Du kan gjerne bruke Java sitt [standard-bibliotek for samlinger](https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html) i implementasjonen (legg merke til at du trenger en konkret implementasjon av interfacet, for eksempel en [ArrayList](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html)).
* For litt mer solid INF101-design, bør du gjerne designe et eget grensesnitt, f.eks. `IContainer<T extends IItem>` da kan du også ha flere varianter av samlinger (som f.eks. virker på forskjellig måte).
* Spilleren (og kaninene) kan bruke samlingen du har laget som bærenett eller ryggsekk til å lagre items som blir plukket opp. Brukeren vil antakelig ha lyst til å ha oversikt over hva som er i “sekken” det er ledig plass på skjermen hvor du kan vise mer informasjon se på metodene `getPrinter()` (du kan skrive ting på skjermen med `printAt(x,y, text)`), `getFreeTextAreaBounds()` og `clearFreeTextArea()`.
* En mer avansert og artig bruk av `IContainer` er å la den også utvide `IItem`. Da kan du putte ting i sekken din, og legge sekken på bakken eller putte en kanin inn i en hatt inn i en sekk inn i en koffert og plukke opp og sette fra deg kofferten.
### C3 Styling
Du kan kommet et godt stykke på vei med litt kreativ bruk av tekst-symbolene. For enkel blokk-grafikk (til vegger, f.eks.) så finnes det en del forskjellige tegn du kan bruke i [BlocksAndBoxes](inf101/v18/gfx/textmode/BlocksAndBoxes.java). Hvis du implementer `getPrintSymbol()` så kan du bruke et eget tegn til grafikk-visningen (hvis du bruker bokstaven i `getSymbol()` til noe fancy fabrikk, f.eks.).
#### Fancy vegger
*(Du kan selvfølgelig gjøre tilsvarende med andre ting enn vegger)*
F.eks. bruker `Wall`-objektene `BlocksAndBoxes.BLOCK_FULL` som symbol. Det kan være litt tricky å få `Wall` til å variere `getSymbol()` avhengig av hvor den har andre vegger som naboer, men du kan i prinsippet lage flere varianter av wall:
* Her er det mest praktisk å bruk *arv*, f.eks.:
```
public class DiagonalWall extends Wall {
// Java vil bruke denne i stedet for getSymbol() fra Wall men alle andre metoder følger
// med fra Wall.
@Override
public String getSymbol() {
return BlocksAndBoxes.DIAG_FORWARD;
}
}
```
* Du trenger også å legge til alle vegg-variantene i `createItem`-metoden.
* Du trenger at alle vegger har `Wall`-typen, fordi kartet bruker det til å se om et felt er opptatt (bla gjennom items på en lokasjon, sjekk om `item instanceof Wall`). Når du sier at `DiagonalWall extends Wall`, så vi alle diagonale vegger også telle som vanlige vekker.
* Alternativet ville vært å enten legge til en metode `isWall()` i `IItem`; eller si at en kartcelle er opptatt hvis det er en veldig stor ting der (`getSize()` større enn 100 eller 1000, f.eks.); eller lage et ekstra grensesnitt `IWall` (og både `Wall` og `DiagonalWall` `implements IWall`) og bruke det istedenfor der hvor man trenger å sjekke etter vegger.
En annen mulighet for fancy vegg er å la veggene tilpasse seg omgivelsene. Det krever litt samarbeid mellom Game og Wall f.eks. kan du finne alle veggene (enten i `beginTurn()` eller når du setter opp kartet) og kalle en ny metode som du lager (f.eks. `setup(IGame game)`). Veggen kan så utforske naboene sine, og finne ut hvilke av dem som er vegger, og velge riktig box-tegn enten en av `BLOCK_*`-tegnene fra `BlocksAndBoxes`, eller med [Box-drawing characters](https://en.wikipedia.org/wiki/Box-drawing_character) (disse var mye brukt på gamle DOS-datamaskiner, men det er nå en standard del av Unicode-tegnsettet, og `Printer`-klassen støtter dem uavhengig av hvilken font du bruker.). Du kan paste box-tegn (og block-tegn) rett inn i koden din (så lenge [Eclipse er riktig satt opp med UTF-8](https://retting.ii.uib.no/inf101/inf101.v18/wikis/oppsett#fiks-for-tegnsett)), eller bruke [`\uXXXX` escape-koder](https://docs.oracle.com/javase/tutorial/java/data/characters.html) i strengen. F.eks., `"╣"` er `"\u2563"`.
#### Emojis
Hvis du bytter font vil du kunne bruke en haug med praktiske symboler. Du kan sette fonten i `start()` metoden i [Main](inf101/v18/rogue101/Main.java)-klassen. “Symbola” inneholder standard [Unicode emojis](https://en.wikipedia.org/wiki/Emoji#Unicode_blocks) i tillegg til vanlige bokstaver. Du kan [laste den ned herfra](http://users.teilar.gr/~g1951d/).
* Hvis du putter `Symbola.ttf` i `src/inf101/v18/gfx/fonts/`, skal du kunne kjøre `printer.setFont(Printer.FONT_SYMBOLA);` i `start()`, og så bruke f.eks. `"☺️"` (`"\u263a"`) som symbol for spilleren.
* Merk at en del mer obskure Unicode-emojis, som [`"🦆"`](https://en.wikipedia.org/wiki/%F0%9F%A6%86) må skrives med to escape koder (`"\ud83e\udd86"`) og er ikke nødvendigvis med i fonten du bruker.
* Vanlige bokstaver ser dessverre ikke så veldig fine ut i Symbola-fonten, siden grafikken vår baserer seg på monospaced tekst (det går foreløpig ikke an å bruke mer enn én font i systemet).
* Hvis du prøver deg med andre fonter (som du selvfølgelig må oppgi kilde til og ha rettigheter til å bruke og finne ut hvordan du setter de opp med `Printer`), vil de gjerne ikke passe så veldig godt på skjermen. Det går an å justere størrelse og posisjon på bokstavene med `inf101.v18.gfx.textmode.TextFondAdjuster`.
#### Farger
Du kan lage farger med [ANSI escape-koder](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors). For eksempel `"\u001b[31m" + "@" + "\u001b[0m"` for å lage et rødt @-tegn. `"\u001b[31m"` velger rød tekstfarge og `"\u001b[0m"` skifter tilbake til standard (hvis du ikke har med den så blir all teksten rød).
#### Skilpaddegrafikk
Alternativet til tekstgrafikken er å bruke `ITurtle`/`TurtlePainter`, som du har sett litt i bruk på forelesningene for å lage frosker og ender. Gulroten er tegnet slik hvis du implementerer `draw()`-metoden for et item, og lar den returnere `true` blir teksten ikke tegnet. Du kan se på gulrot-eksempelet, og på [koden fra forelesningene](https://retting.ii.uib.no/inf101/inf101.v18/wikis/kode-fra-forelesninger) for eksempler.
* Les mer om [skilpaddegrafikk her](https://en.wikipedia.org/wiki/Turtle_graphics)
* Draw metoden får bredden og høyden til kartcellen som parametre. Som standard er ting laget til slik at bredde og høyde er 32 selv om skjermen viser smale tegn (16x32). Hvis du trenger kontroll over bredden, is stedet for at tegningen blir “skvist” til halv bredde, kan du sette `Main.MAP_AUTO_SCALE_ITEM_DRAW` til `false`.
* Foreløpig støtter grafikksystemet ikke at du kan bruke egne bilder (i jpg eller png filer, f.eks.) men det er mulig vi kan legge til dette etterhvert.
### C5: Meldingsvindu
* lage meldings"vindu"
### C6: Win condition
Det går foreløpig ikke an å vinne spillet her må du eventuelt være kreativ selv. F.eks. at spilleren vinner når alle gulrøttene er samlet i det ene hjørnet eller når spilleren er alene igjen eller noe helt annet.
### C?: Noe du finner på / noe annet vi finner på
* Du står fritt til å finne på ting selv; og det kan også være vi legger ut litt flere ideer underveis.
# Diverse
## Åpne kilder til grafikk / lyd / media
*Foreløpig støtter grafikksystemet ikke at du kan bruke egne bilder (i jpg eller png filer, f.eks.) men det er mulig vi kan legge til dette etterhvert. Du kan uansett tegne med skilpaddegrafikken (TurtlePainter). Det ligger heller ikke med kode for å spille av lyd men det kan være vi har noe slikt på lur til når du har kommet skikkelig i gang med ting.*
* Om du ikke er flink til å tegne selv, kan du finne glimrende grafikk på [OpenGameArt](http://opengameart.org/) **husk å skrive i oversiktsdokumentet hvor du har fått grafikken fra** (webside, opphavsperson, copyright-lisens om du bruker OpenGameArt, finner du opplysningene i *License(s)* og *Copyright/Attribution Notice*).
* [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) har en god del bilder og andre mediafiler tilgjengelig du får til og med en “You need to attribute this author show me how” instruks når du laster ned ting.
* [Kevin MacLeod](https://incompetech.com/music/) er komponist og har masse musikk tilgjengelig som egner seg for spill og småfilmer; du trenger bare å kreditere ham (han bruker vanlig [CC-BY-3.0](http://creativecommons.org/licenses/by/3.0/) lisens).
* Tidligere INF101-student [Øyvind Aandalen](https://soundcloud.com/user-616269685) har litt musikk han har laget på [SoundCloud](https://soundcloud.com/user-616269685) som han sier dere kan bruke som dere vil.
# Gå videre til [**Innlevering**](SEM-1.md#praktisk-informasjon)

View File

@ -1,10 +0,0 @@
Game -> IGame
GameMap -> IGameMap -> IMapView
IPlayer, INonPlayer -> IActor -> IItem -> Comparable<IItem>
GameEvent<T> -> Event<T>
Game -> Mapreader.readFile()
Game -> createItem()
Game - Rabbit.doTurn(Game) - Game.move()
Game.doTurn() - Game.beginTurn()

View File

@ -390,38 +390,4 @@ public class GameMap implements IGameMap {
}
return neighbours;
}
/**
* Goes in a direction, and saves all locations it passes to a list.
*
* @param locations Target list
* @param loc The location to start from
* @param dir Which direction to go
* @param max Maximum amount of steps
*/
private void addLoc(List<ILocation> locations, ILocation loc, GridDirection dir, int max) {
for (int j = 0; j < max; j++) {
locations.add(loc);
if (loc.canGo(dir)) {
loc = loc.go(dir);
} else {
return;
}
}
}
/**
* Goes a set amount of steps in a set direction, from a location, and returns the new location.
*
* @param loc Start location
* @param dir Direction to go
* @param max Maximum amount of steps
* @return The new location
*/
private ILocation goTo(ILocation loc, GridDirection dir, int max) {
for (int j = 0; j < max; j++) {
loc = loc.go(dir);
}
return loc;
}
}

View File

@ -63,7 +63,8 @@ public class MapReader {
*/
public static IGrid<String> readFile(String path) {
IGrid<String> symbolMap = null;
InputStream stream = MapReader.class.getResourceAsStream(path);
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream stream = classloader.getResourceAsStream(path);
if (stream == null)
return null;
try (Scanner in = new Scanner(stream, "UTF-8")) {

View File

@ -14,6 +14,8 @@ import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import java.util.List;
/**
@ -167,9 +169,14 @@ public class NPC {
* @param filename The String path of the audio file to play
*/
public static void playSound(String filename) {
Media sound = new Media(new File(filename).toURI().toString());
URL url = NPC.class.getClassLoader().getResource(filename);
if (url != null) {
Media sound = new Media(url.toString());
MediaPlayer mediaPlayer = new MediaPlayer(sound);
mediaPlayer.play();
} else {
System.out.println("Could not play audio file " + filename);
}
}
/**

Some files were not shown because too many files have changed in this diff Show More