CS_LEVEL_21_SOLUTION - OnlyCook/abitur-elite-code GitHub Wiki
public class SmartHomeServer
{
private int port;
private List<Licht> lichter;
private ServerSocket server;
public SmartHomeServer(int port)
{
this.port = port;
this.lichter = new List<Licht>();
this.lichter.Add(new Licht('A'));
this.lichter.Add(new Licht('B'));
this.lichter.Add(new Licht('C'));
this.server = new ServerSocket(port);
}
public void StartServer()
{
Socket clientSocket = server.Accept();
string befehl = "";
while (befehl != "QUIT")
{
befehl = clientSocket.ReadLine();
if (befehl.StartsWith("TOGGLE_LIGHT;"))
{
string idString = befehl.Substring(13);
char id = idString[0];
int asciiWert = (int)id;
if (asciiWert >= 65 && asciiWert <= 90)
{
Licht gefunden = null;
foreach (Licht l in lichter)
{
if (l.GetBezeichnung() == id)
{
gefunden = l;
break;
}
}
if (gefunden != null)
{
gefunden.Toggle();
clientSocket.Write("+OK\n");
}
else
{
clientSocket.Write("-ERR Licht nicht gefunden\n");
}
}
else
{
clientSocket.Write("-ERR ungültige ID\n");
}
}
}
clientSocket.Close();
}
}
public class Licht
{
private char bezeichnung;
private bool istAn;
public Licht(char bez)
{
this.bezeichnung = bez;
this.istAn = false;
}
public void Toggle()
{
istAn = !istAn;
}
public char GetBezeichnung()
{
return bezeichnung;
}
}public class Licht
{
private char bezeichnung;
private bool istAn;
public Licht(char bez)
{
this.bezeichnung = bez;
this.istAn = false;
}
// ...
}char ist ein Datentyp für ein einzelnes Zeichen – also genau ein Buchstabe, eine Zahl oder ein Symbol. 'A' (mit einfachen Anführungszeichen) ist ein char, "A" (mit doppelten) wäre ein string.
public void Toggle()
{
istAn = !istAn;
}! ist der logische Negationsoperator. Er kehrt einen bool-Wert um: !true ergibt false, und !false ergibt true. istAn = !istAn liest sich also als: „Setze istAn auf das Gegenteil seines aktuellen Werts." War die Lampe an, ist sie danach aus – und umgekehrt.
this.lichter = new List<Licht>();
this.lichter.Add(new Licht('A'));
this.lichter.Add(new Licht('B'));
this.lichter.Add(new Licht('C'));Die drei Lichter werden direkt im Konstruktor der Liste hinzugefügt. Das ist die klassische und lesbarste Variante.
Für Fortgeschrittene: In C# gibt es eine kürzere Schreibweise mit Objekt-Initialisierern:
this.lichter = new List<Licht>() { new Licht('A'), new Licht('B'), new Licht('C') };oder noch kompakter mit
new()und in einer Zeile:this.lichter = new() { new('A'), new('B'), new('C') };Da der Typ schon aus der Deklaration bekannt ist, kann der Compiler ihn selbst ableiten. Im Abitur ist die explizite Variante mit
Add()immer die sicherste Wahl.
string idString = befehl.Substring(13);
char id = idString[0];"TOGGLE_LIGHT;" hat genau 13 Zeichen. Substring(13) (dasselbe wie Substring(0, 13)) liefert alles danach, also z.B. aus "TOGGLE_LIGHT;A" entnimmt es "A". Mit [0] greift man auf das erste (und hier einzige) Zeichen zu und erhält einen char ('A').
int asciiWert = (int)id;
if (asciiWert >= 65 && asciiWert <= 90)Das ist das Kernkonzept dieses Levels: Ein char ist intern nichts anderes als eine kleine ganze Zahl – nämlich der ASCII-Wert des entsprechenden Zeichens. Jedes Zeichen hat eine eindeutige Nummer in der ASCII-Tabelle, z.B. 'A' = 65, 'B' = 66, ..., 'Z' = 90.
Mit dem Cast (int)id macht man diese Zahl explizit sichtbar (es wird zu einem int). Dann lässt sich bequem prüfen, ob der Wert im Bereich 65–90 liegt – also ob es ein Großbuchstabe ist.
Alternativ: Da
chardirekt mit Zeichen verglichen werden kann, funktioniert auchid >= 'A' && id <= 'Z'. C# vergleicht dabei intern genau die ASCII-Werte – das Ergebnis ist identisch. Im Abitur ist der explizite Weg über(int)und die numerischen Grenzen aus der ASCII-Tabelle jedoch der erwartete Weg.
Licht gefunden = null;
foreach (Licht l in lichter)
{
if (l.GetBezeichnung() == id)
{
gefunden = l;
break;
}
}
if (gefunden != null)
{
gefunden.Toggle();
clientSocket.Write("+OK\n");
}
else
{
clientSocket.Write("-ERR Licht nicht gefunden\n");
}Das Muster hier ist klassisch: Eine Variable gefunden wird mit null vorbelegt. Die foreach-Schleife iteriert über alle Lichter – wird ein passendes gefunden, wird es in gefunden gespeichert und die Schleife mit break sofort verlassen. Danach reicht eine einzige null-Prüfung, um zu entscheiden, ob die Suche erfolgreich war.
Dieses „Suche mit Ergebnisvariable"-Muster taucht im Abitur regelmäßig auf – es lohnt sich, es verinnerlicht zu haben.