Javascript css class based on random number - javascript

I have a 4x3 matrix where the class is set to blank (white background). I'm using
var rand = Math.floor(Math.random()*2 + 1);
and if its 1, the class is set to one (red background) and if its 2, the class is set to two (blue background). My code is suppose to make 6 links red and 6 links blue with the newgame function, however, sometimes a few of them are still white or there are not exactly 6 red or blue. You might need to refresh (not click new game button) to see what I mean
here it is live: https://dl.dropbox.com/u/750932/iPhone/risk.html
<!DOCTYPE html>
<html>
<head>
<title>RISK</title>
<style type="text/css" media="screen">
a:link, a:visited {color: #eee;border:3px solid #ccc;display:inline-block;margin:3px;text-decoration:none;padding:26px;}
.blank {background:#fff;}
.one {background: #7B3B3B;}
.two {background: #547980;}
#status {color: #eee;padding:1px;text-align:center}
.current {border:3px solid #000;}
p {margin:0 0 15px;padding:0;}
</style>
<script type="text/javascript" charset="utf-8">
var oneTurn = true;
var gameOver = false;
var numMoves = 0;
function newgame()
{
var status = document.getElementById('status');
var one = 0;
var two = 0;
numMoves = 0;
gameOver = false;
oneTurn = true;
status.innerHTML = 'Player One\'s turn';
for(var x = 0; x < 4; x++)
{
for(var y = 0; y < 3; y++)
{
var rand = Math.floor(Math.random()*2 + 1);
if(rand == 1 && one < 7)
{
document.getElementById('a' + x + '_' + y).setAttribute("class", "one");
one++;
console.log("one");
}
else if(rand == 2 && two < 7)
{
document.getElementById('a' + x + '_' + y).setAttribute("class", "two");
two++;
console.log("two");
}
document.getElementById('a' + x + '_' + y).innerHTML = Math.floor(Math.random()*5 + 1);
}
}
console.log(one);
console.log(two);
}
function current(selected)
{
var status = document.getElementById('status');
var value = selected.value;
}
</script>
<meta name="viewport" content="user-scalable=no, width=device-width" />
</head>
<body onload='newgame();'>
<p id="status" class="one">Player One's turn</p>
<br />
<br />
<br />
<br /><br />
<p><input type="button" id="newgame" value="New Game" onclick="newgame();" /></p>
</body>
</html>

Let me offer you a slightly different approach. Represent the board as an array of 12 integers.
Fill the first half of this array with one's and the second half with two's.
Shuffle the array
Loop through the array and update the DOM elements by converting the array index to the corresponding row and column in the matrix
// initialize the array
var board = [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2];
// shuffle the array
for(var j, x, i = board.length; i; j = parseInt(Math.random() * i),
x = board[--i], board[i] = board[j], board[j] = x);
// At this stage one's and two's will be randomly distributed
var row = -1;
for (var i = 0; i < board.length; i++) {
var class = board[i] == 1 ? 'one' : 'two';
var col = i % 4;
if (col == 0) row++;
var box = document.getElementById('a' + col + '_' + row);
if (box != null) {
box.setAttribute('class', class);
box.innerHTML = 1 + Math.floor(Math.random() * 5);
}
}

Read your code again:
if(rand == 1 && one < 7)
...
else if(rand == 2 && two < 7)
Once you roll a red more than six times, or a blue more than six times, your code just does nothing for that square, this is why you end up with white squares.
Try something like this:
if((rand == 1 && one <= 6) || two > 6)
...
else

Related

Paint bucket getting "Maximum Call Stack Size Exceeded" error

This is the code of the paint bucket tool in my drawing app using the p5.js library. The function self.floodFill always get "Maximum Call Stack Size Exceeded" because of recursion and I want to know the way to fix it. I am thinking if changing the function to a no recursion function would help or not. Any help would be appreciated.
function BucketTool(){
var self = this;
//set an icon and a name for the object
self.icon = "assets/bucket.jpg";
self.name = "Bucket";
var d = pixelDensity();
var oldColor;
var searchDirections = [[1,0],[-1,0],[0,1],[0,-1]];
var pixelsToFill = [];
var positionArray = new Array(2);
self.checkBoundary = function(currentX, currentY, localOldColor) {
if (self.getPixelAtXYPosition(currentX,currentY).toString() != localOldColor.toString() || currentX < 0 || currentY < 0 || currentX > width || currentY > height || pixelsToFill.indexOf(currentX+" "+currentY) != -1) {
return false;
}
return true;
};
self.floodFill = function(currentX, currentY, localOldColor, localSearchDirections) {
if (self.checkBoundary(currentX, currentY, localOldColor)){
pixelsToFill.push(currentX+" "+currentY);
} else {
return;
}
for (var i = 0; i < searchDirections.length; i++){
self.floodFill(currentX + searchDirections[i][0], currentY + searchDirections[i][1], localOldColor, localSearchDirections);
}
};
self.getPixelAtXYPosition = function(x, y) {
var colour = [];
for (var i = 0; i < d; i++) {
for (var j = 0; j < d; j++) {
// loop over
index = 4 * ((y * d + j) * width * d + (x * d + i));
colour[0] = pixels[index];
colour[1] = pixels[index+1];
colour[2] = pixels[index+2];
colour[3] = pixels[index+3];
}
}
return colour;
}
self.drawTheNeededPixels = function(){
for(var i = 0; i < pixelsToFill.length; i++){
positionArray = pixelsToFill[i].split(" ");
point(positionArray[0],positionArray[1]);
}
}
self.draw = function () {
if(mouseIsPressed){
pixelsToFill = [];
loadPixels();
oldColor = self.getPixelAtXYPosition(mouseX, mouseY);
self.floodFill(mouseX, mouseY, oldColor, searchDirections);
self.drawTheNeededPixels();
}
};
}
This problem is well documented on the wikipedia page and the shortfalls of the different types of algorithms to perform flood filling. You've gone for the stack-based recursive implementation.
To prevent a stackoverflow — Maximum Call Stack Exceeded — the first step would be to use a data structure. Using queues/stacks rather than having the function call itself.
The code below creates an empty stack where we put a new object containing the x and y where the user has chosen to fill. This is then added to the pixelsToFill array. We then loop the stack until it's completely empty, at which point we are ready to display the filled pixels.
In the while loop we pop an element off the stack and then find its children — the directions up, down, left, right denoted by the searchDirections array you created. If we've not seen the child before and it's within the boundary we add it to the pixelsToFill array and add it to the stack to repeat the process:
self.floodFill = function (currentX, currentY, localOldColor, localSearchDirections) {
let stack = [];
stack.push({ x: currentX, y: currentY });
pixelsToFill.push(currentX + " " + currentY);
while (stack.length > 0) {
let current = stack.pop();
for (var i = 0; i < searchDirections.length; i++) {
let child = {
x: current.x + searchDirections[i][0],
y: current.y + searchDirections[i][1],
localOldColor,
};
if (self.checkBoundary(child.x, child.y, localOldColor)) {
pixelsToFill.push(child.x + " " + child.y);
stack.push(child);
}
}
}
};
This code may stop the stackoverflow but there are still a lot of optimisations that can be made. Once again, it's worth checking out the Wikipedia page and potentially take a look at Span filling.
let bucketTool;
function setup() {
createCanvas(400, 400);
bucketTool = new BucketTool();
}
function draw() {
background(220);
strokeWeight(5);
circle(width / 2, height / 2, 100);
frameRate(1);
bucketTool.draw();
}
function BucketTool() {
var self = this;
//set an icon and a name for the object
// self.icon = "assets/bucket.jpg";
// self.name = "Bucket";
var d = pixelDensity();
var oldColor;
var searchDirections = [
[1, 0],
[-1, 0],
[0, 1],
[0, -1],
];
var pixelsToFill = [];
var positionArray = new Array(2);
self.checkBoundary = function (currentX, currentY, localOldColor) {
if (
self.getPixelAtXYPosition(currentX, currentY).toString() !=
localOldColor.toString() ||
currentX < 0 ||
currentY < 0 ||
currentX > width ||
currentY > height ||
pixelsToFill.indexOf(currentX+" "+currentY) != -1
) {
return false;
}
return true;
};
self.floodFill = function (currentX, currentY, localOldColor, localSearchDirections) {
let stack = [];
stack.push({ x: currentX, y: currentY });
pixelsToFill.push(currentX + " " + currentY);
while (stack.length > 0) {
let current = stack.pop();
for (var i = 0; i < searchDirections.length; i++) {
let child = {
x: current.x + searchDirections[i][0],
y: current.y + searchDirections[i][1],
localOldColor,
};
if (self.checkBoundary(child.x, child.y, localOldColor)) {
pixelsToFill.push(child.x + " " + child.y);
stack.push(child);
}
}
}
};
self.getPixelAtXYPosition = function (x, y) {
var colour = [];
for (var i = 0; i < d; i++) {
for (var j = 0; j < d; j++) {
// loop over
index = 4 * ((y * d + j) * width * d + (x * d + i));
colour[0] = pixels[index];
colour[1] = pixels[index + 1];
colour[2] = pixels[index + 2];
colour[3] = pixels[index + 3];
}
}
return colour;
};
self.drawTheNeededPixels = function () {
for (var i = 0; i < pixelsToFill.length; i++) {
positionArray = pixelsToFill[i].split(" ");
point(positionArray[0], positionArray[1]);
}
};
self.draw = function () {
if (mouseIsPressed) {
pixelsToFill = [];
loadPixels();
oldColor = self.getPixelAtXYPosition(mouseX, mouseY);
self.floodFill(mouseX, mouseY, oldColor, searchDirections);
console.log(pixelsToFill.length);
self.drawTheNeededPixels();
}
};
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>
Shameless plug, but relevant: I've created a blog comparing the different flood fill algorithms using p5.js.

How can I change the order of the box numbers?

The order of the numbers in my box is as follows:
function boxNumbers(){
let boxes = document.querySelectorAll('.box')
boxes.forEach((box,i)=>{
if(String(i).length==1 || (String(i).length==2 && Number(String(i)[0]))%2==0){
//box.innerHTML = `${100-i}, i=${i}`
box.innerHTML = 100-i
}
else{
box.innerHTML = String(Number(`${9-Number(String(i)[0])}${String(i)[1]}`)+ 1)
}
})
}
how can I change it to look like this:
You can use this:
function boxNumbers() {
let boxes = document.querySelectorAll('.box');
let n = Math.sqrt(boxes.length);
[...boxes].reverse().forEach((box, i) => {
box.textContent = i % (n * 2) < n ? i + 1 : i + n - 2*(i % n);
})
}
With the assignment to n you make it a bit more generic -- still assuming your table is square. By reversing the iteration, you eliminate the need for the 100- subtraction. What remains is a formula that detects whether we're on a row with a reverse sequence or not, and adapts the number accordingly. The number "1" will always be in the bottom-right corner:
function boxNumbers() {
let boxes = document.querySelectorAll('.box');
let n = Math.sqrt(boxes.length);
[...boxes].reverse().forEach((box, i) => {
box.textContent = i % (n * 2) < n ? i + 1 : i + n - 2*(i % n);
})
}
// Utility to create the table
function fillTable(table, n) {
for (let i = 0; i < n; i++) {
let row = table.insertRow();
for (let j = 0; j < n; j++) {
let cell = row.insertCell();
cell.className = "box";
}
}
}
// Example run with n=5. Adapt as needed
let n = 5
fillTable(document.querySelector('table'), n);
boxNumbers();
table { border-collapse: collapse }
td { border: 1px solid ; width: 20px; height: 20px; text-align: center }
<table></table>
Here is a function which builds a bi-dimensional array and appends it as a table (row/col) to a dom element. You can adapt it to your template as you wish.
Works with any base number, yours is 5
function buildMatrix(baseNumber){
var flip = false;
var countDownNumber = baseNumber * baseNumber;
var currNumber = countDownNumber;
var matrix = "";
for(i = 0; i < baseNumber; i++) {
if(i !== 0){
currNumber = (flip)? countDownNumber + 1 - baseNumber : countDownNumber;
}
matrix += "<tr>";
for(j = 0; j < baseNumber; j++){
matrix += "<td>" + currNumber + "</td>";
// depending on the direction (flip) we increment or decrement
(flip)? currNumber++ : currNumber--;
countDownNumber--;
}
// change direction at the end of a row
flip = !flip;
matrix += "</tr>";
}
return matrix;
}
var baseSquareNumber = 11; // here you put 5
var matrixHtml = buildMatrix(baseSquareNumber);
document.getElementById("matrix").innerHTML = matrixHtml;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<table id="matrix">
</table>
</body>
</html>

Change the colour of cells with prime numbers in a dynamic table created with javascript

So far I have created the code to generate a table that has the number of cells that is defined by the user. In addition to this, the cells which have the prime numbers in it, must be coloured in a different colour. I have also included a function to find the prime numbers, but the approach I took to create the table, doesn't give me an option to implement the function onto the html body.
I would really appreciate any help.
Here's my code..
<html>
<head>
<style>
table{width: 70%;}
</style>
<script>
const numString= window.prompt("What is the loop maximum.? (between 1 and 500)")
let num=parseInt(numString);
if(num<0 || num>500)
{
window.alert("Warning! Must be between 1 and 500. Setting to default
100")
num=100
}
function isPrime(num)
{
for(var i=2; i< num; i++)
if(num % i ===0) return false;
return num>1;
}
</script>
</head>
<body>
<h1>Javascript Loops and Functions</h1><br>
<script>
document.write("<table border=1>");
let rows = num % 10 >= 0 && num % 10 <= 10 ? num / 10 + 1 : num / 10;
let count = 0;
for (row = 1; row <= rows; row++) {
document.write("<tr>");
for (let i = 1; i <= 10; i++) {
if (count >= num+1) break;
document.write("<td>" + count + "</td>");
count++;
}
document.write("</tr>");
}
document.write("</table>");
</script>
</body>
You can use a CSS class to give colors. For instance prime_true could be the class for prime numbers and prime_false for non-primes.
It is not so good practice to use document.write for such a purpose. So I would suggest to have an empty table element in your HTML, and then use loops to populate that table with rows and cells:
function isPrime(num) {
for(var i=2; i< num; i++)
if(num % i ===0) return false;
return num>1;
}
let table = document.querySelector("table");
for (let line = 1; line <= 500; line += 10) {
let row = table.insertRow();
for (let i = line; i < line + 10; i++) {
let td = row.insertCell();
td.textContent = i;
td.className = "prime_" + isPrime(i);
}
}
table { width: 70%; }
td { border: 1px solid; text-align: center }
.prime_true { background: orange }
.prime_false { background: lightgrey }
<h1>Javascript Loops and Functions</h1><br>
<table></table>
NB: this script should be in a script element that is put below the table element.
for (let i = 1; i <= 10; i++) {
if (count >= num+1) break;
if(isPrime(count)){
document.write("<td style='background-color:red'>" + count + "</td>");
} else {
document.write("<td>" + count + "</td>");
}
count++;
}

LabeledMap and Map equal each other

When I run this in Webstorm, labeledMap and map equal each other and that breaks my paintCanvas(); This is a long shot, and my code is messy, because I've been debugging for hours, and need help. Here is the code:
I am trying to create a pathfinding algorithm. The array "map" represents the array that contains only integers that represent whether each spot of the array represents a wall/start/end/path, and labeledMap converts the wall/start/end to strings, so the paths can be labeled with the number of steps it takes to get there from the start. That way, I can use labeledMap to find the shortest route to get to the end. This may not be the most efficient method, but this is just my way of experimenting with algorithms. But when I ran the program, both labeledMap converted to strings, and that confuses me because I never mentioned it to do that.
Javascript:
const ctx = canvas.getContext('2d');
const cellSize = 10;
const wallPercent = 35;
const colors = ["#FFFFFF", "#283747", "#1ABC9C", "#E74C3C", "#3498DB", "#F7DC6F"]
var map = [];
var labeledMap = []
var start = [];
var end = [];
function setupArray(){
var table = []
var row = []
for(i = 0; i < canvas.height/cellSize; i++){
for(j = 0; j < canvas.width/cellSize; j++){
if(Math.trunc(Math.random()*100) < wallPercent){
row.push(1);
} else{
row.push(0);
}
}
table.push(row);
row = []
}
return table;
}
function selectPoints(){
let startX = Math.floor(Math.random()*map.length);
let startY = Math.floor(Math.random()*map[0].length);
let endX = Math.floor(Math.random()*map.length);
let endY = Math.floor(Math.random()*map[0].length);
if(map[startX][startY] === 0 && map[endX][endY] === 0){
map[startX][startY] = 2;
map[endX][endY] = 3;
} else {
selectPoints();
}
}
function paintCanvas(){
ctx.beginPath();
for(let i = 0; i < map.length; i++){
for(let j = 0; j < map[0].length; j++){
ctx.fillStyle = colors[map[i][j]]
ctx.fillRect(j*cellSize, i*cellSize, cellSize, cellSize);
ctx.fill();
}
}
}
function dijkstraAlgorithm(){
var parsedLocations = [];
var iterationCount = 0;
labeledMap = map;
for(let i = 0; i < map.length; i++){
for(let j = 0; j < map[0].length; j++){
if(map[i][j] === 1){
labeledMap[i][j] = "wall"
} else if(map[i][j] === 2){
labeledMap[i][j] = "start"
start.push(i);
start.push(j)
} else if(map[i][j] === 3){
labeledMap[i][j] = "end"
end.push(i);
end.push(j);
} else {
labeledMap[i][j] = 0;
}
}
}
console.log(map, labeledMap)
parsedLocations.push([0, start[0], start[1]]);
setInterval(function(){
iterationCount += 1;
for(let i = 0; i < parsedLocations.length; i++){
if(parsedLocations[i][0] === iterationCount - 1){
map[parsedLocations[i][1] + 1][parsedLocations[i][2]] = 4;
map[parsedLocations[i][1] - 1][parsedLocations[i][2]] = 4;
map[parsedLocations[i][1]][parsedLocations[i][2] + 1] = 4;
map[parsedLocations[i][1]][parsedLocations[i][2] - 1] = 4;
console.log(map, labeledMap)
}
paintCanvas();
}
}, 250)
}
function initialize(){
map = setupArray();
selectPoints();
paintCanvas();
dijkstraAlgorithm();
}
initialize()
HTML:
<html>
<head>
<title>Pathfinding</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
</head>
<body>
<!--<div id="navbar">
<div id="algorithms-navbar">
<button id="algorithms-header">Pathfinding <span><img src="https://www.flaticon.com/svg/vstatic/svg/25/25243.svg?token=exp=1619464904~hmac=16f5273099cf29e2ef39d65ee1bdf395" alt="Dropdown" class="algorithm-dropdown"></span></button>
<div id="algorithms-body" class="inactive">
<button id="astar-algorithm" class="pathfinding-active">A* Algorithm</button>
</div>
</div>
</div>-->
<canvas id="canvas"></canvas>
<button onclick="initialize()" id="rerunBtn">Rerun</button>
<script src="js/SetupCanvas.js"></script>
</body>
</html>

Detecting 5 in a row

I am making a game of tic tac toe 5 in a row. I have the grid where whenever you click on a square, it records a "coordinate" of [row,column] in the certain color of the dot. I'm currently not sure how to use the 'coordinates' to detect a five in a row of either color and just prints out a message.
Note: If 5 in a row gets tedious with the copy and pasting of previous code or such, a 3 in a row will also work for me and I will just modify it into a 5 in a row. Also when viewing the code snippet below, use the full screen mode.
Code I have so far:
var white=true;
function generateGrid( rows, cols ) {
var grid = "<table>";
for ( row = 1; row <= rows; row++ ) {
grid += "<tr>";
for ( col = 1; col <= cols; col++ ) {
grid += "<td></td>";
}
grid += "</tr>";
}
return grid;
}
$( "#tableContainer" ).append( generateGrid( 10, 10) );
$( "td" ).click(function() {
$(this).css('cursor','default');
var index = $( "td" ).index( this );
var row = Math.floor( ( index ) / 10) + 1;
var col = ( index % 10) + 1;
var $td = $(this);
if ($td.data('clicked'))
return;
if (white===true){
var whi=[row,col];
console.log("white coord is "+whi);
} else {
var bla=[row,col];
console.log("black coord is "+bla);
}
$td.data('clicked', true);
$td.css('background-color', white ? 'white' : 'black');
white = !white;
});
html{
background-color:#7189ea;
}
td {
border: 1px solid;
width: 25px;
height: 25px;
border-radius:100%;
}
table {
border-collapse: collapse;
}
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="tableContainer"></div>
I've written a function that checks whether the last move wins the game. It basically loops the squares in every direction (and backwards) and looks for 5 in a row (the required length of a line).
var board = new Array();
var boardSize = 5;
var requiredLineLength = 5;
for (var r = 0; r < boardSize; r++) {
board[r] = new Array();
for (var c = 0; c < boardSize; c++) {
board[r][c] = 0;
}
}
var lineDirections = [
[0, 1], //horizontal
[1, 0], //vertical
[1, -1], //diagonal 1
[1, 1] //diagonal 2
];
//example usage:
board[0][0] = 1;
board[1][0] = 1;
board[2][0] = 1;
board[3][0] = 1;
board[4][0] = 1;
console.log(checkWin(1, [0, 0]));
// an empty square is marked with 0
// the players are marked with 1 and 2
// pl is the id of the player: either 1 or 2
// lastMove is an array of size 2, with the coordinates of the last move played, for example: [3, 1]
function checkWin(pl, lastMove) {
var boolWon = false;
for (var i = 0; i < lineDirections.length && !boolWon; i++) {
var shift = lineDirections[i];
var currentSquare = [lastMove[0] + shift[0], lastMove[1] + shift[1]];
var lineLength = 1;
while (lineLength < requiredLineLength && legalSquare(currentSquare) && board[currentSquare[0]][currentSquare[1]] === pl) {
lineLength++;
currentSquare[0] += shift[0];
currentSquare[1] += shift[1];
}
currentSquare = [lastMove[0] - shift[0], lastMove[1] - shift[1]];
while (lineLength < requiredLineLength && legalSquare(currentSquare) && board[currentSquare[0]][currentSquare[1]] === pl) {
lineLength++;
currentSquare[0] -= shift[0];
currentSquare[1] -= shift[1];
}
if (lineLength >= requiredLineLength)
boolWon = true;
}
return boolWon;
}
function legalSquare(square) {
return square[0] < boardSize && square[1] < boardSize && square[0] >= 0 && square[1] >= 0;
}
It's not fully tested so let me know if you encounter any problems or if you need any clarification on how this works.

Categories