Je sais qu'il y a beaucoup de questions concernant connect 4 check pour une victoire. Le problème est que la plupart des autres algorithmes font que mon programme a des erreurs d'exécution, car ils essaient d'accéder à un index en dehors de mon tableau. Mon algorithme est comme ceci:
private int checkWin(int[][] gridTable,int rowNum,int colNum, int maxRow, int maxCol)
{
// For checking whether any win or lose condition is reached. Returns 1 if win or lose is reached. else returns 0
// gridTable[][] is the game matrix(can be any number of rows and columns between 4 and 40)
// colNum is the column number where the last token was placed
// rowNum is the row number where the last token was placed
// maxRow is the number of rows in my grid
// maxCol is the number of columns in my grid
int player = gridTable[rowNum][colNum]; //player ID
int count=0;
// Horizontal check
for (int i=0;i<maxCol;i++)
{
if (gridTable[rowNum][i]==player)
count++;
else
count=0;
if (count>=4)
return 1;
}
//Vertical check
for (int i=0;i<maxRow;i++)
{
if (gridTable[i][colNum]==player)
count++;
else
count=0;
if (count>=4)
return 1;
}
count=0;
// 4 in a row diagonally
for(int i=colNum+1,j=rowNum+1;i<maxRow && j<maxCol;i++,j++)
{
if(gridTable[j][i]!=player)
{
count=1;
break;
}
count++;
}
// 4 in a row diagonally
for(int i=colNum-1,j=rowNum-1;i>=0 && j>=0;i--,j--)
{
if(gridTable[j][i]!=player)
{
count=1;
break;
}
count++;
}
// 4 in a row diagonally
for(int i=colNum+1,j=rowNum-1;i<maxRow && j>=0;i++,j--)
{
if(gridTable[j][i]!=player)
{
count=1;
break;
}
count++;
}
for(int i=colNum-1,j=rowNum+1;i>=0 && j<maxCol;i--,j++)
{ // 4 in a row diagonally
if(gridTable[j][i]!=player)
{
count=1;
break;
}
count++;
}
if(count>=4)
return 1;
return 0;
}
count est la variable qui vérifie une victoire si le nombre est égal ou supérieur à 4 signifie qu'ils devraient être 4 jetons consécutifs ou plus du même joueur.
LE PROBLÈME: parfois la méthode vérifie une victoire sans avoir 4 jetons en ordre et d'autres fois ne vérifie pas une victoire quand 4 jetons sont en règle.
Il semble que votre code soit correct pour les cas horizontaux et verticaux. La partie délicate est le boîtier diagonal.
Essayons une image:
Pour les lignes vertes, la position de votre ligne de départ est 0 ... maxRow - 4. La colonne serait 0 ... startingRow -
Pseudocode:
// top-left to bottom-right - green diagonals
for( rowStart = 0; rowStart < rowMax - 4; rowStart++){
count = 0;
int row, col;
for( row = rowStart, col = 0; row < rowMax && col < colMax; row++, col++ ){
if(gridTable[row][col] == player){
count++;
if(count >= 4) return 1;
}
else {
count = 0;
}
}
}
// top-left to bottom-right - red diagonals
for( colStart = 1; colStart < colMax - 4; rowStart++){
count = 0;
int row, col;
for( row = 0, col = colStart; row < rowMax && col < colMax; row++, col++ ){
if(gridTable[row][col] == player){
count++;
if(count >= 4) return 1;
}
else {
count = 0;
}
}
}
Vous pouvez faire quelque chose de similaire pour les diagonales qui vont dans l'autre sens (du bas à gauche au haut à droite).
Pour une raison quelconque, je n'aime pas tellement les compteurs, alors je l'ai fait de cette façon (cela fonctionne pour les planches de différentes tailles).
public boolean areFourConnected(int player){
// horizontalCheck
for (int j = 0; j<getHeight()-3 ; j++ ){
for (int i = 0; i<getWidth(); i++){
if (this.board[i][j] == player && this.board[i][j+1] == player && this.board[i][j+2] == player && this.board[i][j+3] == player){
return true;
}
}
}
// verticalCheck
for (int i = 0; i<getWidth()-3 ; i++ ){
for (int j = 0; j<this.getHeight(); j++){
if (this.board[i][j] == player && this.board[i+1][j] == player && this.board[i+2][j] == player && this.board[i+3][j] == player){
return true;
}
}
}
// ascendingDiagonalCheck
for (int i=3; i<getWidth(); i++){
for (int j=0; j<getHeight()-3; j++){
if (this.board[i][j] == player && this.board[i-1][j+1] == player && this.board[i-2][j+2] == player && this.board[i-3][j+3] == player)
return true;
}
}
// descendingDiagonalCheck
for (int i=3; i<getWidth(); i++){
for (int j=3; j<getHeight(); j++){
if (this.board[i][j] == player && this.board[i-1][j-1] == player && this.board[i-2][j-2] == player && this.board[i-3][j-3] == player)
return true;
}
}
return false;
}
Donc, après avoir fouillé votre code, il semblerait que le contrôle diagonal ne puisse gagner que dans une seule direction (que se passe-t-il si j'ajoute un jeton à la ligne la plus basse et à la colonne la plus basse?)
Au lieu de cela, l'algorithme de vérification de base est toujours le même processus, quelle que soit la direction dans laquelle vous vérifiez.
Vous avez besoin d'un point de départ (x/y) et d'un delta x/y (direction du mouvement). Vous pouvez résumer cela en une seule méthode ...
public boolean didWin(int[][] grid, int check, int row, int col, int rowDelta, int colDelta) {
boolean win = true;
for (int count = 0; count < 4; count++) {
if (row < ROWS && row >= 0 && col < COLUMNS && col >= 0) {
int test = grid[row][col];
if (test != check) {
win = false;
break;
}
}
row += rowDelta;
col += colDelta;
}
return win;
}
Cela vous permettra essentiellement de vérifier dans quatre directions, mais aussi de les inverser
Donc, si nous devions utiliser quelque chose comme ...
int[][] gridTable = new int[ROWS][COLUMNS];
gridTable[ROWS - 1][3] = 1;
gridTable[ROWS - 2][3] = 1;
gridTable[ROWS - 3][3] = 1;
gridTable[ROWS - 4][3] = 1;
System.out.println("Vertical");
System.out.println(didWin(gridTable, 1, ROWS - 4, 3, 1, 0) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, ROWS - 1, 3, -1, 0) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 0, 3, 1, 0) ? "Win" : "Lose");
gridTable = new int[ROWS][COLUMNS];
gridTable[3][1] = 1;
gridTable[3][2] = 1;
gridTable[3][3] = 1;
gridTable[3][4] = 1;
System.out.println("");
System.out.println("Horizontal");
System.out.println(didWin(gridTable, 1, 3, 1, 0, 1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 3, 4, 0, -1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 3, 0, 0, 1) ? "Win" : "Lose");
gridTable = new int[ROWS][COLUMNS];
gridTable[0][1] = 1;
gridTable[1][2] = 1;
gridTable[2][3] = 1;
gridTable[3][4] = 1;
System.out.println("");
System.out.println("Diag");
System.out.println(didWin(gridTable, 1, 0, 1, 1, 1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 3, 4, -1, -1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 1, 2, 1, 1) ? "Win" : "Lose");
Quelles sorties ...
Vertical
Win
Win
Lose
Horizontal
Win
Win
Lose
Diag
Win
Win
Lose
Maintenant, vous pouvez simplement le résumer à ...
public boolean didWin(int[][] grid, int check, int row, int col) {
return didWin(grid, check, row, col, 1, 0) ||
didWin(grid, check, row, col, -1, 0) ||
didWin(grid, check, row, col, 0, 1) ||
didWin(grid, check, row, col, 0, -1) ||
didWin(grid, check, row, col, 1, 1) ||
didWin(grid, check, row, col, -1, -1) ||
didWin(grid, check, row, col, -1, 1) ||
didWin(grid, check, row, col, 1, -1);
}
Donc, en utilisant quelque chose comme ...
int[][] gridTable = new int[ROWS][COLUMNS];
gridTable[ROWS - 1][3] = 1;
gridTable[ROWS - 2][3] = 1;
gridTable[ROWS - 3][3] = 1;
gridTable[ROWS - 4][3] = 1;
System.out.println("Vertical");
System.out.println(didWin(gridTable, 1, ROWS - 1, 3) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, ROWS - 4, 3) ? "Win" : "Lose");
gridTable = new int[ROWS][COLUMNS];
gridTable[3][1] = 1;
gridTable[3][2] = 1;
gridTable[3][3] = 1;
gridTable[3][4] = 1;
System.out.println("");
System.out.println("Horizontal");
System.out.println(didWin(gridTable, 1, 3, 1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 3, 4) ? "Win" : "Lose");
gridTable = new int[ROWS][COLUMNS];
gridTable[0][1] = 1;
gridTable[1][2] = 1;
gridTable[2][3] = 1;
gridTable[3][4] = 1;
System.out.println("");
System.out.println("Diag");
System.out.println(didWin(gridTable, 1, 0, 1) ? "Win" : "Lose");
System.out.println(didWin(gridTable, 1, 3, 4) ? "Win" : "Lose");
Qui imprime quelque chose comme ...
Vertical
Win
Win
Horizontal
Win
Win
Diag
Win
Win
J'ajouterais que cette approche ne fonctionne que si vous fournissez le bon départ des 4 puces d'affilée. Par exemple, didWin (gridTable, 1, 3, 3) fournira false au lieu de true pour votre vérification horizontale, car la boucle ne peut vérifier qu'une seule direction.
L'intention n'était pas de fournir une solution "complète, prête à l'emploi", mais un concept à partir duquel une solution plus large pourrait être développée (je veux dire, je détesterais que les gens aient réellement à réfléchir;)). J'ai également conçu la solution en partant de l'idée que l'OP saurait où était placée la dernière pièce, c'est-à-dire le point de départ;)
En modifiant très légèrement la méthode didWin
, il est possible de vérifier une grille n
par n
à partir de n'importe quel point ...
public boolean didWin(int[][] grid, int check, int row, int col, int rowDelta, int colDelta) {
boolean match = false;
int matches = 0;
while (row < ROWS && row >= 0 && col < COLUMNS && col >= 0) {
int test = grid[row][col];
if (test != check && match) {
break;
} else if (test == check) {
match = true;
matches++;
}
row += rowDelta;
col += colDelta;
}
return matches == 4;
}
Donc, j'ai utilisé ...
public static final int ROWS = 8;
public static final int COLUMNS = 8;
//...
int[][] gridTable = new int[ROWS][COLUMNS];
gridTable[ROWS - 1][3] = 1;
gridTable[ROWS - 2][3] = 1;
gridTable[ROWS - 3][3] = 1;
gridTable[ROWS - 4][3] = 1;
for (int[] row : gridTable) {
StringJoiner sj = new StringJoiner("|", "|", "|");
for (int col : row) {
sj.add(Integer.toString(col));
}
System.out.println(sj);
}
System.out.println(didWin(gridTable, 1, 3, 3));
et a pu le faire fonctionner. Parfois, une réponse n'est pas une solution complète, mais une graine pour une idée qui emmène quelqu'un dans un nouvel endroit;)
J'améliorerais également la fourniture du nombre de pièces jointes attendues, mais je suis presque sûr que c'est une amélioration que je n'ai vraiment pas besoin de démontrer;)
Si quelqu'un a encore besoin de la solution, j'écris une fonction en c # et je mets en dépôt GitHub.
/// <summary>
/// WinnerCalc check if blue or red win the game.
/// </summary>
/// <returns>Return 1 if 1 win and 2 if 2 win and -1 if no one win.</returns>
/// <param name="matrix">2d array</param>
/// <param name="lastRow">The row number.</param>
/// <param name="lastColumn">The column number.</param>
public static int WinnerCalc(int[,] matrix, int lastRow, int lastColumn)
{
int lastValue = matrix[lastRow, lastColumn];
Console.WriteLine("drop in row: " + (lastRow) + " and column: " + (lastColumn) + " , the value is: " + lastValue);
int rows = matrix.GetLength(0); //6
int columns = matrix.GetLength(1); //7
Console.WriteLine("number of rows is " + rows + ", and number of colums is " + columns);
int numToWin = 4;
int winner = -1;//is now one win tha game
int match;
match = 0;
//check Horizontal
for (int c = 0; c < columns; c++)
{
int currentValue = matrix[lastRow, c];
if (currentValue == lastValue)
match++;
else match = 0;
if(match == numToWin)
{
winner = lastValue;
break;
}
}
if (winner != -1)
{
Console.WriteLine("win Horizontal !");
return winner;
}
match = 0;
//check Vertical
for (int r = 0; r < rows; r++)
{
int currentValue = matrix[r, lastColumn];
if (currentValue == lastValue)
match++;
else match = 0;
if (match == numToWin)
{
winner = lastValue;
break;
}
}
if (winner != -1)
{
Console.WriteLine("win Vertical !");
return winner;
}
//check diagonal top-left to bottom-right - include middle
match = 0;
for (int r = 0; r <= rows - 4; r++)
{
int rowPosition = r;
for (int column = 0; column < columns && rowPosition < rows; column++)
{
int currentValue = matrix[rowPosition, column];
if (currentValue == lastValue)
match++;
else match = 0;
if (match == numToWin)
{
winner = lastValue;
break;
}
rowPosition++;
}
if (winner != -1) break;
}
if (winner != -1)
{
Console.WriteLine("win Diagonal Top left! - include middle");
return winner;
}
//check diagonal top-left to bottom-right - after middle
match = 0;
for (int c = 1; c <= columns - 4; c++)
{
int columnPosition = c;
for (int row = 0; row < rows && columnPosition < columns; row++)
{
int currentValue = matrix[row, columnPosition];
if (currentValue == lastValue)
match++;
else match = 0;
if (match == numToWin)
{
winner = lastValue;
break;
}
columnPosition++;
}
if (winner != -1) break;
}
if (winner != -1)
{
Console.WriteLine("win Diagonal Top left! - after middle");
return winner;
}
//check diagonal bottom-left to top-right - include middle
match = 0;
for (int r = rows - 1; r >= rows - 4; r--)
{
int rowPosition = r;
for (int column = 0; column < columns && rowPosition < rows && rowPosition >= 0; column++)
{
int currentValue = matrix[rowPosition, column];
if (currentValue == lastValue)
match++;
else match = 0;
if (match == numToWin)
{
winner = lastValue;
break;
}
rowPosition--;
}
if (winner != -1) break;
}
if (winner != -1)
{
Console.WriteLine("win Diagonal Bottom left! - include middle");
return winner;
}
//check diagonal bottom-left to top-right - after middle
match = 0;
for (int c = 1; c < columns; c++)
{
int columnPosition = c;
for (int row = rows - 1; row < rows && columnPosition < columns && columnPosition >= 1; row--)
{
int currentValue = matrix[row, columnPosition];
if (currentValue == lastValue)
match++;
else match = 0;
if (match == numToWin)
{
winner = lastValue;
break;
}
columnPosition++;
}
if (winner != -1) break;
}
if (winner != -1)
{
Console.WriteLine("win Diagonal Bottom left! - after middle");
return winner;
}
return winner; // no winner return -1
}
}
et voici le repo: https://github.com/JoshK2/connect-four-winner