Pseudocode und Implementationsansätze
Entwicklungsrichtlinien
alle Bezeichnungen und Kommentare auf englisch
Variablen in Kleinbuchstaben und möglichst keine Unterstriche
Klassenbezeichnungen beginnen mit einem Grossbuchstaben, anschließend Kleinbuchstaben
Konstanten nur Grossbuchstaben
Alle Klassen haben einen Konstruktor, Destruktor, operator=(const Klasse&),
Man kann alle Variablen mittels Funktionen abrufen (meistens Konstanter Rückgabewert)
Soweit es geht, Funktionen konstant deklarieren
Zu jeder Klasse 'operator<<(ostream&, const Klasse&)' definieren
jede Funktion hat ein 'return' (auch die 'void'-Funktionen)
jedes 'switch' ein 'default:'
jedes 'case' mit einem return hat nach dem return ein break.
Zu Variablen und Funktionen immer schreiben, was sie machen plus was zurückgegeben wird
Funktionsheader:
/**********************************************************************
*
*
*
* Parameters: Parameter erläutern
*
* Result: Rückgabewert erläutern, insbesondere Fehlercodes
*
* Version: Dummy/Prototype/PreAlpha/Alpha/Beta/Release
*
* Description:
* Kurzbeschreibung der Funktion, alles was neben den Kommentaren
* in der Funktion nützlich wäre
* um den Code zu verstehen und was man wissen sollte, wenn man den
* Code ueberhaupt nicht betrachtet.
*
**********************************************************************/
Bei großen Blöcken und Funktionen am Ende schreiben, was die geschweifte Klammer schließt
Keine Referenzen für Basistypen (int, float, bool,...). Es sei denn es werden mehrere Rückgabewerte benötigt.
Nur Referenzen für Klassen einer gewissen Größe verwenden (mehr als vier Integer-Variablen)
Wenn möglich, Variablen als konstante Referenz an Funktionen übergeben (Geschwindigkeit wegen Referenz, Sicherheit wegen Konstantheit), sofern sie nicht zu obigen beiden Typen gehören
Klassen
Team
Repräsentiert das Team eines Spielers: Re, Contra, unbekannt
Announcement
Repräsentiert die möglichen Ansagen eines Spielers: Re Contra, keine 90, keine 60, keine 30, Schwarz, keine Ansage
GameType
Repräsentiert den Typ des aktuellen Spiels: Normales, Solo (mit Art), Hochzeit, Armut
Rule
Repräsentiert alle unterstützten Spielregeln
GameValues
Repräsentiert Werte die für das gesamte Spiel gültig sind:
Anzahl der Spieler
Anzahl der Karten pro Farbe
Language
Repräsentiert alle benötigten Texte für Ausgaben des Programmes
Kartenfarben
Kartenwerte
Bezeichnungen für: Spieler, Auch, Re, Contra, Keine 90, Keine 60, Keine 30, Schwarz, Hand, Karte, Bitte, wählen, nicht vorhanden, nicht, erlaubt, Stich, Punkte, von, und, war, Gewinner, ist, letztes, Spiel, Punkte, für, Unbekanntes, Team, kein, normal, Solo, Bilder, ohne, Trumpf, Armut, Hochzeit, Spieltyp, Spielstand, zu, spielen, Stiche, Spieler(pl.), Partie
CardValue
Repräsentiert die Werte einer Karte: Neun, Bube, Dame, König, Zehn, As
CardColor
Repräsentiert die Farbe einer Karte: Karo, Herz, Pik, Kreuz
Card
Besteht aus 1 CardValue, 1 CardColor
Repräsentiert eine einzelne Karte
Wert
Farbe (Trumpf ja/nein Farbe)
ob Trumpf
Punkte
Trick
Besteht aus 4 Karten, 1 Ausspieler
Repräsentiert einem Stich
Karte hinzufügen
Gewinner ermitteln (automatisch, nach der vierten Karte)
Punkte
Player
Besteht aus 1 Name, 1 Hand, 1 Ansage, 1 Team
Repräsentiert einen Spieler (Mensch oder Maschine), bestehend aus einem Namen, einem (Karten-)Blatt und einer Ansage
Spielt Karten aus
Kann (nach oder direkt vor jeder ausgespielten Karte entsprechend den Regeln) Ansagen machen
Ai
abgeleitet von 'Player'
repräsentier einen künstlichen Spieler
Human
abgeleitet von 'Player'
repräsentier einen menschlichen Spieler
Game
Besteht 12(10) Stichen, 1 Anzahl von Stichen, 4 Spielern
Repräsentiert ein Spiel, bestehend aus 12(10) Stichen (Verwaltung) und vier Spielern
GamePoints
Besteht aus 1 Spielart, 1 Spielpunkte, 1 Gewinner (RE/CONTRA), 4 Re,4 Spielerpunkten
Repräsentiert eine Wertung (Zeile in der Punktetabelle, bestehend aus der Spielart (Solo, ...), der im Spiel erreichten Punkte, der Gewinnerpartei, wer Re/Contra war und der jeweils erzielten Punkte
GamePointsTable
Besteht aus x Wertungen, x Rundensummen, 4 Namen, 1 Spielart, 1 Punktetopf
Zusammenfassung von GamePoints mit Rundensummen (automatisch), den Spielernamen (Verweis), der Spielart und ggf. einen Punktetopf
Party
Besteht aus 1 Regel, 1 Spieltabelle, 1 Phase (normal, Pflichtsoli), 1 Spielart, Punkte im Topf, Endbedingung, 1 (laufendes) Spiel, 1 Anzahl der gespielten Spiele
Die Grafik
Aufsicht auf Tisch mit den vier Spielern
Karten auf dem Tisch vor den Spielern, vorm aktivem Spieler offen
Stichstapel für jeden Spieler (Größe abhängig von den eingesammelten Stichen)
Punkteblock (vergrösserbar) (mit ggf. Spalte zum Festhalten der Pflichsoli)
Aufgedeckte Karten im Stichstapel für Sonderpunkte
Animationen
(Karten abheben)
Karten austeilen (4*3 Karten)
bedienen
Stich einsammeln
Punkte zählen
Sonderpunkte aufdecken
Kartenart wählen (auf jeden Fall die Rückseite)
Mischen der Karten
Code der PreAlphaversion:
for (i = 12 * Number_of_Players; i > 0; i--)
{
int r; // random variable (number of cards, still to count)
r = int((double(rand()) / RAND_MAX) * i);
if (r == i) r = i - 1;
r += 1;
int n; // Number of the selected card (in the end)
for (n = 0; r > 0; n++)
{
if (!used[n]) {
r--;
if (r == 0) break;
}
Cards[i - 1] = TCard(InttoCardColor(n / 12), InttoCardValue(n % 12));
used[n] = true;
}
Kartenüberprüfung für Stiche
Nur für Standardregeln und Herz Zehnen sind nicht Trumpf.
Code der PreAlphaversion:
bool Trick::IsValid(const TCard& c, const THand& h) const
{
if (act_Card==0) return true;
if (act_Card>3) {
cerr<<"Trick Overflow: IsValid\n";
return false;
}
// Color is equal to first Color in trick: bingo
// and first color is no trump picture
if (c.GetColor()==Cards[0].GetColor() &&
c.GetValue()!=Jack &&
c.GetValue()!=Queen &&
Cards[0].GetValue()!=Jack &&
Cards[0].GetValue()!=Queen) return true;
// attend Trump
if (Cards[0].GetColor()==Diamond ||
Cards[0].GetValue()==Jack ||
Cards[0].GetValue()==Queen)
{
if (c.GetColor()==Diamond) return true;
if (c.GetValue()==Jack) return true;
if (c.GetValue()==Queen) return true;
if (h.hasTrump())
{
return false;
} else return true;
}
// on Hand is no card of this color: Bingo
if (Cards[0].GetValue()!=Jack &&
Cards[0].GetValue()!=Queen &&
Cards[0].GetColor()!=Diamond &&
!h.ExistsColor(Cards[0].GetColor()))
{
return true;
}
// what a shame
return false;
}
Gewinnerermittlung eines Stiches
Nur für Standardregeln und Herz Zehnen sind nicht Trumpf.
Code der PreAlphaversion:
int Trick::WinnerIs(bool Output)
{
int winner=0;
TCard* best=&(Cards[0]);
for(int i=1;i
{
// table of yet made comparisons
//
// Q = queen
// J = jack
// D = diamond
// C = color
//
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | | | |
// J | | | |
// D | | | |
// C | | | |
// Trumpcolor jabs each other color
if (best->GetColor()!=Diamond &&
(Cards[i].GetColor()==Diamond || Cards[i].GetValue()==Jack || Cards[i].GetValue()==Queen) &&
best->GetValue()!=Jack && best->GetValue()!=Queen)
{
winner=i;
best=&(Cards[i]);
continue;
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | | | | x
// J | | | | x
// D | | | | x
// C | | | |
// Queen jabs Jacks
if (best->GetValue()==Jack && Cards[i].GetValue()==Queen)
{
winner=i;
best=&(Cards[i]);
continue;
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | | x | | x
// J | | | | x
// D | | | | x
// C | | | |
// Higher Jack jabs lower
if (best->GetValue()==Jack && Cards[i].GetValue()==Jack)
{
if (best->GetColor()
winner=i;
best=&(Cards[i]);
continue;
}
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | | x | | x
// J | | x | | x
// D | | | | x
// C | | | |
// Higher Queen jabs lower
if (best->GetValue()==Queen && Cards[i].GetValue()==Queen)
{
winner=i;
best=&(Cards[i]);
continue;
}
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | x | x | | x
// J | | x | | x
// D | | | | x
// C | | | |
// Jack jabs no Queen
if(best->GetValue()==Queen && Cards[i].GetValue()==Jack)
{
continue;
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | x | x | | x
// J | x | x | | x
// D | x | | | x
// C | x | | |
// Diamond is jabbed by Jacks and Queens
if (best->GetColor()==Diamond && ( Cards[i].GetValue()==Jack ||
Cards[i].GetValue()==Queen))
{
winner=i;
best=&(Cards[i]);
continue;
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | x | x | x | x
// J | x | x | x | x
// D | x | | | x
// C | x | | |
if (best->GetValue() == Jack)
continue;
if ( (best->GetColor() == Diamond) &&
(Cards[i].GetColor() != Diamond))
continue;
// highest Card of a Color jabs all lower
if (best->GetColor()==Cards[i].GetColor()&&
best->GetValue()!=Jack &&
best->GetValue()!=Queen)
{
// Nine is jabbed by everything except Nine
if (best->GetValue()==Nine && Cards[i].GetValue()!=Nine)
{
winner=i;
best=&(Cards[i]);
continue;
}
// only King and Nine jabs King not
if (best->GetValue()==King &&
Cards[i].GetValue()!=Nine &&
Cards[i].GetValue()!=King)
{
winner=i;
best=&(Cards[i]);
continue;
}
// only Ace jabs ten
if (best->GetValue()==Ten &&
Cards[i].GetValue()!=Nine &&
Cards[i].GetValue()!=King &&
Cards[i].GetValue()!=Ten)
{
winner=i;
best=&(Cards[i]);
continue;
}
}
// i\best| Q | J | D | C
// ------+---+---+---+---
// Q | x | x | x | x
// J | x | x | x | x
// D | x | | x | x
// C | x | | | x
}
return winner;
}
Die Stichdatenbank
Die Datensätze werden in einem Feld gespeichert.
Erzeugung der Datenbank:
Code der PreAlphaversion:
TCard c[4];
for(int w=0;w<24;w++)
for (int x=0;x<24;x++)
for (int y=0;y<24;y++)
for (int z=0;z<24;z++)
{
c[0]=TCard(InttoCardColor(w/6),InttoCardValue(2*(w%6)));
c[1]=TCard(InttoCardColor(x/6),InttoCardValue(2*(x%6)));
c[2]=TCard(InttoCardColor(y/6),InttoCardValue(2*(y%6)));
c[3]=TCard(InttoCardColor(z/6),InttoCardValue(2*(z%6)));
Tricks[w*24*24*24+x*24*24+y*24+z]=TTrick(c);
}
Hierbei sind die Kartenfarbe von 0=Karo bis 3=Kreuz codiert und Die KartenWerte sind 0=Neun, 2=Zehn, 4=As, 6=Bube, 8=Dame und 10=König
Ein Zugriff erfolgt dann wie folgt:
Code der PreAlphaversion:
int mod=24*24*24;
// computation of startposition for Database
for(i = 0; i < CardsInTrick; i++)
{
startpos+=mod*(6*T.GetCard(i).GetColor()+CardValuetoInt(T.GetCard(i).GetValue()/2);
mod=mod/24;
}
Wobei CardValueToInt genau obige Zahlen liefert
Die Berechnung für Gewinnaussicht einer Karte:
Lässt sich als gewichtete Summe aller Punkte der Stiche darstellen, die diese Karte gewinnt, von diesen werden alle Punkte der Stiche abgezogen, die durch diese Karte verloren werden.
Auswerten eines imaginären Spielbaumes
Code der PreAlphaversion:
// add next card to Trick or Evaluate Trick if oll cards played
void PlayTree::calc_one( TTrick T, THand all[Number_of_Players],int depth, int pl, int start,THand h[Number_of_Players])
{
int z,w,i,i1;
TCard c;
THand h2[Number_of_Players];
TTrick T2;
THand h3;
if (T.GetActCard()==Number_of_Players) {
// Evaluate Trick
w=T.WinnerIs(false);
// modify Win_Probality for choosen Card with number start
if (w==pl) {
Win_Prob[start]+=T.GetPoints();
} else {
Win_Prob[start]-=T.GetPoints();
}
// sort hands for next trick to calculate some tricks in the future
for (z=0;z
h2[z]=all[(w+z)%Number_of_Players];
// a little bit statitistic
numbertricks2[start]+=1;
// Calculate next TTrick
calc_Tricks(TTrick(),h2,depth,w,start);
} else {
// Add one Card to T
//by first call find the cards of my hand i'am allowed to play
if (start==-1 || T.GetActCard()==0) {
h[0]=T.GetValidCards(all[0]);
}
// remember my hand before i play a card
h3=h[T.GetActCard()];
for ( i = 0; i < h[T.GetActCard()].GetCardsNumber() ; i++ ) {
T2=T;
c=h[T2.GetActCard()].GetCard(i);
T2=T2+h[T2.GetActCard()].PlayCard(i);
// first call but not last
if ((start==-1 || T.GetActCard()==0) && T2.GetActCard()!=Number_of_Players) {
// modify hands of all other players
for (i1=1;i1
h[i1]=T2.GetValidCards(all[i1]);
}
// add one Card to Trick
calc_one(T2,all,depth,pl,all[T.GetActCard()].GetPos(c),h);
} else {
// add one Card to Trick
calc_one(T2,all,depth,pl,start,h);
}
// restore my hand
h[T.GetActCard()]=h3;
}
}
}
int PlayTree::calc_Tricks(TTrick T,THand all[Number_of_Players],int depth,int pl)
{
if (depth>0) {
depth--;
THand all2[Number_of_Players];
for (int i = 0; i < Number_of_Players; i++)
all2[i] = all[i];
calc_one(T,all,depth,pl,-1,all2);
}
return 0;
}
Stand 17. Oktober 2001