Mastermind-Projektvorlagen:
Tag 1: Mastermind-Projektdatei zum Importieren in Eclipse.
Tag 4: Vollständige Referenz-Mastermind-Implementierung zum Importieren in Eclipse.
Aufgaben und Hinweise zur Implementierung von Mastermind:
Hinweis zur Ermittelung der Exakten (rot) und Korrekten (weiß)
Hinweis zum timergesteuerten Ändern des Hintergrundbildes
Singleplayer Modus
Strategien
Multiplayer Modus
Links zur Android-Entwicklungsumgebung:
Android SDK (Startseite)
Eclipse (Entwickler-GUI)
Eclipse ADT plugin
Einrichtung des ADT plugins für Eclipse
Links zum Thema Mastermind:
Wikipedia-Artikel "Mastermind"
Maturaarbeit über Mastermind (Kurzbesprechung der Lösungstrategien)
Links zur Java-Programmierung:
Buch: Java ist auch eine Insel
Buch: Thinking in Java (3rd Edition)
Oracle Java Tutorials
Java API Specifications
Android Developer Resources
Dokumente der Einführungsveranstaltung:
Mastermind: Spielregeln und Strategien
Eclipse und das Eclipse ADT Plugin
GUI-Programmierung mit dem Android SDK
CIP-Pool-Merkzettel
Informationen über die Verwendung der CIP-Pool-Rechner:
Im CIP-Pool: Erste Schritte mit Eclipse
Im CIP-Pool: Generelle Hinweise
Im CIP-Pool: Fehler "Re-installation failed due to different application signatures" beim Ausführen einer Anwendung auf dem Test-Handy
Hinweis zur Ermittelung der Exakten (rot) und Korrekten (weiß)
Input: int-Arrays a1 und a2
* Die Berechnung der Anzahl der Exakten ist relativ klar:
Zähle, wie oft a1[i] == a2[i]
* Zur Berechnung der Korrekten:
- Gehe Farbenweise vor.
- Für eine bestimmte Farbe c: Bestimme die Anzahl c1, mit der
c in a1 vorkommt, und die Anzahl c2, mit der c in a2 vorkommt.
- m = min(c1, c2) ist die Anzahl der Korrekten + Exakten für c.
- Summiere für alle Farben c die entsprechenden m auf.
- Subtrahiere davon die Anzahl der Exakten. Das Ergebnis ist
die Anzahl der Korrekten.
* Der entsprechende Java-Code sieht wie folgt aus:
public static int computeRed(int[] a1, int[] a2) {
if (a1.length != a2.length)
throw new ArrayStoreException("Arrays a1 and a2 must have the same size.");
int red = 0;
for (int i=0; i<a1.length; i++) {
if (a1[i] == a2[i])
red++;
}
return red;
}
public static int computeWhite(int[] a1, int[] a2, int[] colorValues) {
if (a1.length != a2.length)
throw new ArrayStoreException("Arrays a1 and a2 must have the same size.");
int whiteAndRed = 0;
for (int c=0; c<colorValues.length; c++) {
int counter1 = 0, counter2 = 0;
int currColor = colorValues[c];
for (int i=0; i<a1.length; i++) {
if (a1[i] == currColor)
counter1++;
if (a2[i] == currColor)
counter2++;
}
whiteAndRed += Math.min(counter1, counter2);
}
int white = whiteAndRed - computeRed(a1, a2);
return white;
}
Zurück nach oben
Hinweis zum timergesteuerten Ändern des Hintergrundbildes
// in header
import android.os.Handler;
// in MasterMind class
private Handler handler;
// in onCreate(Bundle)
handler = new Handler();
// where you want to start changing the background
Runnable runnable = new Runnable() {
public void run() {
for (int i = 0; i < colors.length; i++) {
final int value = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
public void run() {
findViewById(R.id.Board).setBackgroundColor(colors[value]);
}
});
}
}
};
new Thread(runnable).start();
Zurück nach oben
Singleplayer Modus
Aufgaben: Singleplayer Modus
0. Zur Terminologie:
Das Spielfeld besteht aus:
* ColorSelector: Hier wählt der Spieler die Farbe aus, die er einem Feld
im ColorSetter zuordnen will.
* ColorSetter: Hier wird die Farbkombination zusammengestellt, die den
nächsten Rateversuch (Guess) bestimmt.
* Board: Das Board ist der restliche Teil des Spielfeldes, in dem die
verschiedenen Rateversuche zusammen mit den Antworten (Answers)
dargestellt werden.
Jede Guess+Answer-Kombination wird in einer 'row' zusammengefasst.
* Für die Aufgabenbewältigung reicht es (in der Regel) nur die angegebene
Klasse zu betrachten!
1. Passe die Layoutdatei "res/layout/main.xml" an,
so dass es z.B. sechs Farben im ColorSelector, vier Eingabefelder im
ColorSetter und zehn Rows im Board gibt.
Passe die Layoutdatei "res/layout/row.xml" an: In jeder Row soll es vier
ImageViews für die Darstellung eines Rateversuchs geben.
Zudem soll in jeder Row die berechnete Antwort in einem 2x2 Feld dargestellt werden.
Dies lässt sich mit ein bisschen Kopieren & Einfügen & Editieren
lösen (am schnellsten in der XML-Datei).
2. Die folgenden Aufgaben sind in src/de.uni_passau.fim/MasterMind.java zu lösen.
Listener-Handling: Jedem klickbaren Feld im Layout wird ein Listener zugeordnet.
Wird ein Feld angeklickt, so wird der Listener aufgerufen,
dieser stößt dann seinerseits alle notwendigen Aktionen an.
Es gibt insgesamt 4 Listener: Jeweils einen für die beiden Buttons,
einen für den ColorSetter und einen für den ColorSelector (bereits implementiert).
a) Die Listener für die Buttons müssen in onCreate(Bundle) noch den
Buttons hinzugefügt werden. Die Aktionen, die durch klicken der Buttons
ausgeführt werden sollen, sind recht umfangreich und werden deshalb
in eigene Methoden ausgelagert (Aufgabe 3 bzw. Aufgabe 1 im Abschnitt
Strategie). Schau Dir z.B. an, wie der colorSelectorListener am Anfang
von onCreate(Bundle) zu einer RadioGroup hinzugefügt wird und imitiere
das Vorgehen für die beiden Buttons.
b) colorSetterListener: Wird ein Feld im ColorSetter gedrückt, so soll diesem
die gerade ausgewählte currentColor hinzugefügt werden.
Sonstiges:
* In dieser Aufgabe müssen nur wenige Zeilen Code hinzugefügt werden. Die
Ziel der Aufgabe ist es, das Zusammenspiel zwischen GUI und Code zu verstehen,
und die Klassen kennenzulernen, die für dieses Zusammenspiel verantwortlich sind.
* Um Debug-Messages auszugeben kann die Methode System.out.println(String) verwendet
werden. Die Ausgaben erscheinen dann in der LogCat-View (Window > Show View >
LogCat). Lege darin einen Filter an, der nur die Ausgaben der Application
"de.uni_passau.fim" anzeigt.
3. Als nächstes sollen die Aktionen implementiert werden, die beim Klick auf den
"Check"-Button ausgeführt werden sollen. Diese könnten direkt in die Methode
checkButtonListener.onClick(View) geschrieben werden, der Übersichtlichkeit
halber werden wir die Schritte jedoch in die Methode updateBoard(...) auslagern.
Um die updateBoard()-Methode ausfüllen zu können, muss man zuerst überlegen,
welche Aktionen bei einem Klick auf den "Check"-Button überhaupt durchzuführen sind:
a) Hole die aktuellen Farben aus dem 'ColorSetter' in ein int-Array.
b) Berechne eine Antwort durch Vergleich mit dem Array "quest". Es müssen zwei Werte
berechnet werden: Die Anzahl der korrekten Farben am korrekten Platz und
die Anzahl der verbleibenden korrekten Farben am falschen Platz. Diese beiden
Werte sind Grundlage der Antwort.
c) In der GUI muss auf dem Spielbrett nun die neue geratene Kombination und die Antwort
angezeigt werden. Hierzu ist es hilfreich sich zu merken, welche Zeile im
Board die aktuelle ist. Diesen Zähler erhöht man anschließend.
d) Überprüfe schließlich, ob der Spieler gewonnen oder verloren hat.
Ein Dialog informiert den Spieler gegebenenfalls (siehe Aufgabe 4b).
4. Abschließend ist noch ein bisschen Feinschliff nötig:
a) Der Check-Button soll nur klickbar sein, wenn alle Felder eine Farbe haben.
b) Die Dialoge am Ende des Spiels sollten sinnvolle Informationen anzeigen.
Danach kann der Spieler zwischen einer neuen Runde wählen oder das Spiel
verlassen.
c) Erweitere das Spiel beliebig. Z.B. könnte die gesuchte "quest" zum Schluss
angezeigt werden.
Zurück nach oben
Strategien
1. Implementiere die Strategie "Lineare Suche" in der Methode
computeAndSetHint().
- Wie kann das systematische Aufzählen aller Codes realisiert werden?
- Schreibe eine Methode, die überprüft, ob ein gegebener Code mit
allen bisher gespielten Codes+Antworten konsistent ist. Vorüberlegung:
Was bedeutet es, dass ein Code mit genau einem gegebenen Code-Antwort-Paar
konsistent ist?
Tipp: Schau Dich im Package *.strategies um, insbesondere die
Klasse Utils enthält ein paar nützliche Funktionen. Um diese zu nutzen
musst du allerdings die Klassen Guess, Answer und Configuration verwenden.
- Bewerte die Strategie. Wie verhält sie sich im schlechtesten Fall, wie
im Durchschnitt?
2. Implementiere eine evolutionäre Strategie.
- Die Klasse strategies.EvolutionaryStrategy enthält bereits ein grobes
Framework, so dass du dich voll auf die Mutations- und Fitness-
Funktionen konzentrieren kannst (die Selektion ist bereits vorgegeben).
Suche nach "TODO" und "NotYetImplementedException" um die fehlenden
Stücke zu identifizieren.
- Implementiere die Fitness-Funktion computeFitness(...).
Die Fitness muss vom typ int sein, je größer desto fitter. Am fittesten
sollen die Codes sein, die mit allen bislang gespielten Konfiguraionen
Konsistent sind.
- Implementiere die Mutations- und Crossover-Funktionen
onePointCrossover(...), twoPointCrossover(...), switchRandomColor(...) und
permuteRandomPositions(...). Du kannst Dir natürlich auch weitere
Mutationen überlegen.
- In makeNewGeneration(...) müssen nun die Mutationen und Kreuzungen noch
aufgerufen werden. Ob eine bestimmte Mutation stattfindet oder nicht,
kann von einer Mutationsrate abhängig sein. Somit kann man z.B. damit
experimentieren, welche Mutationen besonders effektiv sind.
- Bewerte die Strategie. Wie verhält sie sich im schlechtesten Fall, wie
im Durchschnitt?
3. Implementiere und bewerte weitere Strategien oder verfeinere die obigen.
Falls dein Mastermind verschiedene Farb- und Steckplatz-Variationen
realisiert:
Wie verhalten sich die Strategien für die verschiedenen Varianten bzgl.
Laufzeit und Speicher? Wie performant laufen die Strategien auf dem Handy?
Zurück nach oben
Multiplayer Modus
1. Button in der Klasse StartScreen reaktivieren.
2. In der Mulitplayer Klasse den Code hinzufügen,
der nötig ist um nach anderen Bluetooth Handys zu suchen
und diese zu verwalten.
3. In der Multiplayer Klasse muss der Message Handler so erweitert
werden, dass
- beim Client das Spielbrett im Multiplayer Modus angezeigt wird.
- im Server der Vorschlag des Clients verifiziert wird.
- im Client die Darstellung des Spielbretts mit korrekten/inkorrekten
Steinen aktualisiert wird.
4. Beliebige eigene Erweiterungen!
Zurück nach oben
Einrichtung des ADT plugins für Eclipse:
Installiere zuerst
Eclipse.
Dann muss das Android SDK sowie das ADT Eclipse-Plug-in installiert werden,
folge hierzu den Anweisungen auf der
SDK-Download Seite.
1) Root-Pfad zum Android SDK setzen:
Window -> Preferences -> Android -> SDK Location
2) Komponenten installieren (eventuell bereits bei der SDK Installation geschehen):
Window -> Android SDK Manager -> Available Packages
Folgende Komponenten werden benötigt:
* Tools (SDK Tools und SDK Platform-tools)
* Android 4.0, API 14 oder neuer
3) Standard Virtual Device einrichten:
Window -> AVD Manager -> New...
Folgende Einträge im "Create new Android Virtual Device"-Dialog:
Name: StdAVD
Target: Android 4.0 - API Level 14 (oder neuer)
SD Card: Size: 16 MiB
Hardware: -> New...
Property: SD Card support
(Die restlichen Voreinstellungen können übernommen werden.)
Weitere Informationen zum Installationsprozess sind auf den Seiten
http://developer.android.com/sdk/eclipse-adt.html
und
http://developer.android.com/training/basics/firstapp/index.html
zu finden.
Zurück nach oben
Im CIP-Pool: Erste Schritte mit Eclipse
1) Eclipse starten: Im Starmenü unten links nach "konsole" suchen und
das Programm "Konsole" starten. Im erscheinenden Shell-Fenster dann
"eclipse" eingeben.
Der Workspace kann belassen werden.
2) Root-Pfad zum Android SDK setzen:
* Möglichkeit 1: Ihr werdet nach dem ersten Start von Eclipse aufgefordert, den
Pfad zu setzen.
* Möglichkeit 2: Ihr setzt den Pfad später unter
Window -> Preferences -> Android -> SDK Location
Der Pfad lautet in jedem Fall "/usr/local/android-sdk-linux_x86".
3) Standard Virtual Device einrichten:
Window -> AVD Manager -> New...
Folgende Einträge im "Create new Android Virtual Device"-Dialog:
Name: StdAVD
Target: Android 4.0 - API Level 14
SD Card: Size: 16 MiB
Hardware: -> New...
Property: SD Card support
(Die restlichen Voreinstellungen können übernommen werden.)
Dann "Create AVD".
4) Projektdatei herunterladen: Mastermind-Projektdatei
5) Projekt in Eclipse importieren:
File -> (Import ->) Import... -> General -> Existing Projects into Workspace -> Next
Select archive file: -> Browse...
Im nächsten Dialog die heruntergeladene Projektdatei auswählen.
Im Feld unter "Projects:" ist nun das zu importierende Projekt bereits
ausgewählt. Jetzt nur noch den "Finish"-Button anklicken.
6) Im importierten Projekt unter "src > de.uni-passau.fim" die Datei "MasterMind.java" öffnen.
7) Den Emulator starten:
Run -> Run -> Android Application
Es kann etwas dauern, bis der Emulator bereit ist. (Beim allerersten Mal startet MasterMind evtl.
nicht sofort, da man irgendwelche Android-Informationen bestätigen muss.)
Läuft der Emulator einmal, so kann das Fenster offen bleiben. Nach Code-Änderungen einfach
die Datei speichern und über "Run -> Run" das Programm in den laufenden Emulator laden.
Zurück nach oben
Im CIP-Pool: Generelle Hinweise
Nach dem Einloggen erscheinen einige Dialogfenster mit Statusmeldungen.
Diese können ignoriert/geschlossen werden.
Zurück nach oben
Im CIP-Pool: Fehler "Re-installation failed due to different application signatures" beim Ausführen einer Anwendung auf dem Test-Handy
Auf dem Test-Handy existiert eine Anwendung mit gleichem Namen, aber
unterschiedlicher Signatur. Die gleichnamige Anwendung kann wie folgt vom
Test-Handy deinstalliert werden:
1) Eine Shell starten: Im Starmenü unten links nach "konsole" suchen und
das Programm "Konsole" starten.
2) In der Shell mit folgendem Befehl die Anwendung vom Test-Handy entfernen.
"XYZ" ist hierbei mit dem Namen aus der Fehlermeldung (z.B.
"de.uni_passau.fim.MasterMind") zu ersetzen:
/usr/local/android-sdk-linux_x86/platform-tools/adb uninstall "XYZ"
Zurück nach oben