Javascript: Updating direction of robot using string is not working - javascript

Javascript
Trying to work on a simple game of moving a robot using key L(to move left), R(to move right), F(to move forward) from a specific position on a board where it is created using 5x5 dimension and always facing North (shown as N). Clicking a Move button after entering any of above string/characters should display the current position.
Expected: For instance if I say board dimension (5x5), current position (3,3), enter 'R' and hit Move button it should show the resulting position as (3,3) E because the robot was facing north (N) first and now asked to move to RIGHT which would be east (E).
Problem: Can't seem to spot the issue in my code why the direction is not getting updated.
Here is the code that does all calculation and update.
var RobotManager = {
roomType: 'square',
roomParameters: [5, 5],
robotDirection: 'N',
robotPosition: [1, 2],
possibleDirections: ["N", "E", "S", "W"],
errorMessageNumber: -1,
errorMessage: [
"error0",
"error1",
"all other errors removed to keep code clean"
],
squares: [],
stringCommandThatExexuted: '',
init: function() {
var regexp_number = /^[1-9]$|([1][0-9])$/;
return true;
},
// This should move the robot to the right direction
turnRight: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == this.possibleDirections.length - 1) {
return this.possibleDirections[0];
}
return this.possibleDirections[movePosition + 1];
},
turnLeft: function() {
var movePosition = this.possibleDirections.indexOf(this.robotDirection);
if (movePosition == 0) {
return this.possibleDirections[this.possibleDirections.length - 1];
}
return this.possibleDirections[movePosition - 1];
},
moveForward: function() {
var nextPosition = this.getNextPosition();
var nextSquare = {
X: nextPosition[0],
Y: nextPosition[1]
};
if (this.isSquareAvailable(nextSquare)) {
this.robotPosition = nextPosition;
} else {
this.errorMessageNumber = 1;
return false;
}
return true;
},
//this is not getting executed to update the direction
getNextPosition: function() {
var x, y;
switch (this.robotDirection) {
case "N":
x = this.robotPosition[0];
y = this.robotPosition[1] - 1;
break;
case "E":
x = this.robotPosition[0] + 1;
y = this.robotPosition[1];
break;
case "W":
x = this.robotPosition[0] - 1;
y = this.robotPosition[1];
break;
case "S":
y = this.robotPosition[1] + 1;
x = this.robotPosition[0];
break;
}
return [x, y];
},
//First button clicks comes here and just renders default value of direction
getRobotsPositionAndDirection: function() {
if (this.errorMessageNumber <= 1) {
var message = "";
if (this.errorMessageNumber == 0) {
return this.errorMessage[0];
}
if (this.errorMessageNumber == 1) {
message = this.errorMessage[1];
}
return message + this.robotPosition[0] + " " + this.robotPosition[1] + " " + this.robotDirection;
}
return this.errorMessage[8];
},
checkCommandString: function(string) {
var english_command = /^[LRF]*$/;
if (english_command.test(string)) {
return true;
}
this.errorMessageNumber = 0;
return false;
},
getCommandStringThatExecuted: function() {
return this.stringCommandThatExexuted;
},
//This is where index is passed as 0 and doesn't execute
moveRobotToOnePosition: function(letter) {
switch (letter) {
case 'L':
this.robotDirection = this.turnLeft();
this.stringCommandThatExexuted += 'L';
break;
case 'R':
this.robotDirection = this.turnRight();
this.stringCommandThatExexuted += 'R';
break;
case 'F':
if (this.moveForward()) {
this.stringCommandThatExexuted += 'F';
return true;
} else {
return false;
}
break;
}
},
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
return this.moveRobotToOnePosition(i);
}
return true;
}
this.errorMessageNumber = 0;
}
}

So your problem is actually pretty simple, and my apologies for taking so long to figure this out. The issue is that you were passing the array index and not the array element.
moveRobot: function(string) {
string = string.toUpperCase();
if (this.checkCommandString(string)) {
var array = string.split('');
for (var i = 0; i < array.length; i++) {
// return this.moveRobotToOnePosition(i);
this.moveRobotToOnePosition(array[i]); // don't use return here unless you want to exit the function.
}
return true;
}
this.errorMessageNumber = 0;
}

Related

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

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)

JavaScript mocked function returning undefined in tests

I'm trying to test some JavaScript functions that are part of a larger React app. They make heavy use of the module pattern, which I suspect may be what I'm not understanding correctly. Here is the script I'm testing (nearly identical to the one actually used in the real app except that GetFeedData.getFeedData in the real one makes a call to an external API):
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function (sub) {
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
},
getFeedData: function () {
if (feedId === 2) {
feed = require('./MockData');
}
},
feed: feed
};
})();
const ReverseStop = (function () {
let stopIdN, stopIdS;
const stopData = require('../utils/stops');
return {
reverseStop: function (sub, stop) {
var invalidEntries = 0;
function filterByName (item) {
if (item.stop_name == stop && typeof item.stop_id === 'string' && item.stop_id.charAt(0) == sub) {
return true;
}
invalidEntries ++;
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
},
stopIdN: stopIdN,
stopIdS: stopIdS
};
})();
export const IsDelayN = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
export const IsDelayS = (function () {
let noDelay, yesDelay, nextArrival, delay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
function dataFilter () {
var invalidEntries = 0;
var feedObjs = GetFeedData.feed.filter(function (feedObj) {
if (feedObj.entity.trip_update.stop_time_update.stop_id == ReverseStop.stopIdS) {
return feedObj.entity.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs; i++) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
nextArrival: nextArrival
};
})();
What I'm attempting to do is separate out my functions so I have several shorter ones I can call in the exported functions, rather than one or two extremely long functions. Because I need to call a couple variables - GetFeedData.feed, ReverseStop.stopIdN, and ReverseStop.stopIdS in the exported functions, I am assuming that the module pattern is a better way to go than using callbacks. I could totally be wrong.
In my tests, I try log noDelay, nextArrival, and delay to the console to see if they are defined. I'm using Jest, if that information is helpful. I'll omit the other parts of my test for now because they don't seem relevant (please correct me if that's wrong), but here is that section:
it('correctly takes input at beginning of api logic and outputs expected values at end', () => {
IsDelayN.isDelay('L', 'Lorimer St');
IsDelayS.isDelay('L', 'Lorimer St');
expect(IsDelayN.noDelay).toBeTruthy();
expect(IsDelayN.yesDelay).toBeFalsy();
expect(IsDelayS.noDelay).toBeTruthy();
expect(IsDelayS.yesDelay).toBeFalsy();
console.log('IsDelayN noDelay: ' + IsDelayN.noDelay);
console.log('IsDelayN nextArrival: ' + IsDelayN.nextArrival);
console.log('IsDelayN delay: ' + IsDelayN.delay);
console.log('IsDelayS noDelay: ' + IsDelayS.noDelay);
console.log('IsDelayS nextArrival: ' + IsDelayS.nextArrival);
console.log('IsDelayS delay: ' + IsDelayS.delay);
});
The tests prior to my console.log()s are all passing, but every console.log() is turning up undefined. Also, the script that's actually being called by my React components is coming up with the same results. I have my component set to render null if these variables aren't defined, and that's exactly what's happening.
Any help with understanding this is greatly appreciated.
You do not set the modules correctly, when setting a member value you should mutate the object, now you just set a variable value.
The following should work for you:
var module = (function(){
const ret = {
mutateSomething:function(value){
//set otherValue on the object returned (mutate ret)
ret.otherValue = value;
}
,otherValue:undefined
};//create the object first
return ret;//then return the object
}())//IIFE
console.log("before mutate:",module.otherValue);
module.mutateSomething("Hello World");
console.log("after mutate:",module.otherValue);

Is there a javascript library that does spreadsheet calculations without the UI

I am working on a project that needs an excel like calculation engine in the browser. But, it doesn't need the grid UI.
Currently, I am able to do it by hiding the 'div' element of Handsontable. But, it isn't elegant. It is also a bit slow.
Is there a client side spreadsheet calculation library in javascript that does something like this?
x = [ [1, 2, "=A1+B1"],
[2, "=SUM(A1,A2"),3] ];
y = CalculateJS(x);
##############
y: [[1, 2, 3],
[2,3,3]]
I'm not aware of any (although I haven't really looked), but if you wish to implement your own, you could do something along these lines (heavily unoptimized, no error checking):
functions = {
SUM: function(args) {
var result = 0;
for (var i = 0; i < args.length; i++) {
result += parseInt(args[i]);
}
return result;
}
};
function get_cell(position) {
// This function returns the value of a cell at `position`
}
function parse_cell(position) {
cell = get_cell(position);
if (cell.length < 1 || cell[0] !== '=')
return cell;
return parse_token(cell.slice(1));
}
function parse_token(tok) {
tok = tok.trim();
if (tok.indexOf("(") < 0)
return parse_cell(tok);
var name = tok.slice(0, tok.indexOf("("));
if (!(name in functions)) {
return 0; // something better than this?
}
var arguments_tok = tok.slice(tok.indexOf("(") + 1);
var arguments = [];
while (true) {
var arg_end = arguments_tok.indexOf(",");
if (arg_end < 0) {
arg_end = arguments_tok.lastIndexOf(")");
if (arg_end < 0)
break;
}
if (arguments_tok.indexOf("(") >= 0 && (arguments_tok.indexOf("(") < arg_end)) {
var paren_amt = 1;
arg_end = arguments_tok.indexOf("(") + 1;
var end_tok = arguments_tok.slice(arguments_tok.indexOf("(") + 1);
while (true) {
if (paren_amt < 1) {
var last_index = end_tok.indexOf(",");
if (last_index < 0)
last_index = end_tok.indexOf(")");
arg_end += last_index;
end_tok = end_tok.slice(last_index);
break;
}
if (end_tok.indexOf("(") > 0 && (end_tok.indexOf("(") < end_tok.indexOf(")"))) {
paren_amt++;
arg_end += end_tok.indexOf("(") + 1;
end_tok = end_tok.slice(end_tok.indexOf("(") + 1);
} else {
arg_end += end_tok.indexOf(")") + 1;
end_tok = end_tok.slice(end_tok.indexOf(")") + 1);
paren_amt--;
}
}
}
arguments.push(parse_token(arguments_tok.slice(0, arg_end)));
arguments_tok = arguments_tok.slice(arg_end + 1);
}
return functions[name](arguments);
}
Hopefully this will give you a starting point!
To test in your browser, set get_cell to function get_cell(x) {return x;}, and then run parse_cell("=SUM(5,SUM(1,7,SUM(8,111)),7,8)"). It should result in 147 :)
I managed to do this using bacon.js. It accounts for cell interdependencies. As of now, it calculates values for javascript formula instead of excel formula by using an eval function. To make it work for excel formulae, all one has to do is replace eval with Handsontable's ruleJS library. I couldn't find a URI for that library... hence eval.
https://jsfiddle.net/sandeep_muthangi/3src81n3/56/
var mx = [[1, 2, "A1+A2"],
[2, "A2", "A3"]];
var output_reference_bus = {};
var re = /\$?[A-N]{1,2}\$?[1-9]{1,4}/ig
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
function convertToCellRef(rows, cols) {
var alphabet_index = rows+1,
abet = "";
while (alphabet_index>0) {
abet = alphabet[alphabet_index%alphabet.length-1]+abet;
alphabet_index = Math.floor(alphabet_index/alphabet.length);
}
return abet+(cols+1).toString();
}
function getAllReferences(value) {
if (typeof value != "string")
return null;
var references = value.match(re)
if (references.length == 0)
return null;
return references;
}
function replaceReferences(equation, args) {
var index = 0;
return equation.replace(re, function(match, x, string) {
return args[index++];
});
}
//Assign an output bus to each cell
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
output_reference_bus[convertToCellRef(row_index, cell_index)] = Bacon.Bus();
})
})
//assign input buses based on cell references... and calculate the result when there is a value on all input buses
mx.forEach(function(row, row_index) {
row.forEach(function(cell, cell_index) {
if ((all_refs = getAllReferences(cell)) != null) {
var result = Bacon.combineAsArray(output_reference_bus[all_refs[0]]);
for (i=1; i<all_refs.length; i++) {
result = Bacon.combineAsArray(result, output_reference_bus[all_refs[i]]);
}
result = result.map(function(data) {
return eval(replaceReferences(cell, data));
})
result.onValue(function(data) {
console.log(convertToCellRef(row_index, cell_index), data);
output_reference_bus[convertToCellRef(row_index, cell_index)].push(data);
});
}
else {
if (typeof cell != "string")
output_reference_bus[convertToCellRef(row_index, cell_index)].push(cell);
else
output_reference_bus[convertToCellRef(row_index, cell_index)].push(eval(cell));
}
})
})
output_reference_bus["A2"].push(20);
output_reference_bus["A1"].push(1);
output_reference_bus["A1"].push(50);

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
}

How to use Parse JS SDK in Angular.js services? $scope is not updating

First of all sorry for my English
My Task is to create a current work reporting page so i had create a function getWeek() to get current week of month and I have to be stored user enter to Parse database
My Problem is I'm Fetching data from Parse JS SDK and storing in $scope variable but $scope is not updating so please help me..... below is my code
angular.module('workReport', ["xeditable"])
.run(function(editableOptions) {
editableOptions.theme = 'bs3'; // bootstrap3 theme. Can be also 'bs2', 'default'
})
.factory('Reports', function($q) {
return {
getData: function() {
var defered = $q.defer();
var data = getWeek();
var query = new Parse.Query('workReport');
query.find({
success: function(results) {
console.log("Successfully retrieved " + results.length + " scores.");
// Do something with the returned Parse.Object values
for (var i = 0; i < results.length; i++) {
var object = results[i];
for (var j = 0; j < data.length; j++) {
if (data[j].date.getTime() == object.get('date')) {
data[j].activity = object.get('activity');
data[j].mrngSession = object.get('mrngSession');
data[j].afterSession = object.get('afterSession');
data[j].completed = object.get('completed');
}
}
}
defered.resolve(data);
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
console.log(defered.promise)
return defered.promise;
}
}
})
.controller('WeekReportCtrl', function($scope, Reports) {
$scope.week = Reports.getData().then(function(r) {
return r;
}, function(r) { alert('Failed ' + r) })
});
function getWeek() {
var d = new Date
d = d.toString().split(" ");
var day = d[0];
switch (day) {
case 'Mon':
return weeks(1, 1, 5);
break;
case 'Tue':
return weeks(2, -1, 4);
break;
case 'Wed':
return weeks(3, -2, 2);
break;
case 'Thu':
return weeks(4, -3, 1);
break;
case 'Fri':
return weeks(5, -4, 0);
break;
default:
console.log('Nothing');
break;
}
function weeks(d, s, e) {
var week = [];
for (var i = s; i <= e; i++) {
var j = new Date;
j.setHours(0, 0, 0, 0)
var today = false
if (i == 0) {
today = true
}
j.setDate(j.getDate() + i);
week.push({
date: j,
activity: "",
mrngSession: "",
afterSession: "",
completed: 0,
today: today
});
};
return week;
}
}
I think you want to be doing something more like:
Reports.getData().then(function(r) {
$scope.week = r;
}
Currently you're assigning the promise object returned by Reports.getData() to $scope.week, rather than the argument passed to then's success callback function, which is what you want.

Categories

Resources