问题
I am working on my first full program with two weeks of programming under my belt, and have run into a road block I can't seem to figure out. I am making a connect 4 game, and have started by building the logic in JavaScript before pushing to the DOM. I have started to make it with cell objects made by a constructor, that are then pushed into a game object in the form of a 2D array. I have managed to create a function that makes the play each time, and changes the value of the cell at the lowest point of that column with a 2 day array. However, I am not sure how to get my check for wins function to operate.
So far my logic is that, for each point in the 2D array, you can check by row, by column, and by diagonals. I understand the logic of how to check for win, but I don't understand how to traverse through the arrays by row and column. In the example below, this.cellsArray is an array of cell objects in the Board Constructor. The array has 7 column arrays, with 6 rows each, as I flipped the typical row column logic to account for Connect Four's column based nature. However I can't access the array like this.cellsArray[col][row], as col and row aren't defined, and I'm not sure how to define an index value? Any help would be appreciated!
Connect 4
Example:
//array location is equal to an instance of this.cellsArray[col][row]
Board.prototype.checkRowRight = function (arrayLocation) {
if ((arrayLocation[i+1][i].value === arrayLocation.value) && (arrayLocation[i+2][i]=== arrayLocation.value) && (arrayLocation[i+3][i].value === arraylocation.value)){
this.winner = this.currentPlayer;
this.winnerFound = true;
console.log('Winner has been found!')
}
};
回答1:
Referencing back to my logic found here and refactoring out the winning line detection code, this can easily be converted into Javascript as follows:
function chkLine(a,b,c,d) {
// Check first cell non-zero and all cells match
return ((a != 0) && (a ==b) && (a == c) && (a == d));
}
function chkWinner(bd) {
// Check down
for (r = 0; r < 3; r++)
for (c = 0; c < 7; c++)
if (chkLine(bd[r][c], bd[r+1][c], bd[r+2][c], bd[r+3][c]))
return bd[r][c];
// Check right
for (r = 0; r < 6; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r][c+1], bd[r][c+2], bd[r][c+3]))
return bd[r][c];
// Check down-right
for (r = 0; r < 3; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r+1][c+1], bd[r+2][c+2], bd[r+3][c+3]))
return bd[r][c];
// Check down-left
for (r = 3; r < 6; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r-1][c+1], bd[r-2][c+2], bd[r-3][c+3]))
return bd[r][c];
return 0;
}
And a test call:
x =[ [0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 2, 2, 2, 0],
[0, 1, 2, 2, 1, 2, 0] ];
alert(chkWinner(x));
The chkWinner
function will, when called with the board, return the first (and only, assuming each move changes only one cell and you're checking after every move) winning player.
The idea is to basically limit the checks to those that make sense. For example, when checking cells to the right (see the second loop), you only need to check each row 0-6
starting in each of the leftmost four columns 0-3
.
That's because starting anywhere else would run off the right hand side of the board before finding a possible win. In other words, column sets {0,1,2,3}
, {1,2,3,4}
, {2,3,4,5}
and {3,4,5,6}
would be valid but {4,5,6,7}
would not (the seven valid columns are 0-6
).
回答2:
This is an old thread but i'll throw my solution into the mix since this shows up as a top search result for "how to calculate connect4 win javascript"
I tackled this problem by using matrix addition.
Assume your game board is stored in memory as a 2D array like this:
[ [0, 0, 0, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, R, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, R, R, R, 0, 0] ];
On each "Coin Drop" you should call a function passing the x/y position of the coin.
THIS is where you calculate weather the user has won the game
let directionsMatrix = {
vertical: { south: [1, 0], north: [-1, 0] },
horizontal: { east: [0, 1], west: [0, -1] },
backward: { southEast: [1, 1], northWest: [-1, -1] },
forward: { southWest: [1, -1], northEast: [-1, 1] },
};
NOTE: "South" in matrix notation is [1,0]
, meaning "Down 1 cell, Right 0 cells"
Now we can loop through each Axis/Direction to check if there is 4 in a row.
const playerHasWon = (colnum, rowNum, playerColor, newGrid) => {
//For each [North/South, East/West, NorthEast/Northwest, SouthEast/Southwest]
for (let axis in directionsMatrix) {
// We difine this variable here so that "East" and "West" share the same count,
// This allows a coin to be dropped in a middle cell
let numMatches = 1;
// For each [North, South]
for (let direction in directionsMatrix[axis]) {
// Get X/Y co-ordinates of our dropped coin
let cellReference = [rowNum, colnum];
// Add co-ordinates of 1 cell in test direction (eg "North")
let testCell = newGrid[cellReference[0]][cellReference[1]];
// Count how many matching color cells are in that direction
while (testCell == playerColor) {
try {
// Add co-ordinates of 1 cell in test direction (eg "North")
cellReference[0] += directionsMatrix[axis][direction][0];
cellReference[1] += directionsMatrix[axis][direction][1];
testCell = newGrid[cellReference[0]][cellReference[1]];
// Test if cell is matching color
if (testCell == playerColor) {
numMatches += 1;
// If our count reaches 4, the player has won the game
if (numMatches >= 4) {
return true;
}
}
} catch (error) {
// Exceptions are to be expected here.
// We wrap this in a try/catch to ignore the array overflow exceptions
// console.error(error);
break;
}
}
// console.log(`direction: ${direction}, numMatches: ${numMatches}`);
// If our count reaches 4, the player has won the game
if (numMatches >= 4) {
return true;
}
}
}
// If we reach this statement: they have NOT won the game
return false;
};
Here's a link to the github repo if you wish to see the full code.
Here's a link to a live demo
来源:https://stackoverflow.com/questions/33181356/connect-four-game-checking-for-wins-js