I'm currently writing a tic tac toe game in javascript, and I've written the following class to represents the "Computer".
I've included the entire class below, but the method I'm struggling with is atRiskSquare(). Here's how it's supposed to work: the method move() should get called with a board object, and then it should pass that board object into atRiskSquare() which checks whether any of the squares are at risk (in which case the computer would play a defensive move).
When I console.log the "board" inside of the move() method I get an array that represents the board. however, when I console.log the board inside of the atRiskSquare() method I get undefined. I'm not sure if I'm missing something simple, but I can't seem to figure out why this is happening.
Any help would be greatly appreciated
class Computer extends Player {
constructor() {
super();
}
static COMPUTER_MOVE = 'O';
move(board) {
console.log(board); // **Logs the board**
if (this.atRiskSquare(board)) {
this.defensiveMove(this.atRiskSquare(board));
} else {
this.randomMove(board, this.atRiskSquare());
}
}
atRiskSquare(board) {
console.log(board); // **logs undefined**
let humanMoves = board.findSpaces('X'); // Throws an error. Can't iterate over undefined
for (let winningCombo of Game.WINNING_COMBOS) {
let atRiskSquare;
let count;
for (let square of winningCombo) {
if (humanMoves.includes(square)) {
count += 1;
} else {
atRiskSquare = square;
}
}
if (count === 2) {
return atRiskSquare;
}
}
return null;
}
defensiveMove(board, square) {
board.addMove(square, Computer.COMPUTER_MOVE);
this.moves.push(square);
}
randomMove(board) {
let openSpaces = board.findSpaces(' ');
let randomSpace = Math.floor(Math.random() * openSpaces.length);
let move = openSpaces[randomSpace].toString();
board.addMove(move, Computer.COMPUTER_MOVE);
this.moves.push(move);
}
}
I am making a website, http://phaidonasgialis.xyz. I want to make the tiles to turn and every other tile back. Until now it works except one small bug, the tile that you pressed does not turn back until you click second time.Any help would be thankful.
Here is the code:
$(document).ready(function() {
var previous = [];
$('.flip-card').each(function(i, obj) {
$(this).click(function() {
if ($(this).find('.flip-card-inner').hasClass('flip-card-transform')) {
$(this).find('.flip-card-inner').removeClass('flip-card-transform');
} else {
$(this).find('.flip-card-inner').addClass('flip-card-transform');
previous.push(this);
if (previous.length >= 2 && previous[previous.length - 2] != previous[previous.length - 1]) {
for (var i = 0; i < previous.length; i++) {
if ($(this).find('.flip-card-inner').hasClass('flip-card-transform')) {
$(previous[i - 1]).find('.flip-card-inner').removeClass('flip-card-transform');
console.log("2")
} else {
$(this).find('.flip-card-inner').addClass('flip-card-transform');
console.log("3")
}
}
}
}
});
});
If I understand your question correctly, you would like a card to flip back automatically after a certain period of time? If so then you just should set a Timeout and remove the class flip-card-transform from .flip-card-inner.
Aside note: you should definitely optimize your code by using a variable instead of doing $(this).find('.flip-card-inner')– converting this to jQuery object and searching trough its children every time when you need your flip-card-inner. Also instead of $('.flip-card').each(...) you could directly use $('.flip-card').click(...). And also as Harun Yilmaz suggested in his comment you don't need previous as an array...
So something like this should work:
$(document).ready(function () {
var previous
var timeout
$('.flip-card').click(function () {
var cardInner = $(this).find('.flip-card-inner')
if (cardInner.hasClass('flip-card-transform')) {
cardInner.removeClass('flip-card-transform')
clearTimeout(timeout)
} else {
cardInner.addClass('flip-card-transform')
// Set a Timeout
timeout = setTimeout(function () {
cardInner.removeClass('flip-card-transform')
}, 2000) // set whatever time sutable for you
// Also as Harun Yilmaz suggested in his comment you don't need previous as an array
if (previous && previous.hasClass('flip-card-transform')) {
previous.removeClass('flip-card-transform')
}
previous = cardInner
}
})
})
My idea is to build an application that generates sudoku's and allows users to fill them in. I'm using Node and Mongo to do so. For generating the sudoku, I have imported my 'sudoku.js' into a route function. The sudoku generation in 'sudoku.js' runs fine only when I run it by itself, but not in the route.
In short, the sudoku generator picks a random number, checks whether it has already been used in the row/column/block, and if not, adds it to the array. If it has been used, the function is re-ran, until it does 'discover' a correct sudoku. The function should return an array consisting of nine arrays, each with 9 numbers.
It appears to go south when the function genSud() is called within itself. The function, as it is now, returns 'undefined'. When I comment out the function call within the function, it does return an array, but those are almost always unfinished sudoku's. If I leave out the return statement, which I think the issue is related to, it will just keep on rerunning the function until it hits the stack limit.
const createSudoku = {
getRandomNumber: function(array) {
return array[Math.floor(Math.random() * array.length)];
},
checkIfIn: function(array, blockNumber, blockAvailable, columnNumber, columnAvailable) {
let availableNumbers = [];
array.forEach(function(element) {
if (blockAvailable[blockNumber].includes(element) && columnAvailable[columnNumber].includes(element)) {
availableNumbers.push(element);
}
});
if (availableNumbers.length === 0) {
return false;
};
return availableNumbers;
},
genSud: function(callback) {
let availableNumbers = [];
let goodLines;
let blockAvailable = [ [1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,9], etc, etc ]
let columnAvailable = [ [1,2,3,4,5,6,7,8,9], etc, etc ]
let rowAvailable = [ [1,2,3,4,5,6,7,8,9], etc, etc ]
let blockNumber;
let randomNumber;
for (var i = 0; i < 9; i++) {
for (var j = 0; j < 9; j++) {
blockNumber = Math.floor(j / 3) + 3 * Math.floor(i / 3);
availableNumbers = this.checkIfIn(rowAvailable[i], blockNumber, blockAvailable, j, columnAvailable);
if (availableNumbers == false) {
this.genSud(callback);
return;
}
randomNumber = this.getRandomNumber(availableNumbers);
rowAvailable[i].splice(rowAvailable[i].indexOf(randomNumber), 1);
columnAvailable[j].splice(columnAvailable[j].indexOf(randomNumber), 1);
blockAvailable[blockNumber].splice(blockAvailable[blockNumber].indexOf(randomNumber), 1);
body[i].push(randomNumber);
}
}
callback(body);
}
}
// createSudoku.genSud();
module.exports = createSudoku;
Then, in my route:
var sudoku = require('../sudoku.js');
var completeSudoku = sudoku.genSud(function(result) {
return result;
});
I'm aware I could abandon the rerunning altogether by replacing numbers etc., but for now it's fast enough by itself. Also, I know I could store a bunch of sudoku's in a database and retrieve them, but I like the idea of generating them on the spot.
Thanks in advance!
Edit: I have created a CodePen here:
https://codepen.io/anon/pen/OjmGMy?editors=0000
You can run it in the console using:
createSudoku.genSud();
I have made it work by removing the callback and using #nstraub 's suggested edit. Changed:
if (availableNumbers == false) {
this.genSud();
return;
}
to
if (availableNumbers == false) {
return this.genSud();
}
I'm not sure why this works, but it does solve the issue.
I am trying to make a function to buy item but I dont want people to be able to gather more than 2 items at the same time.
I am looking for a condition that state something like.
if Axe + Sword = true then calling the function buyItem(Dagger) will say something like "You cant have more than 2 items".
But consider I want to add more items later.
var buyItem = function (name)
{
if (name === "Axe")
{
console.log("Axe");
}
else if (name === "Sword")
{
console.log("Sword");
}
else if (name === "Dagger")
{
console.log("Dagger");
}
};
Thank you :)
How about having a variable that keeps track of how many items you have?
int itemsHeld = 0;
When you acquire a new item use itemsHeld++; and when you lose one use itemsHeld--;
Now when trying to get a new item you can just ask if (itemsHeld < 2) getItem();
Store bought count as private variable
// store reference to your function returned from self invoking anonymous function enclosure (to prevent internal vairables from leaking into global scope)
var buyItem = (function(){
// store local reference to number of items already bought
var bought = 0;
// return the function to be assigned to buyItem
return function (name)
{
// if we reached the maximum, don't buy any more - just log a warning and return
if(bought >= 2){
console.log("your hands are full!!");
return;
} else {
// otherwise increment the bought counter
bought++;
};
if (name === "Axe")
{
console.log("Axe");
}
else if (name === "Sword")
{
console.log("Sword");
}
else if (name === "Dagger")
{
console.log("Dagger");
}
};
})();
// try it out
buyItem('Dagger');
buyItem('Sword');
buyItem('Axe');
I'm not really sure why my code isn't running correctly.. what I'm trying to do is create a grocery list object that has a couple of functions to add and remove items..
I can instantiate the objects with new items but my functions don't seem to work for some reason.
If you could save me the few hairs left in my head and tell me where the issue is I would greatly appreciate it.
var groceryList = function(itemNames,quantity) {
if (Array.isArray(itemNames)) {
this.items = itemNames;
this.quantity = quantity
this.addItems = function(newItems){
if ( Array.isArray(newItems) ) {
this.items.concat(newItems);
} else {
console.log("Please enter the items in an array fashion!");
};
};
this.removeItem = function(name) {
var listSize = this.items.length;
for (var i = 0; i < listSize; i++) {
if (this.items[i] == name) {
this.items.splice(i,1);
break;
} else {
console.log("Please enter the items in an array fashion!")
};
};
};
} else {
console.log("Please enter the items in an array fashion!")
};
};
.concat() returns a new array so you have to assign the result back to your instance variable.
So this:
this.items.concat(newItems);
needs to be changed to this:
this.items = this.items.concat(newItems);
or, you could actually use this to append to the array directly:
this.items.push.apply(this.items, newItems);
Because .push() can take more than one argument.
Then, in your .removeItem() function, you need to remove the item you actually found by changing this:
this.items.splice(2,1);
to this:
this.items.splice(i,1);