After initiating the tic-tac-toe AI move (it's currently written only to assess if miniMax can successfully run), it takes about 1 - 1.5 minutes to complete in firefox or chrome. Other tic-tac-toe game's minimax functions run on my computer in a fraction of the time.
Logging output has not led closer to the solution. Have verified that all terminal states return a score. Is there an obvious error here?
Codepen
$(document).ready(function() {
var state = {
status: "inProgress",
turn: "human", //can be human or AI
game: 1,
turnSwitch: function() {
if (this.turn == "human") {
return (this.turn = "AI");
} else if (this.turn == "AI") {
return (this.turn = "human");
}
}
};
//AI will use minimx algorithm to determine best possible move
function player(name, symbol) {
this.name = name;
this.symbol = symbol;
}
var human = new player("human", "X");
var AI = new player("AI", "O");
var board = {
board: [],
createBoard: function() {
for (let i = 0; i < 9; i++) {
this.board.push(i);
}
return this.board;
},
resetBoard: function() {
this.board = [];
createBoard();
},
//checks board for terminal state
terminalTest: function() {
for (let i = 0; i < 7; i += 3) {
if (
this.board[i] == this.board[i + 1] &&
this.board[i] == this.board[i + 2]
) {
if (typeof this.board[i] !== "number") {
return this.board[i];
}
}
}
for (let j = 0; j < 3; j++) {
if (
this.board[j] == this.board[j + 3] &&
this.board[j] == this.board[j + 6]
) {
if (typeof this.board[j] !== "number") {
return this.board[j];
}
}
}
if (
(this.board[0] == this.board[4] && this.board[0] == this.board[8]) ||
(this.board[2] == this.board[4] && this.board[2] == this.board[6])
) {
if (typeof this.board[4] !== "number") {
return this.board[4];
}
}
},
//checks for possible moves
findEmptyIndicies: function() {
return this.board.filter(a => typeof a == "number");
}
};
function miniMax(boardCurrent, player) {
//store all possible moves
var availableMoves = boardCurrent.findEmptyIndicies();
console.log("available moves length " + availableMoves.length);
//if terminal state, return score
var terminalCheck = boardCurrent.terminalTest();
if (terminalCheck === "X") {
//console.log(boardCurrent.board + " X wins score: -10")
return human.symbol == "X" ? { score: -10 } : { score: 10 };
} else if (terminalCheck === "O") {
//console.log(boardCurrent.board + " ) wins score: 10")
return human.symbol == "X" ? { score: 10 } : { score: -10 };
} else if (availableMoves.length === 0) {
console.log("availmoves length 0 " + availableMoves.length);
//console.log(boardCurrent.board + " score: 0")
return { score: 0 };
}
//array to store objects containing index and score through each iteration of available moves
var movesArray = [];
for (var i = 0; i < availableMoves.length; i++) {
//create object to store return score from each index branch
var move = {};
move.index = boardCurrent.board[availableMoves[i]];
boardCurrent.board[availableMoves[i]] = player.symbol;
//returned score from leaf node if conditionials at top of function are met
if (player.name == "AI") {
var miniMaxReturn = miniMax(boardCurrent, human);
move.score = miniMaxReturn.score;
console.log("move score " + move.score);
} else {
var miniMaxReturn = miniMax(boardCurrent, AI);
move.score = miniMaxReturn.score;
console.log("move score " + move.score);
}
boardCurrent.board[availableMoves[i]] = move.index;
movesArray.push(move);
}
var bestMove;
console.log("moves array length " + movesArray.length);
if (player.name === "AI") {
let bestScore = -1000;
for (let i = 0; i < movesArray.length; i++) {
if (movesArray[i].score > bestScore) {
bestScore = movesArray[i].score;
bestMove = i;
}
}
} else if (player.name === "human") {
let bestScore = 1000;
for (let i = 0; i < movesArray.length; i++) {
if (movesArray[i].score < bestScore) {
bestScore = movesArray[i].score;
bestMove = i;
}
}
}
return movesArray[bestMove];
}
/**function AIMove() {
console.log("ai move initiated");
var AIPosition = miniMax(board, AI);
//var index = AIposition.index;
//console.log(AIposition);
//$("#" + index).html(AI.symbol);
}**/
$(".cell").click(displayMove);
function displayMove() {
if (state.turn == "human") $(this).html(human.symbol);
board.board[this.id] = human.symbol;
state.turn = "AI";
miniMax(board, AI);
//AIMove();
console.log("AI move complete");
}
$(".cell").click(displayMove);
//on window load create board
board.createBoard();
});
Related
So I have a checkers game, and I am trying to get it so that you can jump over multiple spaces. It works if you jump the max amount of spaces, but if you don't, say you can jump over two spaces, and you choose to jump over only one, it still removes both pieces even though you only jumped over one of the pieces. I think the problem has is inside the checkForJump() function, and it seems like every time the function is called, it returns the same array, any help would be appreciated.
function checkForJump(buttonSelected, remove, isRoot) {
if(isRoot)
{
clearAvailableMoves();
switchPiece();
}
let adjacentValue = 0;
let jumpNotValid = false;
let RemoveTiles = remove;
for (let i = 0; i < adjacentTileValues.length; i++) {
adjacentValue = adjacentTileValues[i];
if (board.value[adjacentValue + buttonSelected] == enemyPiece && board.value[buttonSelected + (adjacentValue * 2)] == empty) {
if (isSpaceAlreadyInArray(buttonSelected + adjacentValue * 2, i) == false) {
RemoveTiles.push(buttonSelected + adjacentValue);
let tile = new jumpTile(buttonSelected + (adjacentValue * 2));
RemoveTiles.push(buttonSelected + adjacentValue);
console.log("removeTiles" + RemoveTiles);
for (let k = 0; k < RemoveTiles.length; k++) {
tile.tilesToRemove.push(RemoveTiles[k]);
}
console.log("tile.tilesToRemove: " + tile.tilesToRemove);
availableSpaces[i].push(tile);
checkForJump(buttonSelected + (adjacentValue * 2), RemoveTiles,false);
console.log("available spaces = " + availableSpaces);
}
}
}
};
Here is some of the other code, relating to that could also be the source of the problem
function jumpTile(tileID) {
this.tilesToRemove = [];
this.tileID = tileID;
};
let numBlackPieces = 12;
let numWhitePieces = 12;
let adjacentTileValues = [7, 9, -7, -9];
let availableSpaces = [
[],
[],
[],
[]
];
function checkValidSpace(buttonPressed, piece) {
// if button is adjacent to selectedbutton
if (buttonPressed == selectedButton + 7 || buttonPressed == selectedButton + 9 || buttonPressed == selectedButton - 9 || buttonPressed == selectedButton - 7) {
return true;
} else {
let valid = false;
// checks if there is a valid jump
checkForJump(selectedButton,[],true);
// foreach of the possible tiles, if the button pressed is one of them than remove all pieces in that tiles remove list
for (let i = 0; i < availableSpaces.length; i++) {
for (let j = 0; j < availableSpaces[i].length; j++) {
if (buttonPressed == availableSpaces[i][j].tileID) {
valid = true;
console.log("availableSpaces[" + i + j + "] is " + availableSpaces[i][j].tileID + "");
remove(availableSpaces[i][j].tilesToRemove);
return true;
}
}
}
if (valid == false)
return false;
}
}
function checkForJump(buttonSelected, remove, isRoot) {
if(isRoot)
{
clearAvailableMoves();
switchPiece();
}
let adjacentValue = 0;
let jumpNotValid = false;
let RemoveTiles = remove;
for (let i = 0; i < adjacentTileValues.length; i++) {
adjacentValue = adjacentTileValues[i];
if (board.value[adjacentValue + buttonSelected] == enemyPiece && board.value[buttonSelected + (adjacentValue * 2)] == empty) {
if (isSpaceAlreadyInArray(buttonSelected + adjacentValue * 2, i) == false) {
RemoveTiles.push(buttonSelected + adjacentValue);
let tile = new jumpTile(buttonSelected + (adjacentValue * 2));
RemoveTiles.push(buttonSelected + adjacentValue);
console.log("removeTiles" + RemoveTiles);
for (let k = 0; k < RemoveTiles.length; k++) {
tile.tilesToRemove.push(RemoveTiles[k]);
}
console.log("tile.tilesToRemove: " + tile.tilesToRemove);
availableSpaces[i].push(tile);
checkForJump(buttonSelected + (adjacentValue * 2), RemoveTiles,false);
console.log("available spaces = " + availableSpaces);
}
}
}
};
function isSpaceAlreadyInArray(spot, arrayIndex) {
let SpaceAlreadyInArray = false;
for (let j = 0; j < availableSpaces[arrayIndex].length; j++) {
if (availableSpaces[arrayIndex][j].tileID == spot) {
SpaceAlreadyInArray = true;
}
}
return SpaceAlreadyInArray;
}
function clearAvailableMoves() {
for (let i = 0; i < availableSpaces.length; i++) {
availableSpaces[i].pop();
}
}
function remove(removeList, button) {
for (let i = 0; i < removeList.length; i++) {
board.value[removeList[i]] = empty;
board.buttons[removeList[i]].textContent = empty;
if (piece == black) {
numBlackPieces--;
checkForWin(numBlackPieces);
} else if (piece == white) {
numWhitePieces--;
checkForWin(numWhitePieces);
}
}
clearAvailableMoves();
};
I am writing a tic tac toe game using JavaScript(no DOM) in console.
I started by doing only one player game and only with 'X'. When the player chooses the row index and the column index and then it store inside an array(Move), but I'm stuck, the player able to do only one move, and that's it. I really dont know what to do from there.
// Variables
let playerName, playerMove = [],
playerShape, boardGame;
// Functions
// Get And Check Name
function getCheckName() {
let name = prompt("Please Enter Your Name");
while (name == null || !isNaN(name) || name == ' ') {
alert("Numbers And Spaces Not Allowed");
name = prompt("Please Enter Your Name");
}
alert("Welcome " + name);
return name;
}
playerName = getCheckName();
playerShape = 'X';
//----------------------------------------------------------------------------------------
// // Get Row And Col
function getRowAndCol() {
let row, col, rowAndColArr = [];
row = parseInt(prompt("Please Enter A Row"));
while (row > 2 || row < 0 || row === null || isNaN(row)) {
alert("Not a Valid Row number");
row = parseInt(prompt("Please Enter A Row"));
}
rowAndColArr[rowAndColArr.length] = row;
col = parseInt(prompt("Please Enter A Col"));
while (col > 2 || col < 0 || col === null || isNaN(col)) {
alert("Not a Valid Col number");
col = parseInt(prompt("Please Enter A Col"));
}
rowAndColArr[rowAndColArr.length] = col;
return rowAndColArr;
}
playerMove = getRowAndCol();
//----------------------------------------------------------------------------------------
// Board Game
boardGame = [
["_", "_", "_"],
["_", "_", "_"],
["_", "_", "_"]
];
function boardFn(board, move) {
for (let rw = 0; rw < board.length; rw++) {
for (let cl = 0; cl < board[rw].length; cl++) {
while (rw === move[0] && cl === move[1] && board[rw][cl] === "_") {
board[rw][cl] = playerShape;
}
}
}
return board;
}
let keepGame = boardFn(boardGame, playerMove);
do {
} while (condition);
console.log(checkWinner());
//----------------------------------------------------------------------------------------
// Check Win
function equal3(a, b, c) {
return (a == b && b == c && a != "_");
};
function checkWinner() {
let winner = null;
// Win In Horizontal
for (let rw = 0; rw < 3; rw++) {
if (equal3(boardGame[rw][0], boardGame[rw][1], boardGame[rw][2])) {
winner = boardGame[rw][0];
alert(playerName + " You Won line");
}
}
// Win In Vertical
for (let cl = 0; cl < 3; cl++) {
if (equal3(boardGame[0][cl], boardGame[1][cl], boardGame[2][cl])) {
winner = boardGame[cl][0];
alert(playerName + " You Won col");
}
}
// Win In Diagonal
if (equal3(boardGame[0][0], boardGame[1][1], boardGame[2][2])) {
winner = boardGame[0][0];
alert(playerName + " You Won diagonal");
}
// Win In Diagonal (Other Way)
if (equal3(boardGame[2][0], boardGame[1][1], boardGame[0][2])) {
winner = boardGame[2][0];
alert(playerName + " You Won digonal other");
}
return winner;
}
Updated code for two players
var board = [
["_", "_", "_"],
["_", "_", "_"],
["_", "_", "_"]
];
//This function will prompt and get user name
function getName(player) {
let name = prompt("Please Enter " + player + " Name");
while (name == null || !isNaN(name) || name == ' ') {
alert("Numbers And Spaces Not Allowed");
name = prompt("Please Enter " + player + " Name");
}
alert("Welcome, " + name + "!");
return name;
}
//This function will prompt and get row and column from player
function getRowAndCol(player) {
let row, col, rowAndColArr = [];
row = parseInt(prompt(player + "! Please Enter A Row"));
while (row > 2 || row < 0 || row === null || isNaN(row)) {
alert("Not a Valid Row number");
row = parseInt(prompt(player + "! Please Enter A Row"));
}
rowAndColArr[rowAndColArr.length] = row;
col = parseInt(prompt(player + "! Please Enter A Col"));
while (col > 2 || col < 0 || col === null || isNaN(col)) {
alert("Not a Valid Col number");
col = parseInt(prompt(player + "! Please Enter A Col"));
}
rowAndColArr[rowAndColArr.length] = col;
//This block will check if the given box already marked. If so it will prompt for the move.
if (board[rowAndColArr[0]][rowAndColArr[1]] !== "_") {
alert("Already marked on the given box. Please Enter different row and column.!");
return getRowAndCol(player)
}
return rowAndColArr;
}
//This function will update the position with the given shape according to the move
function boardFn(board, move, shape) {
for (let rw = 0; rw < board.length; rw++) {
for (let cl = 0; cl < board[rw].length; cl++) {
while (rw === move[0] && cl === move[1] && board[rw][cl] === "_") {
board[rw][cl] = shape;
}
}
}
}
//This function will check if it is tie
function isTie() {
for (let rw = 0; rw < board.length; rw++) {
for (let cl = 0; cl < board[rw].length; cl++) {
if( board[rw][cl] === "_" ) {
return false;
}
}
}
return true;
}
//These functions will check whether the current player win or not
function equal3(a, b, c) {
return (a == b && b == c && a != "_");
};
function checkWinner(player) {
let winner = null;
// Win In Horizontal
for (let rw = 0; rw < 3; rw++) {
if (equal3(board[rw][0], board[rw][1], board[rw][2])) {
winner = board[rw][0];
alert(player + " You Won line");
}
}
// Win In Vertical
for (let cl = 0; cl < 3; cl++) {
if (equal3(board[0][cl], board[1][cl], board[2][cl])) {
winner = board[cl][0];
alert(player + " You Won col");
}
}
// Win In Diagonal
if (equal3(board[0][0], board[1][1], board[2][2])) {
winner = board[0][0];
alert(player + " You Won diagonal");
}
// Win In Diagonal (Other Way)
if (equal3(board[2][0], board[1][1], board[0][2])) {
winner = board[2][0];
alert(player + " You Won digonal other");
}
return winner;
}
var player1 = getName("Player 1") // getting player 1 name
alert(player1 + "! Your shape is 'X'");
var player2 = getName("Player 2") // getting player 2 name
alert(player2 + "! Your shape is 'O'");
// Variables to maintain current players and shape
var currentPlayer = ""
var currentShape = ""
// This block will get and validate moves until we get a winner
while (true) {
// This block will switch player after a move
if (currentPlayer == "") {
currentPlayer = player1;
currentShape = "X";
} else if (currentPlayer == player1) {
currentPlayer = player2;
currentShape = "O";
} else {
currentPlayer = player1;
currentShape = "X";
}
var move = getRowAndCol(currentPlayer);
boardFn(board, move, currentShape);
var status = "";
for (var i in board) {
for (var j in board[i]) {
status += board[i][j] + " ";
}
status += "\n";
}
console.log(status);
console.log("-------------------------------");
if (checkWinner(currentPlayer)) {
break;
} else if (isTie()) {
alert("Game tied.!")
break;
}
}
I'm working on minimax part of a tic tac toe game, and I keep getting "max call stack size exceeded" error. I isolated the bug to line # 110 which is emptyIndexies(board) function. But I don't see anything wrong with the function. I tested it on the console, and the board seems to update when I click on it; however, the computer turn don't work. Here's the code
var board = [0, 1, 2, 3, 4, 5, 6, 7, 8];
var player, sqrId, user, computer, row, col;
const ARR_LENGTH = 9;
$(document).ready(function() {
//1 checkbox event listener
$(".checkBox").click(function() {
if($(this).is(":checked")) {
user = $(this).val();
player = user;
computer = (user == 'X') ? 'O' : 'X';
}
});
//2 square even listener
$(".square").click(function() {
sqrId = $(this).attr("id");
playerMove();
minimax(board);
if(checkWinner(board, turn)) {
alert(turn+" Wins the game!");
resetBoard();
}
if(!checkDraw()) {
alert("It's a draw!");
}
player = (player == user) ? computer : user;
});
//reset board
$(".reset").click(function() {
resetBoard();
})
});
//player move
function playerMove() {
if($("#"+sqrId).text() == "") {
$("#"+sqrId).text(player);
board[sqrId] = player;
console.log(board);
}
else {
alert("Wrong move");
}
}
/* computer AI generate random number between 0 - 8 */
function computerAI() {
var random;
var min = 0, max = 8;
do {
random = Math.floor(Math.random() * (max + min));
}while($("#"+random).text() != "")
$("#"+random).text(computer);
row = getRow();
col = getCol();
board[row][col] = computer;
}
//getting row number
function getRow() {
return Math.floor(sqrId / ARR_LENGTH);
}
//getting col number
function getCol() {
return sqrId % ARR_LENGTH;
}
/* checking for winner */
// winning combinations using the board indexies
function winning(board){
if (
(board[0] == player && board[1] == player && board[2] == player) ||
(board[3] == player && board[4] == player && board[5] == player) ||
(board[6] == player && board[7] == player && board[8] == player) ||
(board[0] == player && board[3] == player && board[6] == player) ||
(board[1] == player && board[4] == player && board[7] == player) ||
(board[2] == player && board[5] == player && board[8] == player) ||
(board[0] == player && board[4] == player && board[8] == player) ||
(board[2] == player && board[4] == player && board[6] == player)
) {
return true;
} else {
return false;
}
}
function resetBoard() {
$(".square").text("");
$(".checkBox").prop("checked", false);
user = "";
turn = "";
computer = "";
for(var i = 0; i < ARR_LENGTH; i++) {
board[i] = "";
}
}
// returns list of the indexes of empty spots on the board
function emptyIndexies(board){
return board.filter(s => s != "O" && s != "X");
}
// the main minimax function
function minimax(newBoard, player){
//available spots
var availSpots = emptyIndexies(newBoard);
// checks for the terminal states such as win, lose, and tie
//and returning a value accordingly
if (winning(newBoard, user)){
return {score:-10};
}
else if (winning(newBoard, computer)){
return {score:10};
}
else if (availSpots.length === 0){
return {score:0};
}
// an array to collect all the objects
var moves = [];
// loop through available spots
for (var i = 0; i < availSpots.length; i++){
//create an object for each and store the index of that spot
var move = {};
move.index = newBoard[availSpots[i]];
// set the empty spot to the current player
newBoard[availSpots[i]] = player;
/*collect the score resulted from calling minimax
on the opponent of the current player*/
if (player == computer){
var result = minimax(newBoard, user);
move.score = result.score;
}
else{
var result = minimax(newBoard, computer);
move.score = result.score;
}
// reset the spot to empty
newBoard[availSpots[i]] = move.index;
// push the object to the array
moves.push(move);
}
// if it is the computer's turn loop over the moves and choose the move with the highest score
var bestMove;
if(player === computer){
var bestScore = -10000;
for(var i = 0; i < moves.length; i++){
if(moves[i].score > bestScore){
bestScore = moves[i].score;
bestMove = i;
}
}
}else{
// else loop over the moves and choose the move with the lowest score
var bestScore = 10000;
for(var i = 0; i < moves.length; i++){
if(moves[i].score < bestScore){
bestScore = moves[i].score;
bestMove = i;
}
}
}
// return the chosen move (object) from the moves array
return moves[bestMove];
}
While we adding HTML into the HTML output render has in the DIV. If we added something like following
<div class="test" w3-include-html="template_build/header/header-classic.html"></div>
But the output render has incldued that
<div class="test">MY INCLUDED CONTENT</div>
I want to remove that div class="test" on rendering process on w3data.js.
Can someone help me?
Snippet 1 features a simple function that removes any given attribute from any given element. Snippet 2 is the w3data.js with an extra line at 126:
elmnt.removeAttribute("class");
You may use either one to get the same result
SNIPPET 1
removeAttr(".test", "class");
function removeAttr(target, attribute) {
var target = document.querySelector(target);
target.removeAttribute(attribute);
}
.test { color:red }
<div class="test">THIS CONTENT SHOULD BE BLACK TEXT, NOT RED</div>
SNIPPET 2
/* W3Data ver 1.31 by W3Schools.com */
var w3DataObject = {};
function w3DisplayData(id, data) {
var htmlObj, htmlTemplate, html, arr = [],
a, l, rowClone, x, j, i, ii, cc, repeat, repeatObj, repeatX = "";
htmlObj = document.getElementById(id);
htmlTemplate = w3InitTemplate(id, htmlObj);
html = htmlTemplate.cloneNode(true);
arr = w3GetElementsByAttribute(html, "w3-repeat");
l = arr.length;
for (j = (l - 1); j >= 0; j -= 1) {
cc = arr[j].getAttribute("w3-repeat").split(" ");
if (cc.length == 1) {
repeat = cc[0];
} else {
repeatX = cc[0];
repeat = cc[2];
}
arr[j].removeAttribute("w3-repeat");
repeatObj = data[repeat];
if (repeatObj && typeof repeatObj == "object" && repeatObj.length != "undefined") {
i = 0;
for (x in repeatObj) {
i += 1;
rowClone = arr[j];
rowClone = w3NeedleInHaystack(rowClone, "element", repeatX, repeatObj[x]);
a = rowClone.attributes;
for (ii = 0; ii < a.length; ii += 1) {
a[ii].value = w3NeedleInHaystack(a[ii], "attribute", repeatX, repeatObj[x]).value;
}
(i === repeatObj.length) ? arr[j].parentNode.replaceChild(rowClone, arr[j]): arr[j].parentNode.insertBefore(rowClone, arr[j]);
}
} else {
console.log("w3-repeat must be an array. " + repeat + " is not an array.");
continue;
}
}
html = w3NeedleInHaystack(html, "element");
htmlObj.parentNode.replaceChild(html, htmlObj);
function w3InitTemplate(id, obj) {
var template;
template = obj.cloneNode(true);
if (w3DataObject.hasOwnProperty(id)) {
return w3DataObject[id];
}
w3DataObject[id] = template;
return template;
}
function w3GetElementsByAttribute(x, att) {
var arr = [],
arrCount = -1,
i, l, y = x.getElementsByTagName("*"),
z = att.toUpperCase();
l = y.length;
for (i = -1; i < l; i += 1) {
if (i == -1) {
y[i] = x;
}
if (y[i].getAttribute(z) !== null) {
arrCount += 1;
arr[arrCount] = y[i];
}
}
return arr;
}
function w3NeedleInHaystack(elmnt, typ, repeatX, x) {
var value, rowClone, pos1, haystack, pos2, needle = [],
needleToReplace, i, cc, r;
rowClone = elmnt.cloneNode(true);
pos1 = 0;
while (pos1 > -1) {
haystack = (typ == "attribute") ? rowClone.value : rowClone.innerHTML;
pos1 = haystack.indexOf("{{", pos1);
if (pos1 === -1) {
break;
}
pos2 = haystack.indexOf("}}", pos1 + 1);
needleToReplace = haystack.substring(pos1 + 2, pos2);
needle = needleToReplace.split("||");
value = undefined;
for (i = 0; i < needle.length; i += 1) {
needle[i] = needle[i].replace(/^\s+|\s+$/gm, ''); //trim
//value = ((x && x[needle[i]]) || (data && data[needle[i]]));
if (x) {
value = x[needle[i]];
}
if (value == undefined && data) {
value = data[needle[i]];
}
if (value == undefined) {
cc = needle[i].split(".");
if (cc[0] == repeatX) {
value = x[cc[1]];
}
}
if (value == undefined) {
if (needle[i] == repeatX) {
value = x;
}
}
if (value == undefined) {
if (needle[i].substr(0, 1) == '"') {
value = needle[i].replace(/"/g, "");
} else if (needle[i].substr(0, 1) == "'") {
value = needle[i].replace(/'/g, "");
}
}
if (value != undefined) {
break;
}
}
if (value != undefined) {
r = "{{" + needleToReplace + "}}";
if (typ == "attribute") {
rowClone.value = rowClone.value.replace(r, value);
} else {
w3ReplaceHTML(rowClone, r, value);
}
}
pos1 = pos1 + 1;
}
return rowClone;
}
function w3ReplaceHTML(a, r, result) {
var b, l, i, a, x, j;
if (a.hasAttributes()) {
b = a.attributes;
l = b.length;
for (i = 0; i < l; i += 1) {
if (b[i].value.indexOf(r) > -1) {
b[i].value = b[i].value.replace(r, result);
}
}
}
x = a.getElementsByTagName("*");
l = x.length;
a.innerHTML = a.innerHTML.replace(r, result);
}
}
function w3IncludeHTML() {
var z, i, elmnt, file, xhttp;
z = document.getElementsByTagName("*");
for (i = 0; i < z.length; i++) {
elmnt = z[i];
file = elmnt.getAttribute("w3-include-html");
if (file) {
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
elmnt.innerHTML = this.responseText;
elmnt.removeAttribute("w3-include-html");
elmnt.removeAttribute("class"); // Add this expression
w3IncludeHTML();
}
}
xhttp.open("GET", file, true);
xhttp.send();
return;
}
}
}
function w3Http(target, readyfunc, xml, method) {
var httpObj;
if (!method) {
method = "GET";
}
if (window.XMLHttpRequest) {
httpObj = new XMLHttpRequest();
} else if (window.ActiveXObject) {
httpObj = new ActiveXObject("Microsoft.XMLHTTP");
}
if (httpObj) {
if (readyfunc) {
httpObj.onreadystatechange = readyfunc;
}
httpObj.open(method, target, true);
httpObj.send(xml);
}
}
I am new to JavaScript, I have been learning and practicing for about 3 months and hope I can get some help on this topic. I'm making a poker game and what I'm trying to do is determine whether i have a pair, two pairs, three of a kind, four of a kind or a full house.
For instance, in [1, 2, 3, 4, 4, 4, 3], 1 appears one time, 4 appears three times, and so on.
How could I possibly ask my computer to tell me how many times an array element appears?
Solved, here's the final product.
<script type="text/javascript">
var deck = [];
var cards = [];
var convertedcards = [];
var kinds = [];
var phase = 1;
var displaycard = [];
var options = 0;
var endgame = false;
// Fill Deck //
for(i = 0; i < 52; i++){
deck[deck.length] = i;
}
// Distribute Cards //
for(i = 0; i < 7; i++){
cards[cards.length] = Number(Math.floor(Math.random() * 52));
if(deck.indexOf(cards[cards.length - 1]) === -1){
cards.splice(cards.length - 1, cards.length);
i = i - 1;
}else{
deck[cards[cards.length - 1]] = "|";
}
}
// Convert Cards //
for(i = 0; i < 7; i++){
convertedcards[i] = (cards[i] % 13) + 1;
}
// Cards Kind //
for(i = 0; i < 7; i++){
if(cards[i] < 13){
kinds[kinds.length] = "H";
}else if(cards[i] < 27 && cards[i] > 12){
kinds[kinds.length] = "C";
}else if(cards[i] < 40 && cards[i] > 26){
kinds[kinds.length] = "D";
}else{
kinds[kinds.length] = "S";
}
}
// Card Display //
for(i = 0; i < 7; i++){
displaycard[i] = convertedcards[i] + kinds[i];
}
// Hand Strenght //
var handstrenght = function(){
var usedcards = [];
var count = 0;
var pairs = [];
for(i = 0, a = 1; i < 7; a++){
if(convertedcards[i] === convertedcards[a] && a < 7 && usedcards[i] != "|"){
pairs[pairs.length] = convertedcards[i];
usedcards[a] = "|";
}else if(a > 6){
i = i + 1;
a = i;
}
}
// Flush >.< //
var flush = false;
for(i = 0, a = 1; i < 7; i++, a++){
if(kinds[i] === kinds[a] && kinds[i] != undefined){
count++;
if(a >= 6 && count >= 5){
flush = true;
count = 0;
}else if(a >= 6 && count < 5){
count = 0;
}
}
}
// Straight >.< //
var straight = false;
convertedcards = convertedcards.sort(function(a,b){return a-b});
if(convertedcards[2] > 10 && convertedcards[3] > 10 && convertedcards[4] > 10){
convertedcards[0] = 14;
convertedcards = convertedcards.sort(function(a,b){return a-b});
}
alert(convertedcards);
if(convertedcards[0] + 1 === convertedcards[1] && convertedcards[1] + 1 === convertedcards[2] && convertedcards[2] + 1 === convertedcards[3] && convertedcards[3] + 1 === convertedcards[4]){
straight = true;
}else if(convertedcards[1] + 1 === convertedcards[2] && convertedcards[2] + 1 === convertedcards[3] && convertedcards[3] + 1 === convertedcards[4] && convertedcards[4] + 1 === convertedcards[5]){
straight = true;
}else if(convertedcards[2] + 1 === convertedcards[3] && convertedcards[3] + 1 === convertedcards[4] && convertedcards[4] + 1 === convertedcards[5] && convertedcards[5] + 1 === convertedcards[6]){
straight = true;
}
// Royal Flush, Straight Flush, Flush, Straight >.< //
var royalflush = false;
if(straight === true && flush === true && convertedcards[6] === 14){
royalflush = true;
alert("You have a Royal Flush");
}
else if(straight === true && flush === true && royalflush === false){
alert("You have a straight flush");
}else if(straight === true && flush === false){
alert("You have a straight");
}else if(straight === false && flush === true){
alert("You have a flush");
}
// Full House >.< //
if(pairs[0] === pairs[1] && pairs[1] != pairs[2] && pairs.length >= 3){
fullhouse = true;
alert("You have a fullhouse");
}else if(pairs[0] != pairs[1] && pairs[1] === pairs[2] && pairs.length >= 3){
fullhouse = true;
alert("You have a fullhouse");
}else if(pairs[0] != pairs[1] && pairs[1] != pairs[2] && pairs[2] === pairs[3] && pairs.length >= 3){
fullhouse = true;
alert("You have a fullhouse");
}
// Four of a kind >.< //
else if(pairs[0] === pairs[1] && pairs[1] === pairs[2] && pairs.length > 0){
alert("You have four of a kind");
}
// Three of a kind >.< //
else if(pairs[0] === pairs[1] && flush === false && straight === false && pairs.length === 2){
alert("You have three of a kind");
}
// Double Pair >.< //
else if(pairs[0] != pairs[1] && flush === false && straight === false && pairs.length > 1){
alert("You have a double pair");
}
// Pair >.< //
else if(pairs.length === 1 && flush === false && straight === false && pairs.length === 1 ){
alert("You have a pair");
}
alert(pairs);
};
while(endgame === false){
if(phase === 1){
options = Number(prompt("Your hand: " + displaycard[0] + " " + displaycard[1] + "\n\n" + "1. Check" + "\n" + "2. Fold"));
}else if(phase === 2){
options = Number(prompt("Your hand: " + displaycard[0] + " " + displaycard[1] + "\n\n" + displaycard[2] + " " + displaycard[3] + " " + displaycard[4] + "\n\n" + "1. Check" + "\n" + "2. Fold"));
}else if(phase === 3){
options = Number(prompt("Your hand: " + displaycard[0] + " " + displaycard[1] + "\n\n" + displaycard[2] + " " + displaycard[3] + " " + displaycard[4] + " " + displaycard[5] + "\n\n" + "1. Check" + "\n" + "2. Fold"));
}else if(phase === 4){
options = Number(prompt("Your hand: " + displaycard[0] + " " + displaycard[1] + "\n\n" + displaycard[2] + " " + displaycard[3] + " " + displaycard[4] + " " + displaycard[5] + " " + displaycard[6] + "\n\n" + "1. Check" + "\n" + "2. Fold"));
}
switch(options){
case 1:
if(phase === 5){
handstrenght();
endgame = true;
}else{
phase++;
}
break;
case 2:
endgame = true;
break;
default:
endgame = true;
break;
}
}
</script>
Keep a variable for the total count
Loop through the array and check if current value is the same as the one you're looking for, if it is, increment the total count by one
After the loop, total count contains the number of times the number you were looking for is in the array
Show your code and we can help you figure out where it went wrong
Here's a simple implementation (since you don't have the code that didn't work)
var list = [2, 1, 4, 2, 1, 1, 4, 5];
function countInArray(array, what) {
var count = 0;
for (var i = 0; i < array.length; i++) {
if (array[i] === what) {
count++;
}
}
return count;
}
countInArray(list, 2); // returns 2
countInArray(list, 1); // returns 3
countInArray could also have been implemented as
function countInArray(array, what) {
return array.filter(item => item == what).length;
}
More elegant, but maybe not as performant since it has to create a new array.
With filter and length it seems simple but there is a big waste of memory.
If you want to use nice array methods, the appropriate one is reduce:
function countInArray(array, value) {
return array.reduce((n, x) => n + (x === value), 0);
}
console.log(countInArray([1,2,3,4,4,4,3], 4)); // 3
Well..
var a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
if (typeof acc[curr] == 'undefined') {
acc[curr] = 1;
} else {
acc[curr] += 1;
}
return acc;
}, {});
// a == {2: 5, 4: 1, 5: 3, 9: 1}
from here:
Counting the occurrences of JavaScript array elements
Or you can find other solutions there, too..
When targeting recent enough browsers, you can use filter(). (The MDN page also provides a polyfill for the function.)
var items = [1, 2, 3, 4, 4, 4, 3];
var fours = items.filter(function(it) {return it === 4;});
var result = fours.length;
You can even abstract over the filtering function as this:
// Creates a new function that returns true if the parameter passed to it is
// equal to `x`
function equal_func(x) {
return function(it) {
return it === x;
}
}
//...
var result = items.filter(equal_func(4)).length;
Here's an implementation of Juan's answer:
function count( list, x ) {
for ( var l = list.length, c = 0; l--; ) {
if ( list[ l ] === x ) {
c++;
}
}
return c;
}
Even shorter:
function count( list, x ) {
for ( var l = list.length, c = 0; l--; list[ l ] === x && c++ );
return c;
}
Here's an implementation that uses the Array Object Prototype and has an extra level of functionality that returns the length if no search-item is supplied:
Array.prototype.count = function(lit = false) {
if ( !lit ) { return this.length}
else {
var count = 0;
for ( var i=0; i < this.length; i++ ) {
if ( lit == this[i] ){
count++
}
}
return count;
}
}
This has an extremely simple useage, and is as follows:
var count = [1,2,3,4,4].count(4); // Returns 2
var count = [1,2,3,4,4].count(); // Without first parameter returns 5