Why are my functions executing out of order at the end of this Connect Four game? It works in some browsers - javascript

I'm having two timing issues here, both involving the process in this game once the winning move has been made: https://codepen.io/acchang/pen/XWePpWB
Ideally, I should (1) pick the winning space (2) see the winning space filled (3) have the alert proclaim the winner.
What I see and do not like is:
*checkForWinners() runs
winDeclared() runs and the alert "winner" pop up first
Then after the alert is cleared, drawboard() runs, adding the winning piece to the gameboard.
This does not happen as badly in Firefox. The piece is added at the same time the alert pops up.
Then, in winDeclared(), I also change the display in the top right to also indicate the winner. But swapTurns() seems to execute before winDeclared().
Is that because winDeclared() is two functions deep into checkForWinners()? Is there a way to delay it?
Thanks!
let gameboard = [
[1,2,3,4,5,6,7],
[8,9,10,11,12,13,14],
[15,16,17,18,19,20,21],
[22,23,24,25,26,27,28],
[29,30,31,32,33,34,35],
[36,37,38,39,40,41,42]
];
let playerOne
let playerTwo
let indexPick
let availableSpots
let gameType
let playerOneTurn = true
document.getElementsByName("announcements")[0].innerHTML = "Current Player: " + whosPlaying() + " "
let itsAOnePlayerGame = true
let isThereAWinner = false
let mainDiv = document.createElement("div");
mainDiv.setAttribute('class', 'mainDiv')
document.body.append(mainDiv);
let selectorHolder = document.createElement("div")
selectorHolder.setAttribute('class', 'selectorHolder')
selectorHolder.setAttribute('id', 'selectorHolder')
mainDiv.append(selectorHolder)
let selectorTable = document.createElement("table")
selectorTable.setAttribute('class', 'selectorTable')
selectorTable.setAttribute('id', 'selectorTable')
selectorHolder.append(selectorTable)
function drawSelector() {
let selectorRow = document.createElement("tr")
selectorRow.setAttribute('class', 'selectorRow')
selectorTable.append(selectorRow)
for (i=0; i<7; i++){
let selectorCell = document.createElement("td")
selectorCell.setAttribute('class', 'selectorCell')
let innerSelectorCell = document.createElement("div")
innerSelectorCell.setAttribute('class', 'innerSelectorCell')
innerSelectorCell.setAttribute('id', [i])
selectorCell.append(innerSelectorCell)
innerSelectorCell.addEventListener("mouseover", function(event) {
if (playerOneTurn == true) {
innerSelectorCell.classList.add('yellowBG')}
else {innerSelectorCell.classList.add('redBG')
}
})
innerSelectorCell.addEventListener("mouseout", function(event) {
if (playerOneTurn == true) {
innerSelectorCell.classList.remove('yellowBG')}
else {innerSelectorCell.classList.remove('redBG')
}
})
innerSelectorCell.onclick = function(){
if (isThereAWinner == true){return}
else {
indexPick = parseInt(this.id)
console.log(indexPick)
claimSpot()
}
}
selectorRow.append(selectorCell)
}
};
drawSelector()
// Draw Main Gameboard
let mainTable = document.createElement("table");
mainTable.setAttribute('class', 'mainTable')
mainDiv.append(mainTable)
function drawBoard() {
for (i=0; i<gameboard.length; i++){
let row = document.createElement("tr")
mainTable.append(row)
for (j=0; j<gameboard[i].length; j++){
let outerCell = document.createElement('td')
outerCell.setAttribute('class', 'outerCell')
row.append(outerCell)
let innerCell = document.createElement('div')
innerCell.setAttribute('class', 'innerCell')
innerCell.classList.add(gameboard[i][j])
innerCell.setAttribute('innerHTML', gameboard[i][j])
outerCell.append(innerCell)
}
}
};
drawBoard()
function validateRadio() {
let ele = document.getElementsByName('gameType');
for(i = 0; i < ele.length; i++) {
if(ele[i].checked){
gameType = (ele[i].value)
beginGame()
}
}
};
function beginGame() {
if (gameType == "1PEasy"){
itsAOnePlayerGame = true
resetBoard()
onePlayerPickSides()
play1PGame()
}
else if (gameType == "1PHard"){
itsAOnePlayerGame = true
resetBoard()
onePlayerPickSides()
play1PGame()
}
else if (gameType == "2P"){
itsAOnePlayerGame = false
resetBoard()
twoPlayerPickSides()
play2PGame()
}
};
function resetBoard() {
playerOneTurn = true
isThereAWinner = false
gameboard = [
[1,2,3,4,5,6,7],
[8,9,10,11,12,13,14],
[15,16,17,18,19,20,21],
[22,23,24,25,26,27,28],
[29,30,31,32,33,34,35],
[36,37,38,39,40,41,42]
];
}
function swapTurns() {
selectorTable.innerHTML = ""
drawSelector()
playerOneTurn = !playerOneTurn
document.getElementsByName("announcements")[0].innerHTML = "Current Player: " + whosPlaying() + " "
};
// GAMEPLAY
function playerSelects2P() {
findAvailableSpots()
// put an eventListener here?
columnPick = prompt(whosPlaying() + ', choose which column 1-7')
if (availableSpots.includes(parseInt(columnPick)))
{console.log(columnPick)}
else {
alert("not available")
playerSelects2P()}
};
function playerSelects1P() {
if (whosPlaying() == playerTwo) {
findAvailableSpots()
columnPick = availableSpots[Math.floor(Math.random() * availableSpots.length)]
return
}
else {playerSelects2P()}
};
function whosPlaying() {
if (playerOneTurn) {
return "Yellow"
} else {
return "Red"
}
};
// starts from the bottom row and claims spot when there it is a number (unoccupied)
function claimSpot(){
findAvailableSpots()
if (availableSpots.includes(indexPick+1)) {
let i;
for (i = 5; i > -1; i--)
{if (Number.isInteger(gameboard[i][indexPick])) {
gameboard[i].splice((indexPick), 1, whosPlaying())
mainTable.innerHTML = ""
drawBoard()
checkForWinners()
// do I need to put some sort of delay here for it not to go to swap turns right away?
swapTurns()
return
}
}
}
else {
console.log(availableSpots)
alert("Forbidden")
}
};
// if there is a string in row[0], that column is no longer available.
// the cells are numbered from 1 to 7, not per index so you need to add one to indexPick to identify
function findAvailableSpots() {
availableSpots = gameboard[0].filter(x => Number.isInteger(x) == true)
};
function checkForWinners() {
horizontalCheck()
verticalCheck()
downrightCheck()
uprightCheck()
}
// WIN CHECKERS
// a forloop evaluates a section of the matrix, moving through it and seeing if the 3 ahead match.
// it stops before going out of bounds
function findFour(w,x,y,z) {
// Checks first cell against current player and all cells match that player
return ((w == whosPlaying()) && (w === x) && (w === y) && (w === z));
};
function winDeclared() {
isThereAWinner = true
alert("winner")
document.getElementsByName("announcements")[0].innerHTML = whosPlaying() + " wins! "
// this does not show, it snaps to swap places
};
function uprightCheck() {
for (r=5; r>2; r--) {
for (c=0; c<4; c++){
if (findFour(gameboard[r][c], gameboard[r-1][c+1], gameboard[r-2][c+2], gameboard[r-3][c+3])) {
winDeclared()
return
}
}
}
};
function downrightCheck() {
for (r=0; r<3; r++) {
for (c=0; c<4; c++){
if (findFour(gameboard[r][c], gameboard[r+1][c+1], gameboard[r+2][c+2], gameboard[r+3][c+3])) {
winDeclared()
return
}
}
}
};
function verticalCheck() {
for (r=5; r>2; r--) {
for (c=0; c<7; c++){
if (findFour(gameboard[r][c], gameboard[r-1][c], gameboard[r-2][c], gameboard[r-3][c])) {
winDeclared()
return
}
}
}
};
function horizontalCheck() {
for (r=0; r<6; r++) {
for (c=0; c<4; c++){
if (findFour(gameboard[r][c], gameboard[r][c+1], gameboard[r][c+2], gameboard[r][c+3])) {
winDeclared()
return
}
}
}
};

When you manipulate the DOM, the operation itself is syncrhonous but the browser decides when the user will actually see the changes. Sometimes, the broswer will not have time to redraw before the prompt appears. To get around this, you can wrap the alert in a setTimeout() to delay the alert.
setTimeout(
function() {
alert("winner")
}, 10)

Related

Give 1 point to each unique winner respectively in javascript

First of all, I hope you can understand my English. I'm not really good at English. I'd like to ask for help on giving 1 point to every unique user(a user that joined, a live stream to be exact) for every correct answer.
The issue I have in the current coding is that instead of giving points to each user respectively, it counts all users as one. What I mean by that is, for example: When user A wins, he gets(displays) 1 point. When user B wins, he gets(displays) 2 points. The points keep adding for every other user.
I'd like it to be like this: When user A wins, he gets(displays) 1 point. When user B wins he also gets(displays) 1 point too. That means each user has their own winning record.
I hope you can understand what I'm trying to explain.
Please ask if you need further explanation on things you don't understand.
I'd like to display the win count under/currently under the 'function addPhoto'.
Following is the current code:
Thanks in advance!
// DATA
let connection = new TikTokIOConnection(undefined);
let gameWords = [];
let gamegameSelectedWord = null;
let gameTimer = null;
let gameStatus = false;
let wins = 0;
// Config
let confComment = false;
let confLike = false;
let confShare = false;
let confJoin = false;
// START
$(document).ready(() => {
// Resize
function resizeContainer() {
let height = window.innerHeight;
let width = Math.round((9 / 16) * height);
$("#gameSize").html(width + 'x' + height);
$(".container").outerWidth(width);
$(".background").outerWidth(width);
$(".printer").outerWidth(width);
$(".animation").outerWidth(width);
// Paper
if (window.innerWidth >= 1366) {
var paperHeight = $("#paperContainer").outerHeight() - 20;
} else {
var paperHeight = $("#paperContainer").outerHeight() + 7;
}
$("#paper").outerHeight(paperHeight);
}
resizeContainer();
$(window).resize(function() {
resizeContainer();
});
// Connect
$("#targetConnect").click(function(e) {
// Check
if (gameStatus) {
let targetLive = $("#targetUsername").val();
connect(targetLive);
} else {
alert("Start game first!");
}
});
// Test
$("#btnPrepare").click(function(e) {
// Check sound
playSound(1);
playSound(2);
playSound(3);
playSound(4);
speakTTS(MSG_TEST);
// Populate dummy
for (let i = 0; i < 30; i++) {
addContent("<div style='text-align:center;'>Welcome ๐Ÿฅณ๐Ÿฅณ๐Ÿฅณ</div>");
}
// Load game
loadGame();
// Setting
loadSetting();
// Set
gameStatus = true;
});
// Save config
$("#btnSave").click(function(e) {
loadSetting();
});
})
/*GAME PLAY
*/
function speakTTS(msg) {
speak(msg, {
amplitude: 100,
pitch: 70,
speed: 150,
wordgap: 5
});
}
/*function scramble( s ) {
return s.replace(
/\b([a-z])([a-z]+)([a-z])\b/gi,
function( t, a, b, c ) {
b = b.split( /\B/ );
for( var i = b.length, j, k; i; j = parseInt( Math.random() * i ),
k = b[--i], b[i] = b[j], b[j] = k ) {}
return a + b.join( '' ) + c;
}
);
}
document.forms.f.onsubmit = function() {
this.elements.t.value = scramble( this.elements.t.value );
return false;
};
document.forms.f.elements.t.value =
scramble( gettext( document.getElementsByTagName( 'p' )[0] ) );
*/
function censor(word) {
let censored = [];
let length = word.length;
let target = Math.ceil(length / 2);
let range_start = 2;
let range_end = target;
for (let i = 0; i < length; i++) {
let c = word.charAt(i);
if (i >= range_start && i <= range_end) {
if (c === " ") {
censored.push(" ");
} else {
censored.push("*");
}
} else {
censored.push(c);
}
}
return censored.join("");
}
function copyArray(a) {
let b = [];
for (i = 0; i < a.length; i++) {
b[i] = a[i];
}
return b;
}
function shuffle(a) {
let j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
a[i] = a[j];
a[j] = x;
}
return copyArray(a);
}
function countDown() {
// Counter
let timeleft = 60 * 4; // 4 Mins
// Clear
if (gameTimer != null) {
clearInterval(gameTimer);
}
// Start
gameTimer = setInterval(function() {
// Reset
if (timeleft <= 0){
clearInterval(gameTimer);
loadGame();
}
// Set
$("#gameTimeout").html(timeleft.toLocaleString() + "s");
timeleft -= 1;
}, 1000);
}
function loadGame() {
// Check
if (gameWords.length < 1) {
gameWords = shuffle(WORDS);
}
// Load
gameSelectedWord = gameWords.pop();
// Set remain words
$("#gameWords").html(gameWords.length);
// Check
if (typeof gameSelectedWord === 'string') {
// Normalize
splittedWord = gameSelectedWord.split("|");
gameSelectedWord = splittedWord[1];
// Set
$("#textGuess").html("<div style='font-size:70%;padding-bottom:5px;'>" + splittedWord[0] + "</div>" + censor(gameSelectedWord));
//$("#textGuess").html("<div style='font-size:70%;padding-bottom:5px;'>" + splittedWord[0] + "</div>" + scramble(gameSelectedWord));
// Timeout
countDown()
} else {
loadGame();
}
}
function checkWinner(data, msg) {
// Check type
if (typeof gameSelectedWord === 'string' && typeof msg === 'string') {
// Check answer
if (gameSelectedWord.trim().toLowerCase() == msg.trim().toLowerCase()) {
// Print Photo
addPhoto(data, "winner");
// Sound
playSound(4);
// Play TTS
let tssMsg = MSG_WINNER.replace("|username|", data.uniqueId);
speakTTS(tssMsg);
// Reload game
loadGame();
}
}
}
function loadSetting() {
// Load
confComment = $("#confComment").prop('checked');
confLike = $("#confLike").prop('checked');
confShare = $("#confShare").prop('checked');
confJoin = $("#confJoin").prop('checked');
}
/*LIVE TIKTOK
*/
function connect(targetLive) {
if (targetLive !== '') {
$('#stateText').text('Connecting...');
$("#usernameTarget").html("#"+targetLive);
connection.connect(targetLive, {
enableExtendedGiftInfo: true
}).then(state => {
$('#stateText').text(`Connected ${state.roomId}`);
}).catch(errorMessage => {
$('#stateText').text(errorMessage);
})
} else {
alert('Enter username first!');
}
}
function sanitize(text) {
return text.replace(/</g, '<')
}
function isPendingStreak(data) {
return data.giftType === 1 && !data.repeatEnd;
}
function playSound(mode) {
document.getElementById("sfx"+mode).play();
}
function addContent(payload) {
// Container
let content = $('#paper');
content.append("<div class='item'>" + payload + "</div>");
// Scroll top bottom
content.animate({ scrollTop: content.get(0).scrollHeight}, 333);
}
function addMessage(data, msg) {
// DATA
let userName = data.uniqueId;
let message = sanitize(msg);
// Check for voice
let command = message.split(" ")[0];
if (command == ":=say" || command == ":=cakap") {
// TTS
let cleanText = message.replace("=:say", "").replace("=:cakap", "");
speakTTS(cleanText);
} else {
// Check setting
if (confComment) {
// Add
addContent("<span style='font-weight: bold;'>" + userName + "</span>: " + message);
// Sound
playSound(1);
}
}
}
function addPhoto(data, mode) {
// DATA
let userName = data.uniqueId;
let userAvatar = data.profilePictureUrl;
let word = ['Nice going','Thatโ€™s better than ever','Thatโ€™s first class work','Iโ€™m impressed','Nothing can stop you now','Well done','Good job','You did it','Thatโ€™s the way','You rock','I knew you could do it','Keep up the good work','Thatโ€™s clever','Way to go','Outstanding','Tremendous','Fantastic','You are amazing','No one can beat you','You are the chosen one'];
let words = word[Math.floor(Math.random()*word.length)];
// Add
if (mode == "winner")
{
wins++;
addContent(
`<div style="text-align:center;font-size: 1.25rem;">
<div style='padding-bottom:.25rem;color:#1881FF;'>๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป `+words+`</div>
<div style='padding-bottom:.5rem;font-weight: bold;color:#20B601;'>`+userName+` โ—</div>
<div>
<img src="`+userAvatar+`" style="width:135px;height:135px;border-radius: 15px;"/>
Wins: `+wins+`
</div>
</div>`
);
} else {
addContent(
`<div style="text-align:center;font-size: 1.25rem;">
<div style='padding-bottom:.25rem;'>๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰Thanks๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰</div>
<div style='padding-bottom:.5rem;font-weight: bold;color:#EA0C0C;'>`+userName+`</div>
<div>
<img src="`+userAvatar+`" style="width:135px;height:135px;border-radius: 15px;"/>
</div>
</div>`
);
}
// Sound
playSound(3);
}
function addGift(data) {
// DATA
let userName = data.uniqueId;
let giftPictureUrl = data.giftPictureUrl;
let giftName = data.giftName;
let giftRepeat = data.repeatCount;
let giftTotal = (data.diamondCount * data.repeatCount);
let word = ['Appreciate it','Thanks','Thank you very much','It means a lot','Youโ€™re the best','Your gift helps me',];
let words = word[Math.floor(Math.random()*word.length)];
// Check
if (giftTotal >= 10) {
// Print Photo
addPhoto(data);
} else {
// Add
addContent(
`<div style="text-align:center;font-size: 1.25rem;"><div style='padding-bottom:.5rem;'>`+words+` <span style='font-weight: bold;color:#EA0C0C;'>`+userName+`!</span></div>
<div style='font-weight: bold;padding-bottom:.5rem;'><img src="`+giftPictureUrl+`" style="width:35px;height:35px;"/> Sent `+giftName+`</div>
x`+giftRepeat.toLocaleString()+` worth `+giftTotal.toLocaleString()+` coins!</div>`
);
// Sound
playSound(2);
// Play TTS
let tssMsg = MSG_GIFT.replace("|username|", userName);
speakTTS(tssMsg);
}
}
// New chat comment received
connection.on('chat', (data) => {
addMessage(data, data.comment);
checkWinner(data, data.comment);
})
// New gift received
connection.on('gift', (data) => {
if (!isPendingStreak(data) && data.diamondCount > 0) {
addGift(data);
}
})
// Like
connection.on('like', (data) => {
if (typeof data.totalLikeCount === 'number') {
// Check setting
if (confLike) {
// Print like
addMessage(data, data.label.replace('{0:user}', '').replace('likes', `${data.likeCount} likes`));
}
}
})
// Share, Follow
connection.on('social', (data) => {
// Check setting
if (confShare) {
// Print share
addMessage(data, data.label.replace('{0:user}', ''));
}
})
// Member join
let joinMsgDelay = 0;
connection.on('member', (data) => {
let addDelay = 250;
if (joinMsgDelay > 500) addDelay = 100;
if (joinMsgDelay > 1000) addDelay = 0;
joinMsgDelay += addDelay;
setTimeout(() => {
joinMsgDelay -= addDelay;
// Check setting
if (confJoin) {
// Print join
addMessage(data, "has entered");
}
}, joinMsgDelay);
})
// End
connection.on('streamEnd', () => {
$('#stateText').text('Stream ended.');
})
You should have an dictionary (object) of wins with keys the users, and values are the wins for each. Thus you save for each user its own wins.
So declare global:
let wins = {
// name: wins, name2: wins2
}
Then whenever need to increase wins, do so for the wins[playerName] value.
if (mode == "winner") {
wins[userName] = wins[userName] || 0
wins[userName]++
addContent(
`<div style="text-align:center;font-size: 1.25rem;">
<div style='padding-bottom:.25rem;color:#1881FF;'>๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป `+ words + `</div>
<div style='padding-bottom:.5rem;font-weight: bold;color:#20B601;'>`+ userName + ` โ—</div>
<div>
<img src="`+ userAvatar + `" style="width:135px;height:135px;border-radius: 15px;"/>
Wins: `+ wins[userName] + `
</div>
</div>`
);
}

JavaScript Need help writing shouldQuarantine prototype

Need this to determine if any of the passengers are isHealthy =false then quarantine the wagon. I may have an issue on the join prototype as well. The isHealthy is only triggered if they eat and have no food. So it is possible for them to eat, and then have no food but not trigger isHealthy.
I am very new to this please be patient.
const Traveler = function (travelerName) {
this.name = travelerName;
this.food = 1;
this.isHealthy = true;
};
Traveler.prototype.hunt = function () {
this.food += 2;
console.log(this.food);
};
Traveler.prototype.eat = function () {
this.food -= 1;
if (this.food === 1) {
} else {
this.food === 0;
this.isHealthy = false;
}
console.log(this.food);
};
console.log(new Traveler("John"));
function Wagon(capacity) {
this.capacity = capacity;
this.passengers = [];
}
console.log(new Wagon(4));
Wagon.prototype.getAvailableSeatCount = function () {
let seatingCapacity = this.capacity - this.passengers.length;
console.log(seatingCapacity);
return seatingCapacity;
};
Wagon.prototype.join = function (traveler) {
console.log(this.capacity);
let currentCapacity = this.capacity;
if (currentCapacity <= this.passengers.length) {
this.currentCapacity = 0;
} else if (this.getAvailableSeatCount != 0) {
this.passengers.push(traveler);
}
console.log(this.passengers);
};
Wagon.prototype.shouldQuarantine = function () {
for (let i = 0; i < this.passengers.length; i++) {
if (this.passengers[i].isHealthy) {
return false;
}
}
};
Wagon.prototype.totalFood = function () {
let totalFood = "";
this.passengers.forEach(this.food);
console.log(this.food);
};
In you eat method of the Traveler class, first check if there is any food. If there is, then subtract one and check if the food is now empty. If it is then set isHealthy to false.
Traveler.prototype.eat = function () {
if (this.food > 0) {
this.food -= 1;
if (this.food === 0) {
this.isHealthy = false;
}
}
};
Subsequently you should also modify your hunt method to make your traveler healthy again after hunting.
Traveler.prototype.hunt = function () {
this.food += 2;
this.isHealthy = true;
};
In the shouldQuarantine method of the Wagon class, instead of checking if all passengers are healthy, check if anyone of them is not healthy and return true if that is the case.
If everyone is healthy, the loop will finish. Return false after the loop.
Wagon.prototype.shouldQuarantine = function () {
for (let i = 0; i < this.passengers.length; i++) {
if (!this.passengers[i].isHealthy) {
return true;
}
}
return false;
};
Alternatively you could use the some method on the this.passengers array to check if any of the passenger isn't healthy.
Wagon.prototype.shouldQuarantine = function () {
return this.passengers.some(
passenger => passenger.isHealthy === false
);
};
The join method can be simplyfied. You only need the result from this.getAvailableSeatCount() to see if there is any room. Add the traveler if the result is not 0.
Wagon.prototype.join = function (traveler) {
const availableSeats = this.getAvailableSeatCount();
if (availableSeats !== 0) {
this.passengers.push(traveler);
}
};
I also noticed that the totalFood method doesn't work as expected, but I'll let this one up to you. Hint: totalFood should be a number. Loop over every passenger and add the amount of food to the totalFood value.

Function not returning properly when set to a variable but is when console.logged

The problem is in this function:
function minimax(newBoard,player, depth = 0) {
const availableSpots = emptySquares();
// console.log(availableSpots)
// console.log((checkGameStatus(newBoard,player) ? 'true' : 'false'))
let score = {};
if (checkGameStatus(newBoard, computerSymbol)) {
console.log("Are we hitting here? 1")
// console.log((onCheckWin(newBoard) === false))
// console.log(newBoard,"o")
score = { "score": (-100 + depth)}
return score
} else if (checkGameStatus(newBoard, playerSymbol)) {
console.log("Are we hitting here? 2")
// console.log(checkGameStatus(newBoard))
// console.log(newBoard,"o")
score = { "score": (100 - depth)}
return score
} else if (availableSpots.length === 0) {
console.log("Are we hitting here? 3")
score = { "score": 0 }
return score
}
let moves = [];
for (let i=0; i<availableSpots.length; i++) {
let move = {};
move.index = newBoard[availableSpots[i]];
newBoard[availableSpots[i]] = player;
console.table(newBoard)
if (player === computerSymbol) {
let result = minimax(newBoard, playerSymbol , depth++);
console.log(newBoard,"first");
console.log(result)
move.score = result["score"];
} else {
let result = minimax(newBoard, computerSymbol, (depth + 1));
console.log(newBoard,"first");
move.score = result.score;
}
console.log(moves,move)
newBoard[availableSpots[i]] = move.index;
moves.push(move);
console.log(moves,move)
} // end of for look
let bestMove;
if (player === computerSymbol) {
let bestScore = -10000;
for (let i=0; i<moves.length; i++) {
if (moves[i].score > bestScore) {
bestScore = moves[i].score;
bestMove = i;
// console.log(bestMove)
}
// end of for loop
}
if (player === playerSymbol) {
let bestScore = 10000;
for (let i=0; i<moves.length; i++) {
if (moves[i].score < bestScore) {
bestScore = moves[i].score;
bestMove = i;
// console.log(bestMove)
}
}
}
}
return moves[bestMove];
}
When I console.log the function inside of it, it returns an object, but when I set that function call to "result" like here:
if (player === computerSymbol) {
let result = minimax(newBoard, playerSymbol , depth++);
console.log(newBoard,"first");
console.log(result)
move.score = result["score"];
I get undefined as the result and that I can't access property of undefined. Also, I seem to have a problem with my minimax algorithm where it's just constantly choosing the next open square. This might be because I am only using an empty board at the moment. I can add more code if need be, but it seems to me that the problem exists inside the function and not from one of my external or helper functions

iframe element returns undefined after onload event?

EDIT: Is there no one who can shed some light on this issue? Anything would be appreciated. :)
I have a script that is supposed to check to see if an elements html contains a given string..
When these elements do exist, my code throws this error: Uncaught TypeError: Cannot read property 'outerHTML' of null
This is the line: let check = document.querySelector("#iframe_${globalI}").contentWindow.document.querySelector(".Row"+inc).outerHTML
I then check to see if the string includes a check string.. IE: check.includes("Pre Trip")
If I run this line directly in the console it works and returns true... So what is going on here..?? How can I get this check to pass..?
I have this check executing after a setTimeout of 20 seconds, then wrapped again in another setTimeout for 500ms as I was trying to figure this out..
Also, I need to note that there are no XSS / CORS issues.
Here is my code..
function checkRowCount(x){
console.log("Row count called on "+x);
let rowCount = 0;
for(let i = 0; i < 30; i++){
if(typeof(document.querySelector(`#iframe_${x}`).contentWindow.document.querySelector('.Row'+i)) != 'undefined' && document.querySelector(`#iframe_${x}`).contentWindow.document.querySelector('.Row'+i) != null){
rowCount++;
}
}
console.log(rowCount);
return rowCount;
}
let globalCompiler = []; //globalCompiler[globalI] = {unit: unitNumber[globalI], data: ["X", " ", "NO POST TRIP]}
let unitNumber = [1031,1743,1744,1986,3239,3256,3257,4024,4062,4063,4064,4065,4247,4309,4315,4326,4327,4334,4335,4337,4350,4382,4385,7166,7380,7381,8765,8823,8945,8950,8988,10720,17045,17163,40014,40069,40122,40380,80129,80188,80700,80701,80702,80728,80831,80852,80875,"80876","81027","81038","401288","401306","402409","60099T","CH889","CH890","SR31077","T19","U5509","U6660","U6667","U6675","U8854","US1025T"];
let url = "http://winweb.cleanharbors.com/Vehicle/VehicleTDSearch.aspx?SearchType=DVIR";
function iframeLoaded(selector, unit, setDate, callback){
document.querySelector(`#iframe_${selector}`).contentWindow.document.querySelector("#txtStartDate").value = setDate;
document.querySelector(`#iframe_${selector}`).contentWindow.document.querySelector("#txtEndDate").value = setDate;
document.querySelector(`#iframe_${selector}`).contentWindow.document.querySelector("#txtVhcleNo").value = unit;
document.querySelector(`#iframe_${selector}`).contentWindow.document.querySelector("#btnRetrieve").click();
}
let loadFinished = {};
for(let dec = 0; dec < unitNumber.length; dec++){
loadFinished[unitNumber[dec]] = false;
}
console.log(loadFinished);
for(let globalI = 0; globalI < 3; globalI++){
globalCompiler[globalI] = {unit: unitNumber[globalI], data: []};
let iframeObj = document.createElement('iframe');
iframeObj.id = `iframe_${globalI}`;
iframeObj.hidden = false;
iframeObj.src = url;
iframeObj.onload = () => {
if (loadFinished[unitNumber[globalI]] == false) {
loadFinished[unitNumber[globalI]] = true;
let setDate = "11/01/2019";
iframeLoaded(globalI, unitNumber[globalI], setDate);
console.log("iframeloaded called on " + globalI);
setTimeout(() => {
setTimeout(() => {
let dateCheckObject = {}, rowCount = checkRowCount(globalI), trackingArr = [];
if (rowCount == 0) {
globalCompiler[globalI].data.push(" ");
} else {
for (let inc = 1; inc <= rowCount; inc++) {
//let check = $('#iframe_'+globalI).contents().find(`.Row` + inc).html().includes("Pre Trip");
let check = document.querySelector(`#iframe_${globalI}`).contentWindow.document.querySelector(".Row"+inc).outerHTML
if (check.includes("Pre Trip")) {
dateCheckObject.pre = true;
} else {
dateCheckObject.post = true;
}
}
if(dateCheckObject.pre && dateCheckObject.post) {
console.log("X");
globalCompiler[globalI].data.push("X");
dateCheckObject = {};
} else if (dateCheckObject.pre == 'undefined') {
console.log("NO PRE");
globalCompiler[globalI].data.push("NO PRE TRIP");
dateCheckObject = {};
} else {
console.log("NO POST");
globalCompiler[globalI].data.push("NO POST TRIP");
dateCheckObject = {};
}
}
},500);
}, 20000);
}
};
document.body.appendChild(iframeObj);
console.log("Global Loop called");
}
```
A for loop ran one count too far...
e.g.: for (let inc = 1; inc <= rowCount; inc++)
Should have been for (let inc = 1; inc < rowCount; inc++)

Javascript: scope effect despite order of execution

Please note: This is not a question about scope, per se. I understand that in order to make the code work, I should make a deep copy of the variable board rather than assigning var tboard = board. However, I am not clear why making a shallow copy has the effect I describe below.
I am experiencing something I find baffling. Basically, a global variable (board) gets altered and I have no clue how. board is initialized in the function NewGame() (which is called from select()) as an empty array. After it is initialized, nothing else is called until the user clicks a square on the board (assuming the user has selected Xs for simplicity). When that happens, the function playerMove() is called. The baffling thing is that console.log(board) at the top of playerMove() prints out an array that has an x is the clicked position and os everywhere else (ie not empty). This is bizarre because the board is empty at the end of select() (which called NewGame()) and nothing else should happen in between. To demonstrate this, I print out the function name at the top of each function and I print out the board variable in the select() function and playerMove() function to show that it changes despite nothing else being called. Please note that to get this behavior, refresh the page (otherwise the board variable starts out full of os). I think this must be somewhat an issue of scope (because I am not making a deep copy of board) but it's strange because I have no clue what is being called that is changing the variable before it gets printed out at the top of playerMove().
Here is the link to my pen and the code: http://codepen.io/joshlevy89/pen/MKjxop?editors=101
$(document).ready(function() {
var pSym; // player's symbol
var cSym; // computer's symbol
var board;
var whosMove; // can be "player" or "computer" or "neither"
var gameOver;
setup();
$("#newgame").on('click', '#X', select);
$("#newgame").on('click', '#O', select);
$("#restart").on('click', setup);
$("table").on('click', 'td', playerMove);
function playerMove()
{
console.log('playerMove');
console.log(board);
if (whosMove === "player")
{
var val = $(this).data('value');
$('#g' + val).text(pSym);
var arr = PositionToCoords(val);
board[arr[0]][arr[1]] = pSym;
var tboard = board;
var gc = gameCheck(tboard);
if (gc>=0)
{
endGame(gc);
setTimeout(function(){setup();}, 1000);
return;
}
whosMove = "computer";
computerMove();
}
}
function computerMove() {
console.log('computerMove');
//var p1 = Math.floor(Math.random() * 3);
//var p2 = Math.floor(Math.random() * 3);
var tboard = board;
var pos = chooseMove(tboard);
var arr = PositionToCoords(pos);
board[arr[0]][arr[1]] = cSym;
DrawPosition(arr[0], arr[1], cSym);
var tboard = board;
var gc = gameCheck(tboard);
if (gc>=0) {
endGame(gc);
setTimeout(function(){setup();}, 1000);
return;
}
whosMove = "player";
}
function chooseMove(inboard) {
console.log('chooseMove');
// get the possible moves
var moves=[];
var scores = [];
for (var i=1;i<10;i++) {
var arr = PositionToCoords(i);
if (inboard[arr[0]][arr[1]] === undefined) {
moves.push(i);
var tboard = inboard;
tboard[arr[0]][arr[1]] = cSym;
var gc = gameCheck(tboard);
scores.push(gc);
}
}
//console.log(moves);
//console.log(scores);
return moves[0]; // TEMPORARY
}
function endGame(gc) {
console.log('endGame');
var str;
if (gc===1) { // somebody won
if (whosMove==="player"){
str = "You Won!"
}
else {
str = "You Lost :(";
}
}
else if (gc === 0){//draw
str = "It's a draw."
}
html = '<div id="closer">' + str + '</div>';
$('#endgame').html(html);
}
function gameCheck(tboard) {
console.log('gameCheck');
// get symbol to check for
var sym;
if (whosMove === "player") {
sym = pSym;
} else {
sym = cSym;
}
// check if in a row
var hrow;
var vrow;
// check for horizonal row
for (var i = 0; i < 3; i++) {
hrow = true;
vrow = true;
for (var j = 0; j < 3; j++) {
if (tboard[i][j] !== sym) {
hrow = false;
}
if (tboard[j][i] !== sym) {
vrow = false;
}
}
if ((hrow) || (vrow)) {
return 1;
}
}
var fdrow = true;
var bdrow = true;
for (var i = 0; i < 3; i++) {
if (tboard[i][i] !== sym) {
fdrow = false;
}
if (tboard[i][2 - i] !== sym) {
bdrow = false;
}
}
if ((fdrow) || (bdrow)) {
return 1;
}
// otherwise, check if board is full
var full = true;
for (var i = 1; i < 10; i++) {
var arr = PositionToCoords(i);
if (tboard[arr[0]][arr[1]] === undefined) {
full = false;
break;
}
}
if (full === true) {
return 0;
}
// if neither 0 (tie) or win (1), return -1 (game not over)
return -1;
}
function select() {
console.log('select');
pSym = $(this).data('value');
$('#newgame').html('');
NewGame();
console.log(board);
}
function setup() {
console.log('select');
$('#endgame').html('');
html = '<div id="opener">Xs or Os? <div id="buttons">';
html += '<div id="X" data-value="X" class="btn btn-default">Xs</div>';
html += '<div id="O" data-value="O" class="btn btn-default">Os</div>';
html += '</div></div>';
$('#newgame').html(html);
}
function NewGame() {
console.log('NewGame');
$('td').empty();
board = new Array(3);
for (i = 0; i < 3; i++) {
board[i] = new Array(3)
};
if (pSym === "X") {
cSym = "O";
whosMove = "player";
} else {
cSym = "X";
whosMove = "computer";
computerMove();
}
}
function DrawPosition(p1, p2, sym) {
console.log('DrawPosition');
var pos = p1 * 3 + (p2 + 1);
$("#g" + pos).text(sym)
}
function PositionToCoords(pos) {
console.log('PositionToCoords');
var p1 = Math.ceil(pos / 3) - 1;
var p2 = ((pos - 1) % 3);
var arr = [p1, p2];
return arr;
}
});
Thanks in advance.
Simply add the break in the for loop fixes the problem. Am I missing anything?
function chooseMove(inboard) {
console.log('chooseMove');
// get the possible moves
var moves = [];
var scores = [];
for (var i = 1; i < 10; i++) {
var arr = PositionToCoords(i);
if (inboard[arr[0]][arr[1]] === undefined) {
moves.push(i);
var tboard = inboard;
tboard[arr[0]][arr[1]] = cSym;
var gc = gameCheck(tboard);
scores.push(gc);
break; // <<<<<<<<<<<< This break guarantees that the computer only makes one move
}
}
//console.log(moves);
//console.log(scores);
return moves[0]; // TEMPORARY
}

Categories

Resources