Random boxes in a grid JavaScript - javascript

I created a grid with random boxes, yellow and one red.
The problem is that when I refresh the page sometimes the red box doesn't appear, is hidden somewhere, I guess under a yellow box. Also, sometimes even the yellow boxes are not all displayed.
I guess there's a problem in the loop to create them?
var grid = document.getElementById("grid-box");
for (var i = 1; i <= 100; i++) {
var square = document.createElement("div");
square.className = 'square';
square.id = 'square' + i;
grid.appendChild(square);
}
var obstacles = [];
while (obstacles.length < 10) {
var randomIndex = parseInt(99 * Math.random());
if (obstacles.indexOf(randomIndex) === -1) {
obstacles.push(randomIndex);
document.getElementById('square' + randomIndex).style.backgroundColor = 'yellow';
}
}
var playerOne = [];
while (playerOne.length < 1) {
var randomIndex = parseInt(99 * Math.random());
if (playerOne.indexOf(randomIndex) === -1) {
playerOne.push(randomIndex);
document.getElementById('square' + randomIndex).style.backgroundColor = 'red';
}
}
#grid-box {
width: 400px;
height: 400px;
margin: 0 auto;
font-size: 0;
position: relative;
}
#grid-box>div.square {
font-size: 1rem;
vertical-align: top;
display: inline-block;
width: 10%;
height: 10%;
box-sizing: border-box;
border: 1px solid #000;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div id="grid-box"></div>

You have to change 2 things:
1. initial value of i should be 0 when you create squares
2. when you make red box then
replace
if (playerOne.indexOf(randomIndex)
with
if (playerOne.indexOf(randomIndex) === -1 && obstacles.indexOf(randomIndex) === -1) {
Here is the final code:
var grid = document.getElementById("grid-box");
// create 100 squares
for (var i = 0; i < 100; i++) { // first change
var square = document.createElement("div");
square.className = 'square';
square.id = 'square' + i;
grid.appendChild(square);
}
var obstacles = [];
while (obstacles.length < 10) {
var randomIndex = parseInt(99 * Math.random());
if (obstacles.indexOf(randomIndex) === -1) {
obstacles.push(randomIndex);
document.getElementById('square' + randomIndex).style.backgroundColor = 'yellow';
}
}
var playerOne = [];
while (playerOne.length < 1) {
var randomIndex = parseInt(99 * Math.random());
if (playerOne.indexOf(randomIndex) === -1 && obstacles.indexOf(randomIndex) === -1) { // second change
playerOne.push(randomIndex);
document.getElementById('square' + randomIndex).style.backgroundColor = 'red';
}
}
It is because, when randomIndex would be zero(0), then you are searching element whose id is "square0" and it is not available because your for loop starts runs from 1 to 100.

Math.random() would sometimes return 0, but your ids are starting from 1 eg: 'square1', there is no 'square0' div.
Make your loop starts from 0:
for (var i = 0; i < 100; i++){
// Code here
}

Related

Game of life issue with setTimeOut and mode selection

A function defined in setTimeOut only runs once in certain situations
I set up 3 inputs in ComboBox by which the user could set the grid size in the game. Selecting a value changes the rows and cols variables respectively, and then reboots the game by calling the init function.
The program starts normally, when I choose a different size the timer does not run the game more than once. When I change the size again it does work. If for example I change the sizes 6 times the game will only work in 3 of the times.
/* Game Of Life Application */
/* ------------------------ */
// initialize global variables
var rows = 55;
var cols = 140;
//initialize 2dim arrays
var arr;// current generation array
var nextArr; // next generation array
var mode = 0; //game current mode
var timeInMS = 40;
var timer;
//buttons selectors
var randomBtn = document.getElementById("randomBtnId");
var startBtn = document.getElementById("startBtnId");
var clearBtn = document.getElementById("clearBtnId");
var gridSize = document.getElementById("sizeId");
var container = document.getElementById("container");
function remove() {
let tb = document.querySelector("table");
tb.outerHTML = "";
}
gridSize.addEventListener("change",function(e) {
remove();
if (this.value === "Small") {
cols = 80;
rows = 20;
}
else if (this.value === "Medium") {
cols = 126;
rows = 34;
}
else {
cols = 140;
rows = 55;
}
timer = 0;
init();
});
//update the visual grid according to the states of the cell - live or dead.
function update() {
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
var cell = document.getElementById(i + "_" + j);
if (arr[i][j] === 0) {
cell.setAttribute("class", "dead");
} else {
cell.setAttribute("class", "live");
}
}
}
}
//copy generation 0 array to generation 1. current arr gets the values of next arr
function copyAndResetGrid() {
console.log("in the reset grid");
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
arr[i][j] = nextArr[i][j];
nextArr[i][j] = 0;
}
}
}
//count number of neighbors for every cell - inputs are r - rows , c - columns
function countNeighbors(r, c) {
let rstart = 0, cstart = 0, rend = rows - 1, cend = cols - 1;
let count = 0;
if (r - 1 > 0)
rstart = r - 1;
if (c - 1 > 0)
cstart = c - 1;
if (r + 1 <= rend)
rend = r + 1;
if (c + 1 <= cend)
cend = c + 1;
for (let i = rstart; i <= rend; i++) {
for (let j = cstart; j <= cend; j++) {
if (arr[i][j] === 1)
count++;
}
}
count -= arr[r][c];
if (count < 0)
count = 0;
// console.log("number of live neighbors at : " + r + "," + c + " is : " + count);
return count;
}
// calculate next 2dim array (generation 1) according to gameOfLife rules
function calculateNext() {
let numOfLivesArr = 0;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
let currentMode = arr[i][j];
if (currentMode === 1)
numOfLivesArr++;
let count = countNeighbors(i, j);
if (currentMode === 0 && count === 3) {
nextArr[i][j] = 1;
}
else if (currentMode === 1 && (count < 2 || count > 3)) {
nextArr[i][j] = 0;
}
else {
nextArr[i][j] = currentMode;
}
}
}
// console.log("num of lives next: " + numOfLivesArr);
copyAndResetGrid();
//update();
}
//run game
function run() {
calculateNext();
update();
timer = setTimeout(run, 1000);
}
//populate the array with random values 0/1
function populateArr() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = Math.floor(Math.random() * 2);
if (arr[i][j] === 1) {
let cell = document.getElementById(i + "_" + j);
cell.setAttribute("class", "live");
}
else {
let cell = document.getElementById(i + "_" + j);
cell.setAttribute("class", "dead");
}
}
}
}
function deleteArr() {
}
//clear array - set 0 values for current and next generations arrays
function clear() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = 0;
nextArr[i][j] = 0;
}
}
//mode = 0;
}
function buttonsControl() {
randomBtn.addEventListener("click", function () {
clear();
populateArr();
});
startBtn.addEventListener("click", function () {
if (mode == 1) {
mode = 0;
startBtn.textContent = "Continue";
clearTimeout(timer);
}
else {
mode = 1;
startBtn.textContent = "Pause";
run();
}
});
clearBtn.addEventListener("click", function () {
startBtn.textContent = "Start";
clear();
update();
})
}
//draw table grid in the web page
function drawGrid() {
let grid = document.getElementById("container");
let table = document.createElement("table");
table.setAttribute("class", "center");
for (let i = 0; i < rows; i++) {
let tr = document.createElement("tr");
for (let j = 0; j < cols; j++) {
let cell = document.createElement("td");
cell.setAttribute("id", i + "_" + j);
cell.setAttribute("class", "dead");
tr.appendChild(cell);
cell.addEventListener("click", function () {
if (cell.classList.contains("live")) {
cell.setAttribute("class", "dead");
arr[i][j] = 0;
}
else
cell.setAttribute("class", "live");
arr[i][j] = 1;
});
}
table.appendChild(tr);
}
grid.appendChild(table);
}
//create 2 dim arrays - current and next generations.
function make2DArr() {
console.log("befire create arr !! ");
for (let i = 0; i < rows; i++) {
arr[i] = new Array(cols);
nextArr[i] = new Array(cols);
}
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = 0;
nextArr[i][j] = 0;
}
}
}
//initial game
function init() {
arr = new Array(rows);
nextArr = new Array(rows);
make2DArr();
drawGrid();
buttonsControl();
}
//load init function
window.onload = init();
body {
background-color: rgba(76, 77, 62, 0.514);
}
.center {
margin: auto;
width: 90%;
padding: 0.5rem;
position: relative;
}
#container {
margin: 0;
position: relative;
overflow: auto;
display: flex;
}
table {
border:1px rgb(241, 241, 241) solid;
border-spacing: 0;
position: absolute;
flex:1;
}
.live {
background-color:rgba(0, 0, 0, 0.685);
}
.dead {
background-color:rgba(228, 228, 241, 0.829);
}
td {
border:1px rgb(29, 182, 29) solid;
/* border-radius: 61px;*/
width: 10px;
height: 10px;
}
/* button {
margin-left: 0.5rem;
} */
button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 1rem 2rem;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 0.5rem 0.5rem;
transition-duration: 0.4s;
cursor: pointer;
}
button:hover {
background-color: rgba(144, 180, 145, 0.596);
color: rgb(54, 59, 54)
}
<body>
<div class="center">
<div id="container">
</div>
<button id="startBtnId"><span>Start</span></button>
<button id="clearBtnId"><span>Clear</span></button>
<button id="randomBtnId"><span>Random</span></button>
<select id="sizeId">
<option value="Big">Big</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
</select>
</div>
<script type="text/javascript" src="game.js"></script>
</body>
the timer is work only in even number of mode selection and does not work in odd number of mode selection.
for example , if i changed the mode 4 times : work -> not -> word -> not
Once an option has been selected from the list, init function was called. Within the function I called for 3 functions that build the arrays, initialize the board and create the button events listeners. The solution is to build the arrays and initialize the board without create the buttons event listeners again. so i just calld make2darray and drawgrid functions.

Grid if box has specific class stop JavaScript

I have a grid with a player, yellow box, and obstacles (.ob) and black boxes. I don't want the player to go in the obstacle squares when I click the 'UP' button.
I was thinking to check if the next class has .ob do not go there. Any suggestions?
let moveCounter = 0;
var grid = document.getElementById("grid-box");
for (var i = 1; i <= 50; i++) {
var square = document.createElement("div");
square.className = 'square';
square.id = 'square' + i;
grid.appendChild(square);
}
var obstacles = [];
while (obstacles.length < 20) {
var randomIndex = parseInt(49 * Math.random());
if (obstacles.indexOf(randomIndex) === -1) {
obstacles.push(randomIndex);
var drawObstacle = document.getElementById('square' + randomIndex);
$(drawObstacle).addClass("ob")
}
}
var playerTwo = [];
while (playerTwo.length < 1) {
var randomIndex = parseInt(49 * Math.random());
if (playerTwo.indexOf(randomIndex) === -1) {
playerTwo.push(randomIndex);
var drawPtwo = document.getElementById('square' + randomIndex);
$(drawPtwo).addClass("p-1")
}
};
$('#button_up').on('click', function() {
moveCounter += 1;
$pOne = $('.p-1')
var id = $pOne.attr('id')
var idNumber = +id.slice(6);
var idMove = idNumber - 10
var idUpMove = 'square' + idMove;
$pOne.removeClass('p-1');
$('#' + idUpMove).addClass('p-1');
});
#grid-box {
width: 400px;
height: 400px;
margin: 0 auto;
font-size: 0;
position: relative;
}
#grid-box > div.square {
font-size: 1rem;
vertical-align: top;
display: inline-block;
width: 10%;
height: 10%;
box-sizing: border-box;
border: 1px solid #000;
}
.p-1 {
background-color: yellow;
}
.ob {
background-color: black;
}
<div id="grid-box"></div>
<div class="move">
<button id="button_up">UP</button><br>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
jsFifddle
Use the following code
$('#button_up').on('click', function() {
moveCounter += 1;
$pOne = $('.p-1')
var id = $pOne.attr('id')
var idNumber = +id.slice(6);
var idMove = idNumber - 10
var idUpMove = 'square' + idMove;
if($('#' + idUpMove).hasClass('ob')){
return false;
}
$pOne.removeClass('p-1');
$('#' + idUpMove).addClass('p-1');
});
Here we check the next selected class having ".ob" class if its return true then we stop the process if it returns false then process continues
if($('#' + idUpMove).hasClass('ob')){
return false;
}
Fiddle

How do you avoid unnecessary line spacing in images displayed with JS?

I have a question. I've been working on a new JS game, and have just barely even started, and I ran into a hurdle:
var block = new Array(35);
var blockdata = new Array(35);
var count = 0;
var rand = 0;
while (count <= 35) {
rand = Math.floor((Math.random() * 3) + 1);
if (rand == 1) {
block[count] = "images/t.jpg";
} else {
block[count] = "images/g.jpg";
}
count++;
}
count = 0;
while (count <= 35) {
blockdata[count] = document.createElement("IMG");
blockdata[count].setAttribute("src", block[count]);
blockdata[count].position = "relative";
document.body.appendChild(blockdata[count]);
//inneficient code below XD
if (count == 5) {
var mybr = document.createElement('br');
document.body.appendChild(mybr);
}
if (count == 11) {
var mybr = document.createElement('br');
document.body.appendChild(mybr);
}
if (count == 17) {
var mybr = document.createElement('br');
document.body.appendChild(mybr);
}
if (count == 23) {
var mybr = document.createElement('br');
document.body.appendChild(mybr);
}
if (count == 29) {
var mybr = document.createElement('br');
document.body.appendChild(mybr);
}
count++;
}
#content {
line-height: 10px;
}
<script type="text/javascript" src="http://gc.kis.scr.kaspersky-labs.com/AA4B3110-75F6-C945-9AFA-B001BE396F4E/main.js" charset="UTF-8"></script>
<div id="content">
The game running can be seen here
The images (t.jpg, g.jpg) are put in rows. I do not want a tiny space between the rows, which you could see from the URL above.
I tried using CSS to make it work, but it won't.
Thanks for the help!
Image element is by default inline-block (display: inline-block). This adds this margin at the bottom. You could add margin-bottom: -4px to img, or you can make it display: block, but that would break your layout and you will need to use float: left on image or use some other css like display: flex on images parent.
And ofc, remove <br>
I have a solution, thanks to Kantoci.
I kept all the code the same, but I added some CSS:
img {
margin-bottom: -4px
}
The other CSS code was unnecessary, and all the <div> tags were not required.
It is actually because of <br> tag you are adding.
if you want to break without any space then alternate way is to use
<ul><li> tag.
then in each li you can mention how many blocks needed.
following way can be done:
update style block like this-
<style>
body,
ul,
ul li {
padding: 0px;
margin: 0px;
}
#content {
line-height: 10px;
}
</style>
<body>
<ul id="content">
</ul>
<script>
var block = new Array(35);
var blockdata = new Array(35);
var count = 0;
var rand = 0;
while (count <= 35) {
rand = Math.floor((Math.random() * 3) + 1);
block[count] = rand == 1 ? "images/t.jpg" : "images/g.jpg";
count++;
}
count = 0;
var gap = 1;
var list = "<li>";
while (count <= 35) {
var isLimit = (count > 0 && (5 * gap) + (gap - 1) == count)
list += isLimit ? "<img src=" + block[count] + "></li><li>" : "<img src=" + block[count] + ">";
gap = isLimit ? gap + 1 : gap;
count++;
}
var content = document.getElementById("content");
content.innerHTML = list;
</script>

How to make this memory board game work?

I am trying to make a memory board game. I got the css part of the game done, but how it the JavaScript part suppose to work out. I tried using the codes below. When I click on the box, even if they are the same, the box won't disappear and when it's not the same number, the box doesn't turn back. Also, for my "gamebox", I want to add a picture to be the background. I couldn't get it to work. Can anyone help me. Thanks.
<html>
<style>
#gamebox
{
position: absolute;
top: 100px;
left: 100px;
background-image: url("https://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=&url=http%3A%2F%2Fwww.pokemontimes.it%2Fhome%2F2014%2F10%2Fannunciato-il-pokemon-center-mega-tokyo-in-apertura-a-dicembre%2F%3F%3Drelated&psig=AFQjCNFGPAm9tU9MR4AZJKe1s6F90F8UFg&ust=1454720806721506");
}
div.box
{
position: absolute;
background-color: red;
top: -800px;
left: -800px;
width: 100px;
height: 100px;
text-align: center;
font-size: 30px;
}
div.box:hover
{
background-color: blue;
}
</style>
<div id=gamebox></div>
<div id=boxdiv class=box onclick="clickedBox(this)"></div>
<script>
var squaresize = 100;
var numsquares = 6;
var numClicked = 0;
var firstClicked;
var secondClicked;
var game = [];
for (var i = 0; i < numsquares; i++)
{
game[i] = [];
for (var j = 0; j < numsquares; j++)
{
game[i][j] = Math.floor(Math.random()*5);
makeBox(i, j);
}
}
function theSame(abox, bbox)
{
var boxParts = abox.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
var boxaNum = game[i][j];
var boxParts = bbox.id.split("-");
i = boxParts[1];
j = boxParts[2];
var boxbNum = game[i][j];
return(boxaNum == boxbNum);
}
function nextTurn()
{
if (numClicked != 2)
return;
if (theSame(firstClicked, secondClicked))
{
deleteBox(firstClicked);
deleteBox(secondClicked);
}
else
{
hideBox(firstClicked);
hideBox(secondClicked);
}
numClicked = 0;
}
function hideBox(box)
{
box.innerHTML = "";
box.style.backgroundColor = "red";
}
function deleteBox(box)
{
//really delete the box
box.style.backgroundColor = "";
}
function showBox(box)
{
var boxParts = box.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
box.innerHTML = game[i][j];
box.style.backgroundColor = "black";
box.style.color = "white";
}
function clickedBox(box)
{
showBox(box);
numClicked++;
if (numClicked == 1)
{
firstClicked = box;
return;
}
if (numClicked == 2)
{
secondClicked = box;
}
}
function makeBox(i, j)
{
var boxdiv = document.getElementById("boxdiv");
var newBox = boxdiv.cloneNode(true);
newBox.style.left = i * (squaresize + 5);
newBox.style.top = j * (squaresize + 5);
newBox.style.width = squaresize;
newBox.style.height = squaresize;
newBox.id = 'box-' + i + '-' + j;
var gamebox = document.getElementById("gamebox");
gamebox.appendChild(newBox);
}
</script>
</html>
I think you're not calling nextTurn() anywhere in your code, meaning theSame() is never called, so nothing gets compared to eachother.
Maybe try calling nextTurn() when the numClicked === 2 in the clickedBox() function.

.mousedown() only called once for each element

I am trying to make a chess game. So far i have only made the white pawns moveable (you move them by dragging them to where you want them to go). However, only the first move works. Why does this happen? I use
$(".piece").mousedown(function(){}
, but it is only called once.
The problem is $("#" + tileFn).append($("#" + tileIn).html()); which creates a new piece element, to whom the mousedown handler is not attached.
One solution is to use event deletagation, or instead of creating a new element just move the existing element like
function parent(element) {
var parentID = $(element).parent().attr("ID");
var parentClass = $(element).parent().attr("class");
var parentType = $(element).parent().get(0).nodeName;
if (parentID != null) {
return ("#" + parentID);
} else if (parentClass != null) {
return ("." + parentClass);
} else {
if (parentType.toLowerCase() == "body") {
parentType = document;
return parentType;
} else {
return parentType;
}
}
}
var dimensions = 600; // must be divisible by 8
var tile1 = "<div class='tile tile1' id='";
var tile2 = "<div class='tile tile2' id='";
var end = "'></div>";
var multiplicity = "";
var tileIn = "";
var tileFi = "";
var classes = "";
var color = "";
var type = "";
var possible = [];
$(document).ready(function() {
//setup start
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
row = i * 2 + 1;
column = j * 2 + 1;
$("#container").append(tile1 + row + column + end + tile2 + row + (column + 1) + end);
}
for (var k = 0; k < 4; k++) {
row = i * 2 + 2;
column = k * 2 + 1;
$("#container").append(tile2 + row + column + end + tile1 + row + (column + 1) + end);
}
}
$("#container").css({
height: dimensions,
width: dimensions
});
$(".tile").css({
height: dimensions / 8,
width: dimensions / 8
});
$(".piece").css({
height: dimensions / 8,
width: dimensions / 8
});
$("<div class='b p piece'><img src='bp.icns' height='69'></div>").appendTo("#21, #22, #23, #24, #25, #26, #27, #28");
$("<div class='b r piece'><img src='br.icns' height='69'></div>").appendTo("#11, #18");
$("<div class='b n piece'><img src='bn.icns' height='69'></div>").appendTo("#12, #17");
$("<div class='b b piece'><img src='bb.icns' height='69'></div>").appendTo("#13, #16");
$("<div class='b k piece'><img src='bk.icns' height='69'></div>").appendTo("#14");
$("<div class='b q piece'><img src='bq.icns' height='69'></div>").appendTo("#15");
$("<div class='w p piece'><img src='wp.icns' height='69'></div>").appendTo("#71, #72, #73, #74, #75, #76, #77, #78");
$("<div class='w r piece'><img src='wr.icns' height='69'></div>").appendTo("#81, #88");
$("<div class='w n piece'><img src='wn.icns' height='69'></div>").appendTo("#82, #87");
$("<div class='w b piece'><img src='wb.icns' height='69'></div>").appendTo("#83, #86");
$("<div class='w q piece'><img src='wq.icns' height='69'></div>").appendTo("#84");
$("<div class='w k piece'><img src='wk.icns' height='69'></div>").appendTo("#85");
//setup end
$(".piece").mousedown(function() {
tileIn = parent($(this)).substr(1, 2);
classes = $(this).attr("class");
color = classes.charAt(0);
type = classes.charAt(2);
y = tileIn.charAt(0);
x = tileIn.charAt(1);
//white start
if (color == "w") {
//white pawn start
if (type == "p") {
if (y == "7") {
possible = ["6" + x, "5" + x];
} else {
possible = [(y - 1) + x];
}
return;
}
//white pawn end
//
else if ("a" == "b") {
}
}
//white end
//black start
else {
}
//white end
});
$(".tile").mouseup(function() {
tileFn = $(this).attr("id");
if (jQuery.inArray(tileFn, possible) !== -1 && $(this).is(':empty')) {
$("#" + tileFn).append($("#" + tileIn).contents());
} else {}
possible = [];
});
});
* {
user-drag: none;
-moz-user-select: none;
-webkit-user-drag: none;
}
#container {
margin: 0 auto;
border: 1px solid gray;
}
.tile {
float: left;
}
.tile1 {
background-color: white;
}
.tile2 {
background-color: rgba(0, 0, 0, 0.58);
}
.piece {
padding: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css">
<div id="container"></div>
The selector $(".piece") only selects the fields which has pices on it at the time you execute the statement. You will have to add the function to the fields as the pieces are moved on the board.
So you mouseup function should probably set the call back for the piece on the new field.

Categories