Opgavebeskrivelse: Dice War
Introduktion
Velkommen til opgaven Dice War! Målet med denne opgave er at bygge et simpelt konsolbaseret spil, hvor du kommer til at arbejde med klasser, nedarvning, arrays og delegates i C#. I Dice War skal en spiller og en computer kæmpe mod hinanden ved at kaste terninger, men terningerne er ikke helt almindelige: nogle af dem har særlige regler for pointgivning.
Denne opgave vil bevise, at du kan arbejde med følgende koncepter:
- Arbejde i Visual Studio Code eller Visual Studio og med compiler og debugger.
- Grundlæggende procedural C#-syntaks.
- Arbejde med klasser.
- Egenskaber og metoder i klasser.
- Nedarvning til at udvide en klasses funktionalitet.
- Benytte grundlæggende polymorfi.
- Arrays for at oprette en samling af terninger.
- Benytte NuGet til at installere pakker.
Tilmelding
For at kunne aflevere opgaven skal du tilmelde dig indtil jul 2024 på https://forms.gle/N6vWUCRpnZurGX439. Det er en Google Form og svar opbevares i Google Sheets. Når du er tilmeldt vil du modtage en mail med en OneDrive-folder hvor du kan uploade din løsning (se senere).
Jeg vil kun bruge dit navn og din mailadresse til at sende feedback og bevis på at du har løst opgaven.
Spilbeskrivelse
Dice War foregår i et antal runder. I hver runde kaster spilleren og computeren hver især et “bæger” med terninger. Terningerne i bægeret er specielle “krigsterninger”, hvor ulige tal tæller dobbelt. Efter hver runde får spilleren og computeren point baseret på summen af deres kastede terninger. Den samlede score for hver spiller opdateres, og spillet fortsætter, indtil alle runder er færdige.
Tip
Hvis du finder nogle fejl i beskrivelsen eller noget er uklart, så skriv til mig på michell@cronberg.dk.
Her er et eksempel på, hvordan output kan se ud (5 runder og 5 terninger i bægrene):
--- Round 1 ---
Player rolled [5] [2] [3] [5] [1] a total of: 30
Computer rolled [5] [5] [2] [6] [6] a total of: 34
--- Round 2 ---
Player rolled [5] [1] [2] [6] [3] a total of: 26
Computer rolled [4] [3] [5] [5] [2] a total of: 32
--- Round 3 ---
Player rolled [6] [2] [6] [1] [4] a total of: 20
Computer rolled [4] [5] [5] [3] [6] a total of: 36
--- Round 4 ---
Player rolled [1] [1] [2] [4] [2] a total of: 12
Computer rolled [6] [6] [3] [2] [1] a total of: 22
--- Round 5 ---
Player rolled [4] [1] [1] [3] [5] a total of: 24
Computer rolled [3] [2] [3] [4] [1] a total of: 20
--- Game Over ---
Player total points: 112
Computer total points: 144
Der er således ingen interaktion med spilleren, og spillet kører automatisk. Spillet er en simpel simulation, hvor spilleren og computeren kaster terninger og får point baseret på terningernes værdi.
Opgaveoversigt
Hele spillet er implementeret i en konsolapplikation - der er således blot et projekt i løsningen. Kald projektet DiceWar
. Det skal være et .NET projekt men versionen er ikke kritisk (.NET 5 - .NET 9).
Du skal bygge fire klasser for at implementere spillet:
Dice
: En standard terning.WarDice
: En speciel terning der arver fraDice
, hvor ulige tal tæller dobbelt.WarDiceCup
: Et bæger med flere terninger, som kan rulles samtidig.Game
: Styrer spillets flow og holder styr på point.
samt logik i Program.cs til at starte spillet.
Trin-for-trin Opgave
Trin 0: Projektet
- Opret et nyt .NET-konsolapplikationsprojekt i Visual Studio Code eller Visual Studio.
- Kald projektet
DiceWar
. - Tilføj NuGet-pakken
PcgRandom
til projektet for at kunne skabe “bedre” tilfældige tal.- Med “bedre” bevæger man sig ind i et nærmest religiøst område, hvor nogle mener, at de indbyggede tilfældige tal i .NET ikke er tilstrækkeligt tilfældige. Pakken
PcgRandom
er blot valgt for at bevise, at du kender til NuGet og kan installere en pakke.
- Med “bedre” bevæger man sig ind i et nærmest religiøst område, hvor nogle mener, at de indbyggede tilfældige tal i .NET ikke er tilstrækkeligt tilfældige. Pakken
- Sørg for at projektet kan kompileres og køres med det normale “Hello World” output.
Trin 1: Dice-klassen
- Opret en klasse
Dice
i namespacetDiceWar
. Dice
skal have enValue
-egenskab, som repræsenterer værdien af terningen.- Husk at en egenskab (property) er en måde at indkapsle et felt. En automatisk egenskab med en privat
setter
er fin til dette formål - men det er op til dig.
- Husk at en egenskab (property) er en måde at indkapsle et felt. En automatisk egenskab med en privat
- Implementer en
Roll()
-metode, som sætterValue
til et tilfældigt tal mellem 1 og 6.- Husk at bruge pakken
PcgRandom
til at generere tilfældige tal (den fungerer somSystem.Random
). Se deres dokumentation for at finde ud af, hvordan du bruger den.
- Husk at bruge pakken
- Tilføj en
Point()
-metode, som returnerer værdien afValue
.- Dette er jo blot en almindelig terning, så pointene er lig med værdien af terningen.
- Tilføj
ToString()
for at vise værdien i en læsbar form, fx"[5]"
.- Det kan du gøre ved at overskrive
ToString()
-metoden i klassen (override
). Se eventuelt i materialet - søg efter “Børn har sin egen implementation”
- Det kan du gøre ved at overskrive
classDiagram
class Dice {
-int Value
+void Roll()
+int Point()
+string ToString()
}
Trin 2: WarDice-klassen
- Opret en klasse
WarDice
, der nedarver fraDice
. - Overskriv
Point()
-metoden, så ulige tal tæller dobbelt, dvs. hvisValue
er ulige, returneresValue * 2
, ellers returneresValue
.- Det er denne metode som er forskellig fra
Dice
-klassen.
- Det er denne metode som er forskellig fra
classDiagram
class Dice {
-int Value
+void Roll()
+int Point()
+string ToString()
}
class WarDice {
+int Point()
}
Dice <|-- WarDice : inheritance
Trin 3: WarDiceCup-klassen
- Opret en
WarDiceCup
-klasse - Implementer en konstruktør, som modtager antallet af terninger.
- Tilføj et array af
WarDice
-objekter svarende til antallet af terninger. - Tilføj en
RollAll()
-metode, som ruller alle terninger i bægeret.- Den løber alle terningerne igennem og kalder
Roll()
på hver terning.
- Den løber alle terningerne igennem og kalder
- Implementer
Point()
, som summerer pointene fra alle terningerne i bægeret.- Her kan du blot løbe igennem alle terningerne og kalde
Point()
på hver terning.
- Her kan du blot løbe igennem alle terningerne og kalde
- Tilføj
ToString()
(override
) for at returnere værdierne af alle terninger i bægeret som en enkelt streng, fx"[3] [5] [2] [6]"
.
classDiagram
class DiceCup {
-Dice[] _diceArray
+DiceCup(int numberOfDices)
+void RollAll()
+int Point()
+string ToString()
}
Trin 4: Game-klassen
- Opret en
Game
-klasse, som styrer spillet. Game
skal have toWarDiceCup
-objekter – ét til spilleren og ét til computeren (se klassediagrammet).- Der skal også være to private felter til at holde styr på pointene for spilleren og computeren (se klassediagrammet).
- Implementer en
PlayRound()
-metode, som:- Ruller begge bægre.
- Beregner og tilføjer point til spilleren og computeren.
- Logger resultaterne for begge.
- Implementer
StartGame(int numberOfDices, int rounds)
, som kører flere runder med et antal terninger og udskriver slutresultatet.
classDiagram
class Game {
-DiceCup _playerCup
-DiceCup _computerCup
-int _playerPoint
-int _computerPoint
-int _rounds
+Game(int numberOfDices, int rounds)
+void PlayRound()
+void StartGame()
}
Info
Din løsning på denne opgave vil have flere “issues” i det virkelige liv - det er ikke super smart at være hårdt bundet til både en NuGet-pakke (hvad nu hvis “kunden” vil bruge noget andet) og Console.WriteLine (hvad nu hvis “kunde” vil kunne udskrive til en fil eller database eller …). Hvis du har lyst til at gøre noget ved det, så prøv at se på afkobling ved hjælp af eksempelvis interfaces og dependency injection eller delegates. Men det er ikke et krav for at løse opgaven.
Aflevering og bedømmelse
Aflevering af opgaven sker ved at uploade en ZIP-fil med hele projektet til en OneDrive-folder. Oplysningerne om denne folder vil blive givet når du tilmelder dig “eksamen”. Jeg vil ikke have /bin
eller /obj
mapperne med i zip-filen - kun de filer som er nødvendige for at kunne bygge og køre projektet (DiceWar.csproj
, alle .cs
filerne samt evt en sln-fil
(solution)). Du må gerne inkludere en readme.txt hvor dit navn og mailadresse fremgår.
Det jeg gør for at tjekke om det virker er at jeg pakker det ud på min egen computer og prøver at bygge og køre det (dotnet run
). Jeg vil også kigge på koden for at se om de forskellige klasser og metoder er implementeret som beskrevet i opgaven. Hvis alt er godt vil du bestå, ellers vil du få en mail med feedback om hvad der skal rettes.
Når opgaven er godkendt vil du modtage et bevis på at du har løst opgaven tilfredsstillende. Beviset vil indeholde en kort beskrivelse af opgaven.