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.
Related
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>
I am new to Angular. Here I am trying to format JSON data being displayed on a table. Here is what I am trying to achieve, for empty rows, instead of being blank , I fill them with a hyphen, values greater than 25 I fill there individual cells background with red color, values between 20 and 25 i fill them with yellow color, but for some weird reason my table is not being formatted completely, it is like it is not detecting the ngAfterViewInit() function, also when i try to get the average of all the columns i am getting the result as NaN for all columns.
My component.ts file
#ViewChild('myTable', {static: false}) myTable: ElementRef;
ngAfterViewInit() {
var table = this.myTable.nativeElement;
var row;
var cell;
var j = 1;
var r = 0;
var t = 0;
//console.log(table);
if (table !== null) {
while (row = table.rows[r++]) {
var c = 0;
while (cell = row.cells[c++]) {
var cellValue = cell.innerHTML;
//cell.innerHTML='[Row='+r+',Col='+c+']'; // do sth with cell
if (c === 5 && cellValue > 25) {
cell.style.background="#FF0000";
} else if (c === 5 && cellValue >= 10 && cellValue < 25) {
cell.style.background="#FFFF00";
}
}
}
//getting the average value of each column
var colL = table.rows.length - 1;
//console.log(table.rows[1].cells.length);
for (j = 1; j < table.rows[1].cells.length; j++) {
var sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
if (i < colL) {
//console.log(table.rows[i].cells[1].innerHTML);
if (Number.isInteger(parseInt(table.rows[i].cells[j].innerHTML)) === true) {
sumVal = sumVal + parseFloat(table.rows[i].cells[j].innerHTML);
} else {
table.rows[i].cells[j].value = "-";
table.rows[i].cells[j].style.backgroundColor = "#FFFF00";
}
}
// console.log(table.rows[colL].cells[table.rows.length - 1].innerHTML);
}
//Setting the last cell with the avirrage value
if (table.rows[colL].cells[j] !== table.rows[colL].cells[table.rows[1].cells.length - 2]) {
var ans = (sumVal / (table.rows.length - 2)).toFixed(2);
table.rows[colL].cells[j].innerHTML = ans;
} else
table.rows[colL].cells[j].innerHTML = sumVal;
//Taking out all cells with zore totals
if (parseFloat(ans) === 0) {
for (t = 0; t <= colL; t++) {
table.rows[t].cells[j].style.display = 'none';
}
}
}
}
}
}
My beginning of the Table
<div class="panel-body" >
<div class="table-responsive">
<table class="table table-hover" #myTable>
<thead>
My beginning of the rows
<tr class="even gradeC" style="text-align:center" ng-repeat="home in homeurban"
*ngFor="let home of homeurban">
<td class="infos" style="position: absolute; top: auto; width: 100.5px;">{{home.teamNumber}}</td>
What I am doing wrong?
Thanks in advance
I've got a small web app in development to simulate the Ising model of magnetism. I've found that the animation slows down considerably after a few seconds of running, and it also doesn't loop after 5 seconds like I want it to with the command:
setInteval(main, 500)
I've added start and stop buttons. When I stop the animation, and then restart it, it begins fresh at the usual speed, but again slows down.
My question is: what steps can I take to troubleshoot and optimize the performance of my canvas animation? I hope to reduce or mitigate this slowing effect.
JS code:
window.onload = function() {
var canvas = document.getElementById("theCanvas");
var context = canvas.getContext("2d");
var clength = 100;
var temperature = 2.1;
var playAnim = true;
canvas.width = clength;
canvas.height = clength;
var imageData = context.createImageData(clength, clength);
document.getElementById("stop").addEventListener("click",function(){playAnim=false;});
document.getElementById("start").addEventListener("click",function(){playAnim=true;});
function init2DArray(xlen, ylen, factoryFn) {
//generates a 2D array of xlen X ylen, filling each element with values defined by factoryFn, if called.
var ret = []
for (var x = 0; x < xlen; x++) {
ret[x] = []
for (var y = 0; y < ylen; y++) {
ret[x][y] = factoryFn(x, y)
}
}
return ret;
}
function createImage(array, ilen, jlen) {
for (var i = 0; i < ilen; i++) {
for (var j = 0; j < jlen; j++) {
var pixelIndex = (j * ilen + i) * 4;
if (array[i][j] == 1) {
imageData.data[pixelIndex] = 0; //r
imageData.data[pixelIndex+1] = 0; //g
imageData.data[pixelIndex+2] = 0; //b
imageData.data[pixelIndex+3] = 255; //alpha (255 is fully visible)
//black
} else if (array[i][j] == -1) {
imageData.data[pixelIndex] = 255; //r
imageData.data[pixelIndex+1] = 255; //g
imageData.data[pixelIndex+2] = 255; //b
imageData.data[pixelIndex+3] = 255; //alpha (255 is fully visible)
//white
}
}
}
}
function dU(i, j, array, length) {
var m = length-1;
//periodic boundary conditions
if (i == 0) { //top row
var top = array[m][j];
} else {
var top = array[i-1][j];
}
if (i == m) { //bottom row
var bottom = array[0][j];
} else {
var bottom = array[i+1][j];
}
if (j == 0) { //first in row (left)
var left = array[i][m];
} else {
var left = array[i][j-1];
}
if (j == m) { //last in row (right)
var right = array[i][0];
} else {
var right = array[i][j+1]
}
return 2.0*array[i][j]*(top+bottom+left+right); //local magnetization
}
function randInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
var myArray = init2DArray(clength, clength, function() {var c=[-1,1]; return c[Math.floor(Math.random()*2)]}); //creates a 2D square array populated with -1 and 1
function main(frame) {
if (!playAnim){return;} // stops
window.requestAnimationFrame(main);
createImage(myArray, clength, clength);
context.clearRect(0,0,clength,clength);
context.beginPath();
context.putImageData(imageData,0,0);
for (var z = 0; z < 10*Math.pow(clength,2); z++) {
i = randInt(clength-1);
j = randInt(clength-1);
var deltaU = dU(i, j, myArray, clength);
if (deltaU <= 0) {
myArray[i][j] = -myArray[i][j];
} else {
if (Math.random() < Math.exp(-deltaU/temperature)) {
myArray[i][j] = -myArray[i][j];
}
}
}
}
var timer = setInterval(main, 500);
}
Every time I click on a cell in a grid, it logs an array of [rows,column] of the cell into a variable, either bla (for black) or whi (for white). However, the next time I click on a cell, it changes the variable. For example, I click on a cell and variable whi is [1,2] then I click on another cell, variable bla is [2,2] and after that, I click on a third cell and variable whi is changed from [1,2] (from the original click) to [3,2]. (I made up random numbers for this). I want to create two 2D arrays, one for the variable bla and one for the variable whi. Using my example, one of the 2D arrays should be [[1,2],[3,2]] (for the white cells) and the other one should be [[2,2]] (for the black cells)
Test out the code:
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]; //I want to log the array for whi into a 2D array
console.log("white coord is "+whi);
} else {
var bla=[row,col]; //I want to log this array into another 2D array
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>
Initialize whi and bla as arrays and push [row,col] to them - see demo below:
var white = true;
var whi = [];
var bla = [];
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) {
whi.push([row, col]);
} else {
bla.push([row, col]);
}
$td.data('clicked', true);
$td.css('background-color', white ? 'white' : 'black');
white = !white;
});
$('#getarr').click(function(){
console.log("white arr: ", whi);
console.log("black arr: ", bla);
});
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>
<button id="getarr">Get array</button>
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