CS_LEVEL_DESIGNER_GUIDE - OnlyCook/abitur-elite-code GitHub Wiki
Willkommen im Level Designer von Abitur Elite Code. Dieses Werkzeug ermöglicht es dir, eigene Programmieraufgaben im Stil der hessischen Abiturprüfung (Praktische Informatik) zu erstellen, zu testen und mit anderen zu teilen.
- Dateisystem & Speicherort
- Die Benutzeroberfläche
- Code Editoren
- Leitfaden für Abitur-konforme Levels
- Schritt-für-Schritt: Dein erstes Level
Bevor wir beginnen, ist es wichtig, den Unterschied zwischen den zwei Dateitypen zu verstehen:
- .elitelvldraft: Dies sind Entwürfe. Sie können jederzeit im Designer bearbeitet werden, sind aber nicht "spielbar" (man kann sie nicht im normalen Menü auswählen, um sie zu lösen).
- .elitelvl: Dies sind exportierte Levels. Sie sind schreibgeschützt und können von Nutzern gespielt werden. Ein Export ist nur möglich, wenn der Entwurf den internen Selbsttest im Designer besteht.
Speicherort:
Alle Levels befinden sich im Ordner levels im Verzeichnis der Anwendung.
Um ein Level zu teilen, sende einfach die .elitelvl-Datei an eine andere Person. Diese muss die Datei dann in ihren levels-Ordner legen.
- Level Name: Der Titel des Levels, der in der Auswahl und im Header angezeigt wird.
- Autor: Dein Name oder Pseudonym.
Hier beschreibst du die Aufgabenstellung. Du kannst spezielle Formatierungen verwenden, um den Text übersichtlicher zu gestalten:
-
Fetter Text: Umschließe Text mit zwei Sternchen.
- Code:
**Wichtig** - Ergebnis: Wichtig
- Code:
-
Highlight (Blau): Umschließe Begriffe mit eckigen Klammern. Ideal für Klassennamen oder Methoden.
- Code:
Implementiere die Klasse [Tier]. - Ergebnis: Implementiere die Klasse
Tier(wird in der App blau dargestellt).
- Code:
-
Code-Block: Umschließe Code mit
{|und|}.- Code:
{|public void Run()|} - Ergebnis:
- Code:
public void Run()Hier kommen Hinweise, Tipps oder weiterführende Erklärungen hin. Auch hier funktioniert die Formatierung wie bei der Aufgabe. Zusätzlich gibt es das Hinweis-System:
Du kannst einklappbare Hinweise erstellen, um Lösungen nicht sofort zu verraten.
Syntax:
start-hint: Titel des Hinweises
Hier steht der Text, der erst nach dem Ausklappen sichtbar ist.
Du kannst auch [Code] verwenden.
:end-hint
Für Tipps verwende start-tipp statt start-hint:
start-tipp: Ein kleiner Tipp
Verwende eine for-Schleife.
:end-tipp
Jedes Level benötigt in der Regel ein Klassendiagramm. Abitur Elite Code nutzt PlantUML zur Generierung.
- Der Designer fügt automatisch ein Theme hinzu (
skinparam backgroundcolor transparentetc.). Du musst dich nicht um das Styling kümmern. - Du kannst mehrere Reiter für Diagramme anlegen (z.B. Hauptdiagramm und Hilfsdiagramme für Materialien).
- Klicke auf den "Vorschau generieren"-Button (das Zauberstab-Icon), um das Diagramm zu aktualisieren.
Dokumentation zu PlantUML:
Offizielle PlantUML Referenz
Offizielle PlantUML Klassendiagramme Referenz
Du kannst bis zu 8 Voraussetzungen definieren. Diese werden dem Nutzer angezeigt und verlinken auf passende Lernressourcen (Dometrain Kurse und Microsoft Docs).
Liste aller verfügbaren Voraussetzungen (Klicken zum Ausklappen)
Die Liste orientiert sich am Curriculum des kostenlosen Kurses "Hands-on C# for Beginners" auf Dometrain.
Hello World & Basics
- Console printing
- Console.Write
- Console.ReadLine
- Single line comments
- Multi line comments
- Variables
- Constants
- The var keyword
Primitive Types
- Integers
- Doubles
- Decimals
- Strings
- Escape Sequences
- Verbatim Strings
- String concatenation
- String interpolation
- Chars
- Booleans
- Floats
Operators
- Addition
- Subtraction
- Multiplication
- Division
- The Modulo operator
- Order of operations
- Compound assignment operators
- Increment and Decrement
- Comparison operators
- Logical AND
- Logical OR
- Logical NOT
Control Flow
- If statements
- If-Else statements
- Else-If chains
- Logical patterns
- Switch statements
- Switch expressions
- The Ternary operator
Loops
- While Loops
- Avoiding Infinite Loops
- Do-While Loops
- For Loops
- For Loop Counting Down
- For-Each Loops
- The break statement
- The continue statement
- Nested Loops
Methods
- Defining void methods
- Method parameters
- Return values
- Using return values
- Method overloading
- Optional parameters
- Named arguments
- Params arguments
- ref Parameters
- out Parameters
- in Parameters
Arrays
- Creating Arrays
- Array Initializer Syntax
- Modifying Array Elements
- Looping Arrays with for
- Looping Arrays with foreach
- Multi-Dimensional Arrays
- Jagged Arrays
- Ranges and Indices
Collections (Lists & Dictionaries)
- Creating Lists
- Adding to Lists
- Accessing List Elements
- Removing from Lists
- Checking List Contents
- Sorting Lists
- Creating Dictionaries
- Adding and Accessing Dictionary Items
- Checking Dictionary Keys
- Looping Through Dictionaries
OOP: Classes & Objects
- Defining a Class
- Fields
- Default Constructors
- Parameterized Constructors
- Constructor Overloading
- Properties
- Auto-Properties
- Read-Only Properties
- Private Set Properties
- The this Keyword
- Public Access Modifier
- Private Access Modifier
OOP: Advanced
- The static keyword
- Static Fields
- Static Methods
- Inheritance Basics
- The base Keyword
- Virtual Methods
- Method Overriding
- Abstract Classes
- Abstract Methods
- Defining Interfaces
- Implementing Interfaces
- Multiple Interfaces
- Default interface methods
Structs, Records, Enums
- Defining Structs
- Value Type Behavior
- Defining Enums
- Enum Values
- Enums in Switch
- Defining Records
- Record With Expressions
Exception Handling
- Try-Catch Blocks
- Exception Messages
- Multiple Catch Blocks
- The Finally Block
- Throwing Exceptions
- Custom Exception Messages
Generics
- Generic Classes
- Using Generic Classes
- Generic Methods
- Generic Constraints
Delegates, Lambdas, Events
- Defining Delegates
- Using Delegates
- Action Delegates
- Func Delegates
- Lambda Expression Basics
- Lambda with Multiple Statements
- Events
- Subscribing to Events
LINQ
- Introduction to LINQ
- LINQ Query Syntax
- Where for Filtering
- Select for Transforming
- OrderBy for Sorting
- ThenBy for Secondary Sorting
- Count and Sum
- Average, Min, and Max
- First and FirstOrDefault
- Single and SingleOrDefault
- Any and All
Async Programming
- Async and Await
- Returning Values from Async
- Task.WhenAll
- Task.WhenAny
Strings & DateTime
- ToUpper and ToLower
- Trim
- Substring
- Replace
- Split
- Join
- Contains and IndexOf
- StartsWith and EndsWith
- String Comparisons
- Format Specifiers
- Interpolation Format
- StringBuilder
- DateTime Basics
- Creating DateTime Values
- Formatting Dates
- Parsing Dates
- Date Arithmetic
- TimeSpan Basics
- Comparing Dates
- DateOnly Basics
- TimeOnly Basics
Advanced / Modern C#
- Nullable Value Types
- The Null-Coalescing Operator
- Nullable Reference Types
- The Null-Conditional Operator
- The Null-Forgiving Operator
- Type Checking with is
- Type Patterns with Variables
- Switch with Type Patterns
- Property Patterns
- Relational Patterns
- When Guards
- Creating Tuples
- Named Tuple Elements
- Returning Tuples from Methods
- Tuple Deconstruction
- Anonymous Types
- Extension Methods
- Understanding Attributes
- Creating Custom Attributes
- The using Statement
- Init-Only Properties
- Required Properties
- Raw String Literals
- Collection Expression Syntax
- Spread Operator in Collections
- Primary Constructors
Conversion & I/O
- Implicit Conversion
- Explicit Conversion (Casting)
- The Convert Class
- Parse Methods
- TryParse Methods
- Checked Arithmetic
- Unchecked Arithmetic
- Writing Text Files
- Reading Text Files
- File Lines
- Checking File Existence
- Path Manipulation
- JSON Serialization
- JSON Deserialization
HTTP Requests
- Introduction to HttpClient
- Making GET Requests
- HttpResponseMessage
- Checking Status Codes
- Using BaseAddress
- Making POST Requests
- Sending JSON with POST
- Deserializing JSON Responses
- Setting Request Headers
- Handling HTTP Errors
- PUT and DELETE Requests
- Async HTTP Operations
C# 13 & 14 Preview
- Params Collections
- The Lock Type
- Partial Properties
- The field Keyword
Der Designer verfügt über drei Code-Fenster. Um diese zu bearbeiten, klicke auf das Pfeil-Icon neben der jeweiligen Überschrift.
Dies ist der Code, den der Spieler zu Beginn des Levels sieht.
- Er sollte das Grundgerüst enthalten (Klassenrümpfe, Methodensignaturen).
- Vermeide es, Lösungen hier schon vorzugeben.
Dieser Code wird niemals exportiert. Er ist nur für dich während der Entwicklung im Designer sichtbar.
- Nutze dieses Feld, um deine Validierungslogik zu testen.
- Schreibe hier eine korrekte Lösung für deine Aufgabe rein.
- Wenn du im Designer auf "Ausführen" klickst, wird dieser Code gegen deine Validierung geprüft.
Dies ist das Herzstück deines Levels. Hier schreibst du C#-Code, der den Code des Spielers analysiert und bewertet.
Die Validierung basiert auf Reflection. Du erhältst das kompilierte Assembly des Spielers und musst prüfen, ob Klassen, Methoden und Rückgabewerte korrekt sind.
Signatur:
private static bool ValidateLevel(Assembly assembly, out string feedback)
{
// Deine Logik
}Rückgabewerte:
-
true: Das Level gilt als bestanden. -
false: Das Level ist nicht bestanden. Das Programm wirft dann meistens eine Exception mit Details. -
feedback: Eine Nachricht, die dem Nutzer bei Erfolg angezeigt wird.
Wichtiges Konzept:
Da der Code des Spielers erst zur Laufzeit existiert, kannst du nicht einfach new Tier() schreiben (das würde einen Compiler-Fehler geben, da dein Validator die Klasse Tier nicht kennt). Du musst assembly.GetType("Tier") verwenden.
Um Levels zu erstellen, die dem Stil des hessischen Abiturs (Praktische Informatik) entsprechen, beachte bitte folgende Regeln:
-
Java-Notation in Diagrammen: Das Abitur verwendet in Diagrammen Java-Syntax (z.B.
Stringstattstring,booleanstattbool,list.addstattlist.Add). Deine Aufgabe ist es oft, diese Unterschiede in den "Hinweisen" zu erklären, aber im Diagramm beim Java-Stil zu bleiben. -
Namenskonventionen:
- Java-Diagramm:
getGewicht() - Erwarteter C#-Code:
GetGewicht()(PascalCase für Methoden).
- Java-Diagramm:
-
Progression:
- Levels sollten ein Thema schrittweise einführen.
- Verwende am Anfang viel "Händchenhalten" (genaue Anweisungen, viele Hinweise).
- Gegen Ende einer Sektion (Mini-Exam) sollten weniger Hilfen gegeben werden.
-
Datenkapselung: Getter und Setter werden im Abitur meist explizit gefordert (
getVariable()), statt C#-Properties ({ get; set; }) zu nutzen. -
Listen: Wenn
List<T>verwendet wird, muss dies oft als Assoziation im Diagramm dargestellt werden (mit Sternchen*für "viele").
Hier erstellen wir gemeinsam ein einfaches Level: "Der Taschenrechner".
Folge diesen Schritten und kopiere den Code exakt in die entsprechenden Felder im Designer, um ein funktionierendes, exportierbares Level zu erhalten.
Klicke im Level-Auswählen-Menü "Eigene Levels" auf + und gib folgende Daten ein:
- Name: Der einfache Rechner
- Autor: (Dein Name)
Gehe in den Level Designer des neu erzeugte Level-Entwurfs "Der einfache Rechner (Entwurf)" mit ✎.
Kopiere dann folgenden Text in das Feld Aufgabe:
Erstelle eine Klasse [Rechner], die grundlegende mathematische Operationen durchführen kann.
Implementiere die Methode [Addiere(int a, int b)], die die Summe der beiden Zahlen zurückgibt.
Kopiere diesen Text in das Feld Materialien:
start-hint: Wie addiert man?
Nutze den [+] Operator.
Beispiel: {|return a + b;|}
:end-hint
Füge diesen Code in das Feld Haupt bei "UML/Diagramme (PlantUML)" ein und klicke auf den Vorschau-Button (das kleine Zauberstab-Icon über dem Textfeld):
@startuml
class Rechner {
+ addiere(a : int, b : int) : int
}
@endumlKlicke auf den Pfeil bei Starter Code (dies öffnet den Editor). Füge dort diesen Code ein, damit der Spieler nicht bei Null anfangen muss:
public class Rechner
{
// Hier Code implementieren
}Klicke auf den Pfeil bei Musterlösung / Test-Code. Füge hier die korrekte Lösung ein. Dieser Code wird gleich verwendet, um zu testen, ob deine Validierung funktioniert:
public class Rechner
{
public int Addiere(int a, int b)
{
return a + b;
}
}Das ist der wichtigste Teil. Klicke auf den Pfeil bei Validierungs-Code. Hier schreiben wir das Programm, das die Lösung des Spielers prüft.
Kopiere diesen kompletten Block:
private static bool ValidateLevel(Assembly assembly, out string feedback)
{
// 1. Suche nach der Klasse "Rechner"
Type t = assembly.GetType("Rechner");
if (t == null)
{
throw new Exception("Die Klasse 'Rechner' wurde nicht gefunden. Hast du den Namen korrekt geschrieben?");
}
// 2. Erstelle eine Instanz der Klasse (ruft den Konstruktor auf)
object instance = Activator.CreateInstance(t);
// 3. Suche nach der Methode "Addiere"
MethodInfo m = t.GetMethod("Addiere");
if (m == null)
{
throw new Exception("Die Methode 'Addiere' fehlt in der Klasse Rechner.");
}
// 4. Teste die Methode mit Werten (5 + 5)
// Invoke ruft die Methode auf der Instanz auf. Das Array sind die Parameter (a, b).
object resultObj = m.Invoke(instance, new object[] { 5, 5 });
// Prüfe das Ergebnis
if (resultObj is int result)
{
if (result == 10)
{
feedback = "Super! 5 + 5 ist korrekt 10.";
return true; // Test bestanden
}
else
{
throw new Exception($"Falsches Ergebnis. Erwartet: 10, Erhalten: {result}");
}
}
throw new Exception("Die Methode gibt kein 'int' zurück.");
}- Gehe sicher, dass du im Musterlösung / Test-Code Fenster (Schritt 6) bist oder es zumindest befüllt hast.
- Klicke auf den großen grünen
▶ AUSFÜHRENButton oben rechts. - Die Konsole sollte jetzt grün anzeigen:
✓ DESIGNER TEST BESTANDEN. - Der Button Exportieren (grün, oben links im Designer-Tab) ist jetzt aktiv. Klicke darauf.
- Fertig! Du hast eine
.elitelvlDatei imlevels-Ordner erstellt, die du jetzt verschicken kannst.
Falls du die fertigen Beispiel-Dateien direkt verwenden möchtest:
- Der einfache Rechner.elitelvl - Die exportierte, spielbare Version
- Der einfache Rechner.elitelvldraft - Die Entwurfs-Datei zum Bearbeiten im Designer
Lege die heruntergeladenen Dateien einfach in deinen levels-Ordner (neben der .exe, wenn keiner existiert erstelle diesen selbst).