I have a sliding tile puzzle in Javascript and want to add a 200 ms transition when a tile is moved. I also want to shuffle the tiles upon loading more than they already do (supposed to be 100 times, according to the last lines of my JS code, but this doesn't seem to be very effective).
You can look at all my code here: https://codepen.io/Xjjacobx/pen/LYBbjRL
// First, create a 2D array representing the tiles of the puzzle
var tiles = [
[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, null]
];
// Next, create a function to shuffle the tiles randomly
function shuffleTiles() {
for (let i = tiles.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[tiles[i], tiles[j]] = [tiles[j], tiles[i]];
}
}
// Then, create a function to render the puzzle to the screen
function renderPuzzle() {
for (let i = 0; i < tiles.length; i++) {
for (let j = 0; j < tiles[i].length; j++) {
let tile = tiles[i][j];
let tileElement = document.getElementById(`tile-${i}-${j}`);
if (tile === null)
{
tileElement.style.backgroundImage = "";
} else {
tileElement.style.backgroundImage = `url('https://upload.wikimedia.org/wikipedia/commons/9/9e/Ours_brun_parcanimalierpyrenees_1.jpg')`;
tileElement.style.backgroundPosition = `-${(tile - 1) % 6 * 100}px -${Math.floor((tile - 1) / 6) * 100}px`;
}
}
}
}
// Finally, create event handlers to move the tiles when they are clicked
document.addEventListener("click", function(event) {
let tileElement = event.target;
let tileCoords = tileElement.id.split("-").map(function(x) { return parseInt(x, 10); });
let i = tileCoords[1];
let j = tileCoords[2];
if (tiles[i][j] === null) return;
if (i > 0 && tiles[i - 1][j] === null) {
tiles[i - 1][j] = tiles[i][j];
tiles[i][j] = null;
} else if (i < tiles.length - 1 && tiles[i + 1][j] === null) {
tiles[i + 1][j] = tiles[i][j];
tiles[i][j] = null;
} else if (j > 0 && tiles[i][j - 1] === null) {
tiles[i][j - 1] = tiles[i][j];
tiles[i][j] = null;
} else if (j < tiles[i].length - 1 && tiles[i][j + 1] === null) {
tiles[i][j + 1] = tiles[i][j];
tiles[i][j] = null;
}
renderPuzzle();
});
// Call the shuffle function multiple times to shuffle the tiles more
for (let i = 0; i < 100; i++) {
shuffleTiles();
}
renderPuzzle();
I used ChatGPT to generate my JS and its solutions to the two problems I mentioned above don't work.
Thanks in advance! (EDIT: also, if you have any recommendations of how I can improve my code, please let me know!)
Is this what you want?
// First, create a 2D array representing the tiles of the puzzle
var tiles = [
[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, null]
];
// Then, create a function to render the puzzle to the screen
function renderPuzzle() {
for (let i = 0; i < tiles.length; i++) {
for (let j = 0; j < tiles[i].length; j++) {
let tile = tiles[i][j];
let tileElement = document.getElementById(`tile-${i}-${j}`);
if (tile === null) {
tileElement.style.backgroundImage = "";
} else {
tileElement.style.backgroundImage = `url('https://upload.wikimedia.org/wikipedia/commons/9/9e/Ours_brun_parcanimalierpyrenees_1.jpg')`;
tileElement.style.backgroundPosition = `-${((tile - 1) % 6) * 100}px -${
Math.floor((tile - 1) / 6) * 100
}px`;
}
}
}
}
// Finally, create event handlers to move the tiles when they are clicked
document.addEventListener("click", function (event) {
let tileElement = event.target;
let tileCoords = tileElement.id.split("-").map(function (x) {
return parseInt(x, 10);
});
let i = tileCoords[1];
let j = tileCoords[2];
if (tiles[i][j] === null) return;
if (i > 0 && tiles[i - 1][j] === null) {
tiles[i - 1][j] = tiles[i][j];
tiles[i][j] = null;
} else if (i < tiles.length - 1 && tiles[i + 1][j] === null) {
tiles[i + 1][j] = tiles[i][j];
tiles[i][j] = null;
} else if (j > 0 && tiles[i][j - 1] === null) {
tiles[i][j - 1] = tiles[i][j];
tiles[i][j] = null;
} else if (j < tiles[i].length - 1 && tiles[i][j + 1] === null) {
tiles[i][j + 1] = tiles[i][j];
tiles[i][j] = null;
}
renderPuzzle();
});
function getRandom(min,max){
return Math.floor(Math.random()*max)+min;
};
// Call the shuffle function multiple times to shuffle the tiles more
for (let y = 0; y < tiles.length; y++) {
for (let x = 0; x < tiles[y].length; x++){
let yy = getRandom(0 ,tiles.length-1 )
let xx = getRandom(0 ,tiles[yy].length-1)
let temp = tiles[y][x]
tiles[y][x] = tiles[yy][xx]
tiles[yy][xx] = temp
}
}
renderPuzzle();
I have to write a function switchMaxMin(tab, n) that swaps the maximum element with the minimum element in an n-element array tab. We assume that all elements of the array are distinct (i. e. there are not a few maxima or minima). I don't know how to do this
I started to write the code and I came up with this:
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = tab[0];
var max = tab[0];
document.write("Tablica: ");
for (i = 1; i < tab.length; i++) {
document.write(tab[i] + ", ");
if (min > tab[i]) {
min = tab[i];
}
if (max < tab[i]) {
max = tab[i];
}
}
document.write("<br /><br />Max: " + max);
document.write("<br />Min: " + min);
To swap the elements you have also to store the indices of the max and min elements
if (min > tab[i]) {
min = tab[i];
minIndex = i;
}
if (max < tab[i]) {
max = tab[i];
maxIndex = i;
}
Then you can reassign it by a classical swap function
function swapper(maxInd, minInd) {
let temp = tab[maxInd];
tab[maxInd] = tab[minInd]
tab[minInd] = temp;
}
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = tab[0];
var max = tab[0];
var minIndex = 0;
var maxIndex = 0;
document.write("Tablica: ");
for (let i = 1; i < tab.length; i++) {
document.write(tab[i] + ", ");
if (min > tab[i]) {
min = tab[i];
minIndex = i;
}
if (max < tab[i]) {
max = tab[i];
maxIndex = i;
}
}
swapper(maxIndex, minIndex);
document.write("<br /><br />Max: " + max);
document.write("<br />Min: " + min);
document.write("<br /> After the swap " + tab.join(","));
function swapper(maxInd, minInd) {
let temp = tab[maxInd];
tab[maxInd] = tab[minInd]
tab[minInd] = temp;
}
Just another way to do it, slightly less efficient, but fewer lines of code.
var tab = new Array(6, 4, 65, 34, 67, 89, 45, 7, 35, 79, 23, 56, 87, 12, 38, 9);
var min = Math.min.apply(null,tab);
var minIndex = tab.indexOf(min);
var max = Math.max.apply(null,tab);
var maxIndex = tab.indexOf(max);
var temp = tab[minIndex]
tab[minIndex] = tab[maxIndex]
tab[maxIndex] = temp;
console.log(tab)
I am trying to generate sprial matrix in javascript.
question
Given an integer A, generate a square matrix filled with elements from 1 to A^2 in spiral order.
input : 3
[ [ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ] ]
when input is 4
[ [1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7] ]
my approach is to create 2d array with 0 value and after that they will fill values.
let generateMatrix = function(A) {
let arr = [], counter = 1;
for (let i = 0; i < A; i++) {
let items = []
for (let j = 0; j < A; j++) {
items.push(0)
}
arr.push(items)
}
var spiralMatrix = function(arr) {
if (arr.length > 1) {
for (let i = 0; i < arr[0].length; i++) {
arr[0][i] = counter++;
}
}
return arr
}
return spiralMatrix(arr)
}
console.log(generateMatrix(2))
You could take loops for each edges and loop until no more ranges are avaliable.
function spiral(length) {
var upper = 0,
lower = length - 1,
left = 0,
right = length - 1,
i = 0,
j = 0,
result = Array.from({ length }, _ => []),
value = 1;
while (true) {
if (upper++ > lower) break;
for (; j < right; j++) result[i][j] = value++;
if (right-- < left) break;
for (; i < lower; i++) result[i][j] = value++;
if (lower-- < upper) break;
for (; j > left; j--) result[i][j] = value++;
if (left++ > right) break;
for (; i > upper; i--) result[i][j] = value++;
}
result[i][j] = value++;
return result;
}
var target = document.getElementById('out'),
i = 10;
while (--i) target.innerHTML += spiral(i).map(a => a.map(v => v.toString().padStart(2)).join(' ')).join('\n') + '\n\n';
<pre id="out"></pre>
This bit of code should do what you are trying to.
// This is your Editor pane. Write your JavaScript hem and
// use the command line to execute commands
let generateMatrix = function(A) {
let arr = [],
counter = 1;
for (let i = 0; i < A; i++) {
let items = [];
for (let j = 0; j < A; j++) {
items.push(0);
}
arr.push(items);
}
var spiralMatrix = function(arr) {
let count = 1;
let k = 0; // starting row
let m = arr.length; // ending row
let l = 0; // starting column
let n = arr[0].length; //ending column
while (k < m && l < n) {
// top
for (var i = l; i < n; i++) {
arr[k][i] = count;
count++;
}
k++;
// right
for (var i = k; i < m; i++) {
arr[i][n - 1] = count;
count++;
}
n--;
// bottom
if (k < m) {
for (var i = n - 1; i >= l; i--) {
arr[m - 1][i] = count;
count++;
}
m--;
}
// left
if (l < n) {
for (var i = m - 1; i >= k; i--) {
arr[i][l] = count;
count++;
}
l++;
}
}
return arr;
};
return spiralMatrix(arr);
};
console.log(generateMatrix(4));
This is in some ways the reverse of an answer I gave to another question. We can recursively build this up by slicing out the first row and prepending it to the result of rotating the result of a recursive call on the remaining numbers:
const reverse = a =>
[...a] .reverse ();
const transpose = m =>
m [0] .map ((c, i) => m .map (r => r [i]))
const rotate = m =>
transpose (reverse (m))
const makeSpiral = (xs, rows) =>
xs .length < 2
? [[... xs]]
: [
xs .slice (0, xs .length / rows),
... rotate(makeSpiral (xs .slice (xs .length / rows), xs.length / rows))
]
const range = (lo, hi) =>
[...Array (hi - lo + 1)] .map ((_, i) => lo + i)
const generateMatrix = (n) =>
makeSpiral (range (1, n * n), n)
console .log (generateMatrix (4))
A sharp eye will note that rotate is different here from the older question. transpose (reverse (m)) returns a clockwise rotated version of the input matrix. reverse (transpose (m)) returns a counter-clockwise rotated one. Similarly, here we rotate the result of the recursive call before including it; whereas in the other question we recurse on the rotated version of the matrix. Since we're reversing that process, it should be reasonably clear why.
The main function is makeSpiral, which takes an array and the number of rows to spiral it into and returns the spiraled matrix. (If rows is not a factor of the length of the array, the behavior might be crazy.) generateMatrix is just a thin wrapper around that to handle your square case by generating the initial array (using range) and passing it to makeSpiral.
Note how makeSpiral works with rectangles other than squares:
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 2) //=>
// [
// [ 1, 2, 3, 4, 5, 6],
// [12, 11, 10, 9, 8, 7]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 3) //=>
// [
// [ 1, 2, 3, 4],
// [10, 11, 12, 5],
// [ 9, 8, 7, 6]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 4) //=>
// [
// [ 1, 2, 3],
// [10, 11, 4],
// [ 9, 12, 5],
// [ 8, 7, 6]
// ]
makeSpiral ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 6) //=>
// [
// [ 1, 2],
// [12, 3],
// [11, 4],
// [10, 5],
// [ 9, 6],
// [ 8, 7]
// ]
The other functions -- range, reverse, transpose, and rotate -- are general purpose utility functions for working with arrays or matrices.
Here's one solution.
I keep the current "moving direction" in dx and dy, such that the next matrix element indices are given by x+dx and y+dy.
If the next item is already filled or is out of bounds, I change this direction clockwise. Otherwise, I fill it with the next value.
const size = 6;
const matrix = Array(size).fill().map(() => Array(size).fill(0));
let x = -1;
let y = 0;
let dx = 1;
let dy = 0;
function changeDirection() {
if (dx === 1) {
dx = 0;
dy = 1;
} else if (dy === 1) {
dy = 0;
dx = -1;
} else if (dx === -1) {
dx = 0;
dy = -1;
} else {
dx = 1;
dy = 0;
}
}
for (let i = 0; i < size * size; i++) {
const yNext = y + dy;
const xNext = x + dx;
const nextRow = matrix[yNext] || [];
const nextItemContent = nextRow[xNext];
if (nextItemContent === undefined || nextItemContent > 0) {
changeDirection();
i--;
continue;
}
y = yNext;
x = xNext;
matrix[y][x] = i + 1;
}
const result = document.getElementById('result');
matrix.forEach(row => {
row.forEach(value => {
result.innerHTML += value.toString().padStart(3);
});
result.innerHTML += '\n';
});
<pre id="result"></pre>
I'm calculating the index, each number should go in a linear array
console.clear();
Array.prototype.range = function(a, b, step) {
step = !step ? 1 : step;
b = b / step;
for(var i = a; i <= b; i++) {
this.push(i*step);
}
return this;
};
const spiral = function(dimen) {
"use strict";
const dim = dimen;
const dimw = dim;
const dimh = dim;
var steps = [1, dimh, -1, -dimh];
var stepIndex = 0;
var count = 1;
var countMax = dimw
var dec = 0
var index = 0;
var arr = [];
arr = arr.range(1, dimh * dimw)
const newArr = arr.reduce((coll, x, idx) => {
index += steps[stepIndex]
coll[index-1] = idx+1;
if (count === countMax) {count = 0; stepIndex++; dec++;}
if (dec === 1) {dec = -1; countMax--}
if (stepIndex == steps.length) {stepIndex = 0}
count++;
return coll;
}, []);
var ret = []
while (newArr.length) {
ret.push(newArr.splice(0,dimw))
}
return ret
}
console.log(spiral(3))
console.log(spiral(4))
console.log(spiral(5))
var n=14; // size of spiral
var s=[]; // empty instruction string
function emp() {} // no move
function xpp() {xp++;} // go right
function xpm() {xp--;} // go left
function ypp() {yp++;} // go down
function ypm() {yp--;} // go up
var r=[xpp,ypp,xpm,ypm]; // instruction set
s.push(emp); // push 'no move' (used for starting point)
var c=n-1;
while (c-->0) s.push(r[0]); // push first line - uses a different rule
for (var i=1;i<2*n-1;i++) { // push each leg
c=Math.floor((2*n-i)/2);
while (c-->0) s.push(r[i%4]);
}
var sp=new Array(n); // spiral array
for (var i=0;i<n;i++) sp[i]=new Array(n);
var xp=0; // starting position
var yp=0;
for (var i=0;i<n*n;i++) {
s[i](); // execute next instruction
sp[yp][xp]=i+1; // update array
}
for (var i=0;i<n;i++) console.log(sp[i].toString()); // log to console
This code makes a macro of functions to generate a run sequence, for example:
'right4, down4, left4, up3, right3, down2, left2, up1, right1
and then implements it.
Here is a solution to Spiral Matrix from leetcode, maybe this can help
https://leetcode.com/problems/spiral-matrix/
var spiralOrder = function(matrix) {
if (matrix.length == 0) {
return [];
}
let result = [];
let rowStart = 0;
let rowEnd = matrix.length - 1;
let colStart = 0;
let colEnd = matrix[0].length - 1;
while (true) {
// top
for (let i = colStart; i <= colEnd; i++) {
result.push(matrix[rowStart][i]);
}
rowStart++;
if (rowStart > rowEnd) {
return result;
}
// right
for (let i = rowStart; i <= rowEnd; i++) {
result.push(matrix[i][colEnd]);
}
colEnd--;
if (colEnd < colStart) {
return result;
}
// bottom
for (let i = colEnd; i >= colStart; i--) {
result.push(matrix[rowEnd][i]);
}
rowEnd--;
if (rowEnd < rowStart) {
return result;
}
// left
for (let i = rowEnd; i >= rowStart; i--) {
result.push(matrix[i][colStart]);
}
colStart++;
if (colStart > colEnd) {
return result;
}
}
return result;
};
console.log(
spiralOrder([[2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13], [14, 15, 16]])
);
console.log(spiralOrder([[7], [9], [6]]));
console.log(spiralOrder([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]));
console.log(spiralOrder([[1, 2, 3], [4, 5, 6], [7, 8, 9]]));
Here's my answer using only one for loop -
function matrix(n) {
const arr = [];
let row = 0;
let column = 0;
let counter = 1;
let edge = n - 1;
let leftToRightRow = false;
let topToBottomCol = false;
let rightToLeftRow = false;
let bottomToTopCol = false;
for (i = 0; i < n * n; i++) {
if (column <= edge && !leftToRightRow) {
if (!Array.isArray(arr[row])) {
arr[row] = []; // if array is not present at this index, then insert one
}
arr[row][column] = counter;
if (column == edge) {
row = row + 1;
leftToRightRow = true;
} else {
column = column + 1;
}
counter = counter + 1;
} else if (column === edge && !topToBottomCol) {
if (!Array.isArray(arr[row])) {
arr[row] = []; // if array is not present at this index, then insert one
}
arr[row][column] = counter;
if (row === edge) {
column = column - 1;
topToBottomCol = true;
} else {
row = row + 1;
}
counter = counter + 1;
} else if (column >= 0 && !rightToLeftRow) {
arr[row][column] = counter;
if (column === 0) {
row = row - 1;
rightToLeftRow = true;
} else {
column = column - 1;
}
counter = counter + 1;
} else if (row >= n - edge && !bottomToTopCol) {
arr[row][column] = counter;
if (row === n - edge) {
column = column + 1;
bottomToTopCol = true;
//setting these to false for next set of iteration
leftToRightRow = false;
topToBottomCol = false;
rightToLeftRow = false;
edge = edge - 1;
} else {
row = row - 1;
}
counter = counter + 1;
}
}
return arr;
}
Solution is implemented in C++, but only logic matter then you can do it in any language:
vector<vector<int> > Solution::generateMatrix(int A) {
vector<vector<int>> result(A,vector<int>(A));
int xBeg=0,xEnd=A-1;
int yBeg=0,yEnd=A-1;
int cur=1;
while(true){
for(int i=yBeg;i<=yEnd;i++)
result[xBeg][i]=cur++;
if(++xBeg>xEnd) break;
for(int i=xBeg;i<=xEnd;i++)
result[i][yEnd]=cur++;
if(--yEnd<yBeg) break;
for(int i=yEnd;i>=yBeg;i--)
result[xEnd][i]=cur++;
if(--xEnd<xBeg) break;
for(int i=xEnd;i>=xBeg;i--)
result[i][yBeg]=cur++;
if(++yBeg>yEnd) break;
}
return result;
}
Solition in c#:
For solving this problem we use loops for each moving directions
public IList<int> SpiralOrder(int[][] matrix) {
var result = new List<int>();
var n = matrix[0].Length;
var m = matrix.Length;
var i = 0;
var j = 0;
var x = 0;
var y = 0;
while (true)
{
//left to right moving:
while (x <= n - 1 - i)
{
result.Add(matrix[y][x]);
x++;
}
if (result.Count == n * m)
return result;
x--;y++;
//up to down moving:
while (y <= m - 1 - j)
{
result.Add(matrix[y][x]);
y++;
}
if (result.Count == n * m)
return result;
y--;x--;
//right to left moving:
while (x >= j)
{
result.Add(matrix[y][x]);
x--;
}
if (result.Count == n * m)
return result;
x++;y--;
//down to up moving:
while (y > j)
{
result.Add(matrix[y][x]);
y--;
}
if (result.Count == n * m)
return result;
y++;x++;
i++;
j++;
}
}
Can someone help me understand how to return the total of all the items in the array added together? Here is my code below:
var numbers = [7, 55, 99, 27, 3, 1];
function addThemUp(numeros) {
for (var i = 0; i < numeros.length; i++) {
return numeros[i];
}
}
addThemUp(numbers);
alert(addThemUp);
There are some mistakes in the code in the alert calling, here is the one to do it.
var numbers = [7, 55, 99, 27, 3, 1];
function addThemUp(numeros) {
var total = 0;
for (var i = 0; i < numeros.length; i++) {
total+=numeros[i];
}
return total;
}
var t = addThemUp(numbers);
alert(t);
Add(+) each value in a lopp to a variable and return the summed-variable
var numbers = [7, 55, 99, 27, 3, 1];
function addThemUp(numeros) {
var total = 0;
for (var i = 0; i < numeros.length; i++) {
total += numeros[i];
}
return total;
}
var op = addThemUp(numbers);
alert(op);
Using Array#reduce
var numbers = [7, 55, 99, 27, 3, 1];
function addThemUp(numeros) {
return numeros.reduce(function(a, b) {
return a + b;
});
}
var op = addThemUp(numbers);
alert(op);