Battleship error JavaScript - javascript

I'm currently developing the Battleship game in Javascript, however, everytime a run the code there's a Cannot read property '4' of undefined error.
I've searched everywhere for an answer but couldn't find any. I've also tried console.log to see what it's undefined, which I think it's my variable tab which is the board of the game, but I can't find a solution do make it not undefined.
Here's the code where I create the board:
var tab = [];
for (var i=0; i<dim; i++) {
tab.push([]);
for(var j=0; j<dim; j++) {
tab[i].push(0);
}
}
generateships(tab, dim, 1, 4);
generateships(tab, dim, 2, 3);
generateships(tab, dim, 3, 2);
generateships(tab, dim, 4, 1);
On the last part of the code I call the function that checks if it's okay to insert a boat in that position. It requires tab, dim which is the dimension of the board, for example 10, the number of ships and finally the boat's length.
function generateships(tab, dim, numbships, boatlen) {
for (var i = 0; i < numbships; i++) {
var empty = false;
while (!empty) {
var direction = Math.floor(Math.random() * 2);
if (direction === 1) {
var X = Math.floor(Math.random() * (dim - boatlen));
var Y = Math.floor(Math.random() * dim);
for (var i = 0; i < dim; i++) {
if (tab[X][Y + i] == 0) {
empty = true;
} else {
empty = false;
}
}
} else {
var X = Math.floor(Math.random() * dim);
var Y = Math.floor(Math.random() * (dim - boatlen));
for (var k = 0; k < dim; k++) {
if (tab[X + k][Y] == 0) {
empty = true;
} else {
empty = false;
}
}
}
}
shiplocations(numbships, boatlen, direction, X, Y);
}
}
The last function I call is the fucntion that inserts a ship on a specific location. It requires the number of ships, the boat's length, their direction and the coordinates.
function shiplocations(numbships, boatlen, direction, X, Y) {
for (var k = 0; k < numbships; k++) {
for (var i = 0; i < boatlen; i++) {
if (direction === 1) {
tab[X][Y + i] = boatlen;
} else if (direction != 1) {
tab[X + i][Y] = boatlen;
}
}
}
}
I'd really appreciate youre help, thank you.

I haven't debugged your code, but this sounds like an index vs count problem. When you have four items and you loop through them, the indexes are 0, 1, 2, 3 for items 1, 2, 3, & 4. Most likely you are trying to reference item nbr 4 but it's going to be at index 3 (the 4th index). There will be nothing at index 4 (undefined). Try starting your loops at i = 1 instead of i = 0 or better yet start your items at zero instead of 1.

Related

Failing leet code next-permutation test cases but works on local system

I was attempting the leet-code problem next permutation and here's my js soln.
/**
* #param {number[]} nums
* #return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function(nums) {
for(let i=nums.length-1;i>=0;i--){
if(nums[i]>nums[i-1]){
var x= [...nums.slice(0,i-1),nums[i],nums[i-1]]
console.log(x)// <- This gives a different value as compared to
return x// the returned value
}
}
return nums.reverse()
};
The issue is that I am pretty much failing every test case on leetcode and the printed values are absolutely correct whereas the returned values are incorrect. It gets weirder as it runs exactly as expected on my local system with node.js.
Is this an issue with leetcode? I'd really appreciate if someone could try running this on leetcode on their local system.
So for each number sequence, we need to find the next bigger one by swapping digits. That's awesome lets try. The hardest part was to define the algorithm. Here's how I did it:
/*
Instruction
start with 2nd digit from right
swap with next smallest to the right
if result is bigger than exit that's the solution
start with 3rd digit from right
if exists, swap with next smallest to the right, sort to the right. solution
start with 4rd digit from right
if exists, swap with next smallest to the right, sort to the right. solution
return first number (minimal)
*/
And here's my solution:
/**
* #param {number[]} nums
* #return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function (nums) {
function swap(index1, index2) {
var temp = nums[index1]
nums[index1] = nums[index2]
nums[index2] = temp;
}
function next_bigger_from(pos) {
var current = nums[pos];
result = -1;
var min = Infinity;
for (var i = pos + 1; i < len; i++) {
if (nums[i] > current && nums[i] < Infinity) {
result = i;
min = nums[i];
}
}
return result;
}
function sort_from(pos) {
for (var i = pos; i < len - 1; i++) {
for (var j = i + 1; j < len; j++) {
if (nums[i] > nums[j]) {
swap(i, j)
}
}
}
}
var len = nums.length;
if (len < 2) {
console.log("" + nums)
return;
}
var rotator = 2; // from right
while (rotator <= len) {
var pos = len - rotator;
var pos2 = next_bigger_from(pos);
if (pos2 == -1) {
rotator += 1;
continue;
}
swap(pos, pos2);
sort_from(pos+1);
console.log("" + nums)
return;
}
nums = nums.sort();
console.log("" + nums)
return;
};
nextPermutation([1, 2, 3])
nextPermutation([3, 2, 1])
nextPermutation([1, 1, 5])
var nums = [1, 3, 5, 7];
for (var i = 0; i < 24; i++) {
nextPermutation(nums)
}
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
So what is wrong with the following solution by the OP? It doesn't change the array nums but rather returns an array x. This is why the second test (of the 4 digits sequence) fails for your code. By the way, even if I try nums = nextPermutation(nums) for the second test the results are still wrong.
/**
* #param {number[]} nums
* #return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function(nums) {
for (let i = nums.length - 1; i >= 0; i--) {
if (nums[i] > nums[i - 1]) {
var x = [...nums.slice(0, i - 1), nums[i], nums[i - 1]]
console.log("" + x) // <- This gives a different value as compared to
return x // the returned value
}
}
console.log("" + nums.reverse()) // added for verbosity
return nums.reverse()
};
nextPermutation([1, 2, 3])
nextPermutation([3, 2, 1])
nextPermutation([1, 1, 5])
var nums = [1, 3, 5, 7];
for (var i = 0; i < 24; i++) {
nextPermutation(nums)
}

Having issues trying to solve N Rook problem . Always get n*n solution and not N factorial

I'm trying to get N ways of solves a N rook problem. The issue I am having is currently, I seem to get n*n solutions while it needs to be N! . Below is my code, I have written it in simple loops and functions, so it's quite long. Any help would be greatly appreciated
Note: Please ignore case for n = 2. I get some duplicates which I thought I would handle via JSON.stringify
var createMatrix = function (n) {
var newMatrix = new Array(n);
// build matrix
for (var i = 0; i < n; i++) {
newMatrix[i] = new Array(n);
}
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
newMatrix[i][j] = 0;
}
}
return newMatrix;
};
var newMatrix = createMatrix(n);
// based on rook position, greying out function
var collision = function (i, j) {
var col = i;
var row = j;
while (col < n) {
// set the row (i) to all 'a'
col++;
if (col < n) {
if (newMatrix[col][j] !== 1) {
newMatrix[col][j] = 'x';
}
}
}
while (row < n) {
// set columns (j) to all 'a'
row++;
if (row < n) {
if (newMatrix[i][row] !== 1) {
newMatrix[i][row] = 'x';
}
}
}
if (i > 0) {
col = i;
while (col !== 0) {
col--;
if (newMatrix[col][j] !== 1) {
newMatrix[col][j] = 'x';
}
}
}
if (j > 0) {
row = j;
while (row !== 0) {
row--;
if (newMatrix[i][row] !== 1) {
newMatrix[i][row] = 'x';
}
}
}
};
// checks position with 0 and sets it with Rook
var emptyPositionChecker = function (matrix) {
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < matrix.length; j++) {
if (matrix[i][j] === 0) {
matrix[i][j] = 1;
collision(i, j);
return true;
}
}
}
return false;
};
// loop for every position on the board
loop1:
for (var i = 0; i < newMatrix.length; i++) {
var row = newMatrix[i];
for (var j = 0; j < newMatrix.length; j++) {
// pick a position for rook
newMatrix[i][j] = 1;
// grey out collison zones due to the above position
collision(i, j);
var hasEmpty = true;
while (hasEmpty) {
//call empty position checker
if (emptyPositionChecker(newMatrix)) {
continue;
} else {
//else we found a complete matrix, break
hasEmpty = false;
solutionCount++;
// reinitiaze new array to start all over
newMatrix = createMatrix(n);
break;
}
}
}
}
There seem to be two underlying problems.
The first is that several copies of the same position are being found.
If we consider the case of N=3 and we visualise the positions by making the first rook placed red, the second placed green and the third to be placed blue, we get these three boards:
They are identical positions but will count as 3 separate ones in the given Javascript.
For a 3x3 board there are also 2 other positions which have duplicates. The gets the count of unique positions to 9 - 2 - 1 -1 = 5. But we are expecting N! = 6 positions.
This brings us to the second problem which is that some positions are missed. In the case of N=3 this occurs once when i===j==1 - ie the mid point of the board.
This position is reached:
This position is not reached:
So now we have the number of positions that should be found as 9 - 2 - 1 - 1 +1;
There appears to be nothing wrong with the actual Javascript in as much as it is implementing the given algorithm. What is wrong is the algorithm which is both finding and counting duplicates and is missing some positions.
A common way of solving the N Rooks problem is to use a recursive method rather than an iterative one, and indeed iteration might very soon get totally out of hand if it's trying to evaluate every single position on a board of any size.
This question is probably best taken up on one of the other stackexchange sites where algorithms are discussed.

Why does a tetris piece fall all at once instead of one at a time?

I am making tetris in JS. When making a block fall, it makes the block reach the bottom of the screen in one draw instead of slowly approaching the bottom. I tried creating a variable that stores the changes to be made so that it only looks at the current board, but no luck. After checking whether the output variable is == to the board, it seems like the board is changing after all, as it returns true. What's going on?
EDIT: I have successfully made a shallow copy of the array. It still falls to the bottom immediately, though. What's going on?
var data = [];
function array(x, text) {
var y = [];
for (var i = 0; i < x-1; i++) {y.push(text);}
return y;
}
for (var i=0; i<20; i++){data.push(array(10, "b"));}
function draw(){
var j;
var i;
var dataOut = [...data];
for (i = 0; i < data.length - 1; i++){
for (j = 0; j < data[i].length; j++){
if (data[i][j] == "a" && data[i + 1][j] == "b" && i < data.length - 1) {
dataOut[i][j] = "b";
dataOut[i + 1][j] = "a";
}
}
}
data = dataOut;
}
data[0][4] = 'a';
draw();
console.log(data);
In JavaScript, Arrays and Objects are passed by reference. So when you do this:
var dataOut = data;
Both of these references point to the same Array. You could clone the Array every time:
var dataOut = JSON.parse(JSON.stringify(data));
Or simply revert your loop, to go from the bottom to the top. I took the liberty of renaming the variables to make this more clear. Try it below:
var chars = {empty: '.', block: '#'},
grid = createEmptyGrid(10, 20);
function createEmptyGrid(width, height) {
var result = [], x, y;
for (y = 0; y < height; y++) {
var row = [];
for (x = 0; x < width; x++) {
row.push(chars.empty);
}
result.push(row);
}
return result;
}
function draw() {
var x, y;
for (y = grid.length - 1; y > 0; y--) {
for (x = 0; x < grid[y].length; x++) {
if (grid[y][x] === chars.empty && grid[y - 1][x] === chars.block) {
grid[y][x] = chars.block;
grid[y - 1][x] = chars.empty;
}
}
}
}
// Just for the demo
var t = 0, loop = setInterval(function () {
draw();
if (grid[0].includes(chars.block)) {
clearInterval(loop);
grid[9] = 'GAME OVER!'.split('');
}
document.body.innerHTML = '<pre style="font-size:.6em">'
+ grid.map(row => row.join(' ')).join('\n')
+ '</pre>';
if (t % 20 === 0) {
grid[0][Math.floor(Math.random() * 10)] = chars.block;
}
t++;
}, 20);

Having trouble displaying results correctly after changing the value of an Ace from 11 to 1 in a blackjack simulation

This is the first time I've written anything beyond a few simple lines in javascript. I know similar questions have been asked before because I've looked at a lot of them. I still can't seem to figure out what I'm doing wrong though. I am attempting to make a blackjack game simulation. I've almost got it except I keep running into problems when I need to change the value of an ace from 11 to 1. When I need to change the value of an ace from 11 to 1, it seems to only display the last player's results. Here's the script in it's entirety:
function cardShuffle(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function add(a, b) {
return a + b;
}
function contains(arr, obj) {
var i = 0;
for (;i < arr.length;i++) {
if (arr[i] === obj) {
return true;
}
}
return false;
}
function blackjack() {
var spades = "\u2660";
var clubs = "\u2663";
var hearts = "\u2665";
var diamonds = "\u2666";
var dealer = "Dealer";
var player = "Player";
var table = [player, dealer];
var suits = [hearts, clubs, diamonds, spades];
var deck = [];
// create a deck of cards
x = 0;
for (;x < suits.length; x++) {
var cards = ["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"];
i = 0;
for (;i < cards.length; i++) {
deck.push(cards[i] + suits[x]);
}
}
i = 0;
for (;i < table.length; i++) {
var players = table[i];
var cardsToDeal = 1;
var cardsHeld = [];
var sum = [];
aces = [];
var result;
for (;0 < cardsToDeal;) {
// get a random card from the deck
var index = cardShuffle(0, deck.length - 1);
var card = deck[index];
// give the card to the player
cardsHeld.push(card);
// remove the card from the deck
deck.splice(index, 1);
// strip the suit from the card and get the value
var value = card.substring(0, card.length - 1);
if (value == "J" || (value == "Q" || value == "K")) {
value = 10;
} else {
if (value == "A") {
value = 11;
// put aces into a separate array
aces.push(value);
} else {
value = Number(value);
}
}
// put the value of the card into the sum array
sum.push(value);
// store the sum of the value in the total variable
var total = sum.reduce(add, 0);
/*
This is where I think the problem is.
It works if the last player's hand is greater than 21 and contains an ace.
But if the first players hand has an ace and is greater than 21
only those result are shown in console.log. I don't know why.
*/
if (total > 21 && contains(sum, 11)) {
var i = sum.indexOf(11);
if (i !== -1) {
sum[i] = 1;
}
total = sum.reduce(add, 0);
}
if (total >= 17 && total <= 21) {
result = Number(total);
}
if (total >= 17) {
cardsToDeal--;
}
}
console.log(players, cardsHeld, sum, total);
}
}
blackjack();
On this line:
for (;i < table.length; i++) {
... you use a variable i for a loop. But inside this loop, you redefine that variable, and change its value:
var i = sum.indexOf(11);
which results in this kind of behavior:
If you just change that variable's name to something else, it seems to work fine:
if (total > 21 && contains(sum, 11)) {
var index = sum.indexOf(11);
if (index !== -1) {
sum[index] = 1;
}
total = sum.reduce(add, 0);
}
Be careful about variable scopes when using the var keyword, they are not limited to blocks -unlike let- but to functions (and be sure to add a var in front of the first definition, to avoid making it global). Also, just a piece of advice. for loops are generally used when you know how many iterations you're going to do. This:
for (;0 < cardsToDeal;) { /*...*/ }
would be better with a while loop.
When you check for Aces, you declare i again. This changes the value of i in your table loop. Change the the second var i to var ii and you should be good. To better understand this, you can look up more about Javascript scope.
if (total > 21 && contains(sum, 11)) {
var ii = sum.indexOf(11); // This is what changed
if (ii !== -1) {
sum[ii] = 1;
}
total = sum.reduce(add, 0);
}

Randomize frames with no repeats with html5 javascript

Super noob question here. I have the code below from an as3 project below where frame numbers are randomized then clicking a sprite (next) will move to the next random frame. I am having trouble figuring out what else I need to do to convert it to javascript. Can anyone help me out or point me in the right direction? TIA!
var sortedNumbers:Array = [];
for(var i:int = 1; i < 21; i++)
{
sortedNumbers.push(i);
}
var unsortedNumbers:Array = sortedNumbers.slice();
while(sortedNumbers.join() == unsortedNumbers.join())
{
unsortedNumbers.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
this.start.addEventListener("click", f_nextRE.bind(this));
function f_nextRE() {
if(index == 20) {
gotoAndStop (22);
}
else {
gotoAndStop (unsortedNumbers [index] + 1);
index +=1;
}
}
So it took me a few days but I found my answer (a combination of several sources many on this site)... Posting it here to help others...
//create array
var shuffledFrames = [];
//fill array
for (var i = 1; i <= 35; i++) {
shuffledFrames.push(i);
}
//shuffle array
function shuffle(a) {
var 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;
}
}
//run shuffle function
shuffle(shuffledFrames);
//function to call next random frame then repeat when reaching the end.
function f_next()
{
if (shown == 1){
if (nextF == 35) {
nextF = 0;
}
else {
nextF += 1;
}
this.gotoAndStop (shuffledFrames [nextF]);
}
}

Categories