Algorithmus für Gewinner bei Tic Tac Toe - Original (war : FragenderNoob)
-
Wenn ich ehrlich bin, verstehe ich den Code in der Antwort nicht.
Woher kommt die Nummerierung?
Ich habe doch ein 2dimensionales Array...
-
In jedem Fall hast du ein 3x3 Felder grosses Spielfeld, bei denen die Felder von 0-8 nummeriert werden können. Wenn man links oben bei 0 anfängt und rechts unten bei 8 aufhört ergbit sich folgende Aufteilung:
+---+---+---+
| 0 | 1 + 2 |
+---+---+---+
| 3 | 4 + 5 |
+---+---+---+
| 6 | 7 + 8 |
+---+---+---+
Damit dürfte doch eigentlich klar sein, wie der Code funktioniert. Die Anpassung an ein 2D Array ist doch trivial:
unsigned int linear_index; // linearer Index 0-8 unsigned int Row = linear_index / 3; // 0,1,2 -> 0, 3,4,5 -> 1, 6,7,8 -> 2 unsigned int Col = linear_index % 3; // 0,3,6 -> 0, 1,4,7 -> 1, 2,5,8 -> 2
-
Ah, ok... Ich verstehe
Mir war nur wichtig, dass ich den Algorithmus auch problemlos "umkonfigurieren" kann, so dass es für z.B. 4 Gewinnt auch funktioniert. Das ist mit diesem Code scheinbar der fall.
Ich probiers mal aus!
-
Ich hab es jetzt doch noch geschafft, den Code sehr dynamisch zu halten.
Ist zwar mehr Code als vorher, aber anpassungsfähiger.
bool Controller::isCombination(Spieler* player, int startX, int startY, int dirX, int dirY, unsigned int length) { //Teste, ob Startkoordinaten gültig sind if(!this->model->isValidCoord(startX, startY)) { return false; //Ungültige Koordinaten } //Teste, ob Endkoordinaten gültig sind if(!this->model->isValidCoord(startX + (dirX*(length-1)), startY + (dirY*(length-1)))) { return false; //Ungültige Koordinaten } for(unsigned int i = 0; i < length; i++) { if(this->model->getFeld(startX + (dirX*i), startY + (dirY*i))->getPlayer() != player) { return false; } } return true; } Spieler* Controller::checkField() { unsigned int spielfeld_breite = CONST__anzX; unsigned int spielfeld_hoehe = CONST__anzX; unsigned int length = 3; Spieler* player = NULL; for(unsigned int y = 0; y < spielfeld_hoehe; y++) { for(unsigned int x = 0; x < spielfeld_breite; x++) { player = this->model->getFeld(x, y)->getPlayer(); if(player != NULL) { if( this->isCombination(player, x, y, 0, 1, length) || this->isCombination(player, x, y, 1, 0, length) || this->isCombination(player, x, y, 1, 1, length) || this->isCombination(player, x, y, 1, -1, length) || this->isCombination(player, x, y, -1, 1, length) ) { return player; } } } } return NULL; }
Was haltet ihr davon?
Man kann das so problemlos für 4 Gewinnt benutzen, indem man length = 3 in length = 4 umwandelt.
Auch die "erlaubten" Kombinationen können sehr einfach angegeben werden (in der if mit den vielen ||)
Simon
-
[Ursprüngliches Posting gelöscht, da zu blöd, den oben gezeigten Code zu verstehen.]
Dein Modell bzw. das Spielfeld sollte selber wissen, welche Ausmasse es hat. Die Benutzung von lokalen Konstanten in Funktionen wird irgendwann dazu führen, dass dir die Funktion um die Ohren fliegt, weil das Spielfeld ein andere Ausmasse hat und du die Konstante nicht angepasst hast.
-
Das Feld kann keine anderen Ausmaße annehmen, da überall, wo die Größe des Felds irgendwo benötigt wird, die Konstante steht.
Ändere ich also die Konstante, passt sich der Rest auch daran an.
Habs schon ausprobiert
Funktioniert perfekt
-
[Ursprüngliches Posting gelöscht, da zu blöd, den oben gezeigten Code zu verstehen.]
Das kann ich nachvollziehen.
Der Code funktioniert eh nicht, da man dazu den Unterschied zwischen || und && verstehen müsste.
-
So von der funktionsweise wolltest du wohl soetwas.(Einfacherhalber mit einem char Spielfeld)
const int fieldsize=3; bool check_line(char player,int xstart,int ystart,int xadd,int yadd) { unsigned counter=0; while(xstart<fieldsize && ystart<fieldsize) { if(Feld[xstart][ystart]==player) counter++; xstart+=xadd; ystart+=yadd; } return counter==fieldsize; } bool player_win(char player) { for(int i=0;i<fieldsize;i++) { if(check_line(player,i,0,0,1)||check_line(player,0,i,1,0)||check_line(player,0,0,1,1)||check_line(player,fieldsize-1,0,-1,1)) { return true; } } return false; }
-
Ist jetzt natürlich blöd über Code zu sprechen, den ich wieder entfernt habe.
Grundsätzlich war der Ansatz, die Summe der übereinstimmenden horizontalen, vertikalen und diagonalen Felder zu bestimmen. Man bestimmt also für ein Referenzfeld die Summe der aktuellen Zeile, Spalte und der beiden Diagonalen. Aus diesen Summen bestimmt man das Maximum und schaut, ob es das Gewinnkriterium erfüllt.PS:
In der Gültigkeitsüberprüfung musst du ebenfalls prüfen, ob der Index für die Zeile/Spalte negativ sind, da ein "Inkrement" um -1 zu negativen Zahlen führen kann.
-
Hab nochmal rübergeschaut.
Die Abfrage der Diagonalen gehört natürlich nicht in die Schleife.bool player_win(char player) { for(int i=0;i<fieldsize;i++) { if(check_line(player,i,0,0,1)||check_line(player,0,i,1,0)) { return true; } } if (check_line(player,0,0,1,1)||check_line(player,fieldsize-1,0,-1,1)) return true; return false; }