I am trying to make a tic-tac-toe game, but in Codepen my Javascript gives me an error saying "Infinite loop found on line 0. The line number is approximated so look carefully." Here is the pen
See the Pen Tic-Tac-Toe by Maris (#spacegeek224) on CodePen.
and here is my JS:
(function() {
var PLAYERS = ['X','O'];
var TURN = PLAYERS[0];
var BOARD = [new Array(3),new Array(3),new Array(3)];
function togglePlayer() {
TURN = (TURN == PLAYERS[0]) ? PLAYERS[1] : PLAYERS[0];
}
$('.square').click(function(e) {
if ($(e.target).attr('data-p')) {
} else {
$(e.target).attr('data-p',TURN).text(TURN);
BOARD[$(e.target).attr('data-y')][$(e.target).attr('data-x')] = TURN;
if (checkWin(BOARD)) {
$('.turn').attr('data-p',checkWin(BOARD)).text(checkWin(BOARD) + " wins!");
$('.square:not([data-p])').attr('data-p',true);
}
else {
togglePlayer();
$('.turn').attr('data-p',TURN).text(TURN+"\'s turn");
}
}
});
function checkWin(board) {
for (var i = 0;i<3;i++) {
if (board [0][i] !== undefined)
if (board[0][i]==board[1][i] && board[1][i] == board[2][i])
return board[0][i];
else if (board [i][0] !== undefined)
if (board[i][0]==board[i][1] && board[i][1] == board[i][2])
return board[i][0];
else if (board[1][1] !== undefined)
if (board[0][0] == board[1][1] && board[1][1] == board[2][2])
return board[1][1];
else if (board[0][2] == board[1][1] && board[1][1] == board[2][0])
return board[1][1];
}
return false;
}
$('.container').on('dblclick',function() {
$('.square').removeAttr('data-p').text('');
BOARD = [new Array(3),new Array(3),new Array(3)];
TURN = PLAYERS[0];
$('.turn').attr('data-p',TURN).text(TURN+"\'s turn");
});
})();
I figured it out, and i cant believe I didn't see this before. In the checkWin function I should have put if instead of if else inside the for loop.
Related
I have solved the problem Count the smiley faces:
Given an array (arr) as an argument complete the function countSmileys that should return the total number of smiling faces.
Rules for a smiling face:
Each smiley face must contain a valid pair of eyes. Eyes can be marked as : or ;
A smiley face can have a nose but it does not have to. Valid characters for a nose are - or ~
Every smiling face must have a smiling mouth that should be marked with either ) or D
No additional characters are allowed except for those mentioned.
Valid smiley face examples: :) :D ;-D :~)
Invalid smiley faces: ;( :> :} :]
Example
countSmileys([':)', ';(', ';}', ':-D']); // should return 2;
countSmileys([';D', ':-(', ':-)', ';~)']); // should return 3;
countSmileys([';]', ':[', ';*', ':$', ';-D']); // should return 1;
Note
In case of an empty array return 0. You will not be tested with invalid input (input will always be an array). Order of the face (eyes, nose, mouth) elements will always be the same.
Then when I look through the solutions I find that many people use regexp. Then I want write a state machine to implement regexp and solve this problem. But I failed. This is my code:
function countSmileys(smileys) {
let state = smileyHasValidEye;
return smileys.filter(smiley => {
for (let s of [...smiley]) {
state = state(s);
}
return state === true;
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return;
}
console.log(countSmileys([':)', ';(', ';}', ':-D']));
And the error I get is:
state = state(s);
^
TypeError: state is not a function
Then I debugged my code I found the procedure doesn't enter the smileyHasValidNose function. Then I don't know the reason.
The problem is you don't really reset state in between smileys. So the next smiley state will be true which you can't call (it's not a function).
You could use a local variable for state that resets it to the first function (the first step).
function countSmileys(smileys) {
let firstStep = smileyHasValidEye;
return smileys.filter(smiley => {
let state = firstStep;
for (let s of [...smiley]) {
state = state(s);
}
return state === true;
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return;
}
console.log(countSmileys([':)', ';(', ';}', ':-D']));
This code however, will error if there's more on the string besides the smiley (or a partial of the smiley).
I would change smileyHasValidMouth to return false if it doesn't detect a smiley. Just to be more consistent here...
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return false;
}
And adjust your loop to exit early if it finds a value that is not a function.
for (let s of [...smiley]) {
state = state(s);
if(typeof state !== 'function') return state;
}
function countSmileys(smileys) {
let firstStep = smileyHasValidEye;
return smileys.filter(smiley => {
let state = firstStep;
for (let s of [...smiley]) {
state = state(s);
if (typeof state !== 'function') return state;
}
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return false;
}
console.log(countSmileys([':~(', ':>', ':D', ':(', ':o>', ';)', ':)']));
The subject will be displayed randomly, and if you write any of (same value, different value, empty value) in the text box, click and press the OK button, you will proceed to the next problem even if the values are not exactly the same. After repeating this process 5 times, I would like to display the number of erroneous inputs.
Look at this if/else if block:
document.addEventListener("keypress", function(e) {
if(e.key === questionList[question].charAt(index) ){
document.forms[0].elements[0].value = "";
index++;
} else if (e.key === 'Shift') {
;
} else if(index == questionList[question].length){
document.forms[0].elements[0].value = "";
index++;
} else if(e.key !== questionList[question].charAt(index)){
typecount++;
} else {
typemiss++;
}
});
The if statement at the beginning checks this:
e.key === questionList[question].charAt(index)
The else if statement before the else checks this:
e.key !== questionList[question].charAt(index)
One or the other will be true. Which means it will never reach the else where you have the typemiss counter incremented.
I have not checked if the following works completely like you wanted but it could help find the error for you:
document.addEventListener("keypress", function(e) {
var isTyping = false;
if(e.key === questionList[question].charAt(index) ){
document.forms[0].elements[0].value = "";
index++;
isTyping = true;
} else if (e.key === 'Shift' || e.key === 'Alt') {
;
} else if(index == questionList[question].length){
document.forms[0].elements[0].value = "";
index++;
} else if(e.key !== questionList[question].charAt(index)){
typemiss++;
isTyping = true;
}
if (isTyping) {
typecount++;
}
});
I have a webpage that populates a table with arrays. It has a doClick function so that when a user clicks on a cell it passes the row and column of the cell to the function. Example cell: onclick="doClick(0,1)"
function doClick(row, col)
{
var top = row -1;
var bottom = row +1;
var left = col -1;
var right = col +1;
var swapped = false;
if ((top != -1) && (cells[top][col].innerHTML = ""))
{
cells[top][col].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else if ((right != 4) && (cells[row][right].innerHTML = ""))
{
cells[row][right].innerHTML = cells[row][col].innerHTML ;
cells[row][col].innerHTML = "";
swapped = true;
}
else if ((bottom != 4) && (cells[bottom][col].innerHTML = ""))
{
cells[bottom][col].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else if ((left != -1) && (cells[row][left].inn = ""))
{
cells[row][lef].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else
{
alert("Illegal Move.");
}
. The problem is, even if both if expressions are true, the if statement is being skipped and it's falling through to the else statement. I've desk checked it and run it through the developer tools and checked values. A statement that was true on both expressions was skipped. Any suggestions?
cells[row][right].innerHTML = ""
is wrong. You are missing the double (triple) =.
The correct way should be...
cells[row][right].innerHTML === ""
It looks like maybe there are a few typos or misconceptions in your code.
A quick note about Conditions in an IF statement
A statement like (cells[top][col].innerHTML = "") as a condition will always return true as this is setting cells[top][col].innerHTML as "" or at least instantiating the variable. So, the proper condition to test absolutely true or false would be (cells[top][col].innerHTML === ""). However, you can get away with not even doing that and simply replace (cells[top][col].innerHTML = "") with cells[top][col].innerHTML. You may run into some other issues though is the variable is not instantiated already, either way. I would wrap the latter logic in an IF statement to check if cells[top][col].innerHTML is even instantiated.
To fix this, check out the following modifications I have made to your code.
function doClick(row, col)
{
var top = row -1;
var bottom = row +1;
var left = col -1;
var right = col +1;
var swapped = false;
if(typeof cells[top][col].innerHTML !== 'undefined' $$ cells[top][col].innerHTML !== null)
{
if ((top != -1) && cells[top][col].innerHTML !== '')
{
cells[top][col].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else if ((right != 4) && cells[row][right].innerHTML !== '')
{
cells[row][right].innerHTML = cells[row][col].innerHTML ;
cells[row][col].innerHTML = "";
swapped = true;
}
else if ((bottom != 4) && (cells[bottom][col].innerHTML))
{
cells[bottom][col].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else
{
alert("Illegal Move.");
}
}
else if (typeof cells[row][left].inn !== 'undefined' && (left != -1) && cells[row][left].inn !== '')
{
cells[row][lef].innerHTML = cells[row][col].innerHTML;
cells[row][col].innerHTML = "";
swapped = true;
}
else
{
alert("Illegal Move.");
}
}
An example working to demonstrate the above code
var testVar1 = '';
var testVar2 = 'Hello';
// var testVar3; <- Left this un-instantiated to test existance
// Testing if a var is empty but exists
if(typeof testVar1 !== 'undefined' && testVar1 !== null){
if(testVar1 !== ''){
alert('testVar1 has a value!');
}{
alert('testVar1 does not have a value!');
}
}
// Testing if a var is empty but exists
if(typeof testVar2 !== 'undefined' && testVar2 !== null){
if(testVar2 !== ''){
if(testVar2 === 'Hello'){
alert('testVar2 has a value! Value: ' + testVar2);
}{
alert('testVar2 has a value but it is not the one we expected.');
}
}{
alert('testVar2 does not have a value!');
}
}
// Test existance
if(typeof testVar3 !== 'undefined' && testVar3 !== null){
alert('testVar3 exists!');
}else{
alert('testVar3 does not exist!');
}
I just picked up JavaScript and want to make my tic-tac-toe game object-oriented. Right now I'm having trouble making my players take turns. Below I've made a global variable turn that starts off as true, then alternates between true and false as a player clicks on the board. The HTML is not provided here, but each grid in the 3x3 board is a form.
If turn === true, it should be player_1's turn, and player_2 otherwise, but it isn't working. Any ideas on what I should be doing to get it right? I understand that the "if...else if" statement at the bottom runs only once, which is why it isn't working. Any ideas on what and where my conditional statement should be for it to work?
$(document).ready(function() {
var turn = true;
var Player = function(id,symbol){
this.symbol = symbol;
this.id = id;
function playerMove(player){
$("#tictac").on("click", function(event){
event.preventDefault();
var $button = $(event.target);
$button.val(symbol);
turn = turn ? false : true;
console.log(checkIfWinner());
console.log("turn:"+turn);
})
};
this.playerMove = playerMove;
function checkIfWinner(player) {
var $board = $("#tictac").children();
if ($board.find("#cell0").children().val() == symbol &&
$board.find("#cell1").children().val() == symbol &&
$board.find("#cell2").children().val() == symbol)
return true;
if ($board.find("#cell2").children().val() == symbol &&
$board.find("#cell5").children().val() == symbol &&
$board.find("#cell8").children().val() == symbol)
return true;
if($board.find("#cell0").children().val() == symbol &&
$board.find("#cell3").children().val() == symbol &&
$board.find("#cell6").children().val() == symbol)
return true;
if ($board.find("#cell0").children().val() == symbol &&
$board.find("#cell4").children().val() == symbol &&
$board.find("#cell8").children().val() == symbol)
return true;
if ($board.find("#cell2").children().val() == symbol &&
$board.find("#cell4").children().val() == symbol &&
$board.find("#cell6").children().val() == symbol)
return true;
if ($board.find("#cell3").children().val() == symbol &&
$board.find("#cell4").children().val() == symbol &&
$board.find("#cell5").children().val() == symbol)
return true;
if ($board.find("#cell6").children().val() == symbol &&
$board.find("#cell7").children().val() == symbol &&
$board.find("#cell8").children().val() == symbol)
return true;
if ($board.find("#cell1").children().val() == symbol &&
$board.find("#cell4").children().val() == symbol &&
$board.find("#cell7").children().val() == symbol)
return true;
return false;
}
this.checkIfWinner = checkIfWinner;
};
var startGame = function(player_1,player_2){
this.player_1 = player_1;
this.player_2 = player_2;
setMessage('<p>'+ player_1.symbol + ' starts the game</p>');
function setMessage(msg){
$("#message").html(msg);
};
};
var player_1 = new Player(1,"X");
var player_2 = new Player(2,"O");
var game = new startGame(player_1,player_2);
if (turn === true){
game.player_1.playerMove();
}
else if (turn === false){
game.player_2.playerMove();
}
game.player_1.playerMove();
});
This is not enough:
if (turn === true){
game.player_1.playerMove();
}
else if (turn === false){
game.player_2.playerMove();
}
You have to negate turn. Also, you can simplify the if ... else conditions:
if (turn) {
game.player_1.playerMove();
} else {
game.player_2.playerMove();
}
turn = !turn; // Negate the value to alternate moves.
You can write the player move even more succinctly, if you wish:
game['player_' + (turn ? '1' : '2')].playerMove();
Don't forget to put the player moves inside a loop of some kind:
while (true) {
// Make the player move.
// Check if the game is over.
// Has the player won? Is the board full? Display an appropriate message.
if (gameOver) {
break; // Break out of the loop if the game is over.
}
turn = !turn;
}
Back to the basics of JavaScript. This is a question I am coming with is based on computation time speed of JavaScript If condition.
I have a logic which includes usage of if condition. The question is computing equal to value is faster OR not equal to value is faster?
if(vm.currentFeedbackObject.sendReminderLists[0].sendReminderFlag !== '' && vm.currentFeedbackObject.sendReminderLists[0].sendReminderedOn !== null)
{
vm.isReminderSectionVisible = true;
} else
{
vm.isReminderSectionVisible = false;
}
The above one computes not equal to
if(vm.currentFeedbackObject.sendReminderLists[0].sendReminderFlag === '' && vm.currentFeedbackObject.sendReminderLists[0].sendReminderedOn === null)
{
vm.isReminderSectionVisible = false;
} else
{
vm.isReminderSectionVisible = true;
}
The above one computes equal to value
which of both these is faster in execution?
Why don't you try it out? Write to your console this:
function notequal() {
if(vm.currentFeedbackObject.sendReminderLists[0].sendReminderFlag !== '' && vm.currentFeedbackObject.sendReminderLists[0].sendReminderedOn !== null)
vm.isReminderSectionVisible = true;
}
else {
vm.isReminderSectionVisible = false;
}
}
function yesequal() {
if(vm.currentFeedbackObject.sendReminderLists[0].sendReminderFlag === '' && vm.currentFeedbackObject.sendReminderLists[0].sendReminderedOn === null)
vm.isReminderSectionVisible = false;
}
else {
vm.isReminderSectionVisible = true;
}
}
var iterations = 1000000;
console.time('Notequal #1');
for(var i = 0; i < iterations; i++ ){
notequal();
};
console.timeEnd('Notequal #1')
console.time('Yesequal #2');
for(var i = 0; i < iterations; i++ ){
yesequal();
};
console.timeEnd('Yesequal #2')