====== Projekt: ConsoleGames ======
**DEADLINE: (siehe Details zur Abgabe weiter unten)**
* **3M: 05.01.2024, @23.59**
* **4M: 12.01.2024, @23.59**
**Ziele:**
* Zusammen eine **Sammlung** von **Singleplayer-Konsolengames** erstellen.
* Alle steuern (alleine oder in 2er-Gruppen) **ein Game** bei,
* ... wobei das **Framework** vorgegeben ist.
* Grundideen der **objektorientierten Programmierung (OOP)** verstehen.
* Wissen, welche Variablen/Funktionen/Methoden **private** und welche **public** sein sollen.
* Game zuerst sauber **modellieren**, erst dann ausprogrammieren.
* Paradigma von **Model vs. View** anwenden.
* Ansprechendes **GUI** u.a. mit Farbe in Konsole erstellen.
Bevor wir aber mit dem eigentlichen Game anfangen, bereiten wir uns mit einigen Aufträgen darauf vor.
===== Übersicht =====
Das Ziel ist, in der Klasse eine **Konsolen-Game-Sammlung** zu erstellen, wobei ihr alle entweder alleine oder in Zweiergruppen (Kriterien unten) ein **Game beisteuert**. Das Framework, in welches euer Game dann eingebunden wird, wird von den Lehrpersonen vorgegeben. In diesem Framework kann man dann u.A. das Game auswählen, Spielstände speichern und Highscores einsehen.
Das Game wird bewertet und es gibt eine mündliche Prüfung dazu. Beides zusammen gibt die zweite Note in diesem Semester.
===== Slides =====
{{ :ef_informatik:efif_console_games_uebersicht.pdf |Slides ConsoleGames 01 Übersicht}}
{{ :ef_informatik:efif_consolegames_modellieren.pdf |Slides ConsoleGames 02 Modellieren}}
{{ :ef_informatik:efif_consolegames_consoleart.pdf |Slides ConsoleGames 03 ConsoleArt}}
===== Framework =====
{{ :ef_informatik:consolegames2023v01.zip |}}
===== Aufträge =====
==== Auftrag 0 ====
* **Gruppen** bilden, Kriterien:
* Grundsätzlich wird das Projekt **alleine** absolviert.
* Ausnahmsweise können **Zweiergruppen** genehmigt werden, aber nur falls (a) beide Personen genügend waren bei der letzten Prüfung und (b) beide Personen auf einem ähnlichen Programmierstand (vergleichbare Note) sind.
* **Game überlegen**, mit LP besprechen und ...
* ... **absegnen lassen**
Die **Kriterien** an das Game sind:
* Spiel in Konsole.
* Ihr dürft ein bereits bekanntes Spiel implementieren. Ihr könnt aber auch ein eigenes erfinden oder ein bestehende abändern/erweitern. (-> Kriterium: Spielidee, Originalität)
* Es ist für sämtliche Gruppenmitglieder ein neues Spiel, ihr habt diese also nicht bereits im Vorfeld programmiert.
* Gibt nach erfolgreichem Spielen einen Score zurück: absolviertes Level und Anzahl Punkte (z.B. gesammelte Punkte, Spieldauer in Sekunden, Anzahl Versuche, ...)
* Es ist auch möglich (und sogar wünschenswert), verschiedene Levels zu haben. Das Ziel wäre dann, ein möglichst hohes Level mit einem möglichst guten Score zu erzielen.
* Das Game wird selbständig und komplett von euch programmiert.
* Der programmiererische Schwierigkeitsgrad eures Games entspricht in etwa euren Vorkenntnissen: Z.B. wird von den Talits mehr erwartet!
* Die Erwartungen an Zweiergruppen sind höher als an EinzelkämpferInnen.
* Gegen Ende des Semesters gibt es für alle Gruppen eine mündliche Prüfung. Dort müsst ihr demonstrieren, dass ihr euer Programm komplett versteht.
==== Auftrag I: HangMan im Framework ====
**Auftrag in Kürze:** HangMan in Framework integrieren und in ein Single-Player-Game umwandeln.
**Auftrag im Detail:**
1. Erstelle ein **GitHub-Repo** mit Namen `ConsoleGame` (wähle Gitignore "Visual Studio") und klone es auf Computer. Alle erstellen ihr eigenes Repo. Für das eigentliche Game-Project wird dann ein neues Repo erzeugt.\\ \\
1. Lade das Framework herunter und entzippe es. Füge den Inhalt dem Repo zu. Add, commit, push. Verschaffe dir nun einen groben **Überblick** über das Framework:
1. Programm ausführen und ausprobieren, spielen
1. Welche Files, Klassen, Methoden usw. gibt es?
1. Insbesondere Code von Spiel `GuessNumber` studieren.\\ \\
1. **Integriere** nun dein **HangMan-Spiel** in das Framework:
1. Erstelle eine neue Klasse (neues File) mit Namen "HangMan", in welche der Code des Spiels kommt:\\ Projektmappe / rechte Maustaste auf Ordner "Games" / Hinzufügen / neue Klasse
1. Grundsätzlich kommt der Inhalt der Main-Methode von der alten Version in die Play-Methode
1. Die zusätzlich benötigten Funktionen von Modell und View werden *parallel* zur Play-Methode eingefügt. Diese müssen mit dem **Zugangmodifizierer** `public` oder `private` versehen werden. Überlege dir, welcher für welche Funktion passend ist.
1. Public methods: Framework kann diese von aussen aufrufen, z.B. von `Program.cs` aus.
1. Private methods: Können nur von *innerhalb der Klasse* aufgerufen werden, z.B. in der Play-Methode der gleichen Klasse.
1. Die Play-Methode muss ein Score-Objekt zurückgeben. Für den Moment kannst du einfach ein leeres zurückgeben: `return new Score();`
1. Nun solltest du dein HangMan-Spiel innerhalb des Frameworks spielen können.\\ \\
1. **HangMan v2.0**: Das Problem ist noch, dass das HangMan in der jetzigen Fassung ein 2-Player Game ist. Wandle es nun in ein **Singleplayer-Game** um und gebe einen **sinnvollen Score** zurück:
1. Das gesuchte Wort soll aus einem Array von vorgegebenen Wörtern per Zufall ausgewählt werden. Man kann die vorgegebenen Arrays unten verwenden oder eigene erstellen.
1. Das Spiel soll mind. 3 Levels haben. Mit jedem höheren Level kommen schwierigere Wörter vor. Erzeuge ein passendes Score-Objekt und gib dieses am Ende der Play-Methode zurück. *Tipp:* Schaue in "GuessNumber" nach, wie das gemacht wird.
1. *Optional:* Speichere die Wörterlisten in einem File (z.B. CSV oder JSON) und lese dieses ein.
++++Arrays mit Wörtern|
string[] wordsSimple = new string[] { "Hund", "Katze", "Haus", "Auto", "Apfel", "Tisch", "Stuhl", "Buch", "Fenster", "Tür", "Wasser", "Baum", "Blume", "Sonne", "Mond", "Tag", "Nacht", "Ball", "Kind", "Schule"};
string[] wordsMedium = new string[] { "Bibliothek", "Abenteuer", "Geheimnis", "Symphonie", "Expedition", "Karriere", "Toleranz", "Illusion", "Revolution", "Koordination", "Vision", "Harmonie", "Konsequenz", "Inspiration", "Kreativität", "Perspektive", "Emotion", "Rhythmus", "Universum", "Innovation", "Mysterium" };
string[] wordsAdvanced = new string[] { "Paradox", "Ambivalenz", "Konnotation", "Konstellation", "Subjektiv", "Pragmatik", "Divergenz", "Osmose", "Symbiose", "Dissonanz", "Redundanz", "Hyperbel", "Polymorph", "Metamorphose", "Obsession", "Resonanz"};
++++
Q: Was ist der Unterschied von Funktion und Methode?
A: Eine Methode ist eine Funktion, die zu einer *Klasse* gehört.
==== Hauptauftrag: Eigenes Game programmieren ====
=== Vorgehen ===
1. Sicherstellen, dass Projekt von Lehrpersonen **abgesegnet** wurde
1. **Neues Repo** erstellen mit *passendem Namen*.
1. Repo den Lehrpersonen **freigeben**.
1. Aktuelle Version von Framework herunterladen, entpacken und in Repo kopieren.
1. Beginnen mit Arbeiten.
1. **Tipp:** Zuerst Planen, Modellieren & Skizzieren, erst dann Programmieren!
1. Regelmässige und unaufgeforderte **Commits & Pushes** von allen Gruppenmitgliedern, ca. 2x pro Woche
1. **Pünktliche Abgabe:** Sende Game-Klasse(n) (NICHT das gesamte VS Projekt) per Teams-Chat an sca.
1. **Verspätete Abgabe:** 1 Note pro angebrochene 24h Verspätung
=== Bewertung ===
Das Game einer Gruppe (1-2 Leute) wird mit einer Note bewertet. Alle Personen in der Gruppe erhalten im Normalfall die gleiche Note. Ausnahme: es ist klar ersichtlich, dass eine Person deutlich mehr beigetragen hat als die andere.
**Gibt es Probleme in der Gruppe, meldet dies rechtzeitig, damit wir eine Lösung finden können.**
^ Kriterium ^ Punkte ^
|**Spielidee, Originalität, Komplexität** | 10 |
|**Prozess, Vorgehensweise, Selbständigkeit (1)** | 10 |
|kontinuierliches Arbeiten und Fortschritt | ::: |
|regelmässige Commits (und Pushes) auf GitHub | ::: |
|mehrheitlich selbständig gearbeitet | ::: |
|**Arbeiten mit Framework** | 10 |
|Plug n' Play (einfaches Einbinden in Framework)| ::: |
|Gesamter Code in einem File| ::: |
|private vs. public| ::: |
|**Model vs. View** | 10 |
|Modellierung (Abstrahierung) | ::: |
|Aufteilung in Methoden & Klassen (letztere optional) | ::: |
|Strikte Trennung von Model- und View-Methoden/Klassen | ::: |
|**GUI / Darstellung** | 10 |
|anspruchsvolles GUI, Anwendung der Console-Befehle | ::: |
|**Programmieren**| 15 |
|Benennung von Variablen, Methoden usw.| ::: |
|sauber und effizient programmiert| ::: |
|Logik| ::: |
|Stabilität, Umgang mit falschen Eingaben | ::: |
|**Gamespezifischer Teil** | 15 |
|unterschiedlicher Fokus je nach Game| ::: |
|**Mündliche Prüfung (2)** | 20 |
|**Total** | **100** |
Aus den Punkten wird die Note linear berechnet (95% der Punkte: 6er, 0 Punkte: 1er).
* (1) Für allgemeine Fragen zu C#, dem Framework und OOP stehen die Lehrpersonen euch gerne zur Verfügung. Die konkrete Umsetzung des Games sollt ihr aber möglichst ohne Hilfe hinkriegen.
* (2) ** Disclaimer:** In der Prüfung müsst ihr uns überzeugen, dass ihr euer Game komplett selbständig programmiert habt. Zweifeln wir daran, führt dies zu zusätzlichem (massivem) Abzug. "ChatGPT hat mir das gesagt." ist keine Erklärung!
Änderungen für 2025 usw: Gute Kommentierung in Code sollten auch Punkte geben, zB 10 dafür, aber nur 10 für mündl. P oder so
===== Theorie =====
==== Kommentare zur Dokumentation ====
Dokumentiere die wichtigen Methoden, Felder und Eigenschaften *professionel*: Siehe [[https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/documentation-comments|offiziellen Guidelines für "Documentation Comments"]]
==== Console Befehle ====
// Clear console
Console.Clear();
// Hide cursor
Console.CursorVisible = false;
// Write line
Console.WriteLine();
// Write at specific position
Console.SetCursorPosition(20,10);
Console.Write();
// Read input
Console.ReadLine();
Console.ReadKey();
// Using color
Console.BackgroundColor = ConsoleColor.Yellow;
Console.ForegroundColor = ConsoleColor.Red; // font color
// Get terminal windows width and height
Console.WindowWidth;
Console.WindowHeight;
==== Delays & Sleep ====
Für mehr Infos, siehe Slides zu ConsoleArt
using System.Threading; // for sleep
using System.Diagnostics; // for stopwatch
// Let program sleep
Thread.Sleep(500);
// Stopwatch: Measures time since program start
Stopwatch stopwatch = Stopwatch.StartNew();
long time = stopwatch.ElapsedMilliseconds;
==== Key event listener ====
Auf User-Input warten, z.B. für Game-Steuerung:
while (true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey();
Console.WriteLine("key pressed: " + key.Key);
}
else
{
Console.WriteLine("no key pressed");
}
Thread.Sleep(200); // sleep for 200ms, requires using System.Threading;
}
==== Mehrdimensionale Arrays ====
// declare 2d-array and set array element values:
int[,] arr = { { 1, 4, 2 }, { 3, 6, 8 } };
// declare 2d-array without setting element values (int array -> default elements are 0):
int[,] arr2 = new int[3, 5];
// looks like this:
// | column 1 | column 2 | column 3 |
// row 1 | 1 | 4 | 2 |
// row 2 | 3 | 6 | 8 |
// Access element:
Console.WriteLine(arr[1, 2]); // Outputs 8
// Change element:
arr[0, 0] = 5; // Value 1 -> 5
// Get total number of elements in array
Console.WriteLine(arr.Length);
// Get dimension of array (nr columns and rows)
Console.WriteLine(arr.GetLength(0)); // -> 2 (y-direction)
Console.WriteLine(arr.GetLength(1)); // -> 3 (x-direction)
// IMPORTANT: order is different than in math: first y, then x
// Iterate over elements
Console.WriteLine();
for (int y = 0; y < arr.GetLength(0); y++)
{
for (int x = 0; x < arr.GetLength(1); x++)
{
Console.WriteLine(arr[y,x]);
}
}
==== OOP ====
private class Point
{
// Field
public int x;
public int y;
public string color;
// Constructor
public Point(int _x, int _y, string _color)
{
x = _x;
y = _y;
color = _color;
}
// Methode
public void SetToStart()
{
x = 0;
y = 0;
}
}
private class PointWithProperty
{
// Field
private int _x;
private int _y;
private string _color;
// Property
public int x
{
get { return _x; }
set
{
if (value > 0)
{
_x = value;
}
else
{
_x = 0;
}
}
}
// Constructor
public PointWithProperty(int _xx, int _yy, string _col)
{
_x = _xx;
_y = _yy;
_color = _col;
}
// Methode
public void SetToStart()
{
_x = 0;
_y = 0;
}
}
public override Score Play(int level)
{
Console.CursorVisible = false;
Point p = new Point(10, 7, "red"); // create new point object
Console.SetCursorPosition(p.x, p.y);
Console.Write(p.color);
Console.ReadKey();
p.SetToStart(); // call method
Console.SetCursorPosition(p.x, p.y);
Console.Write(p.color);
Console.ReadKey();
// Point is new data type, can thus create point array
Point[] points = new Point[]
{
new Point(1, 1, "black"),
new Point(7, 5, "yellow"),
new Point(2, 12, "green")
};
return new Score();
}
===== Kriterien =====
* Model View, Modellierung
* Documentation Comments
* Grafik
* Plug n Play
* Kann (fast) jederzeit aus Game ausbrechen, ohne Programm schliessen zu müssen (z.B. 'q' drücken)