Related
i am triying to create a sodoku solve. but I get the following error:
Maximum call stack size exceeded. Please help me.
let board = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9],
];
const possible = function (x, y, n, board) {
for (let i = 0; i < 9; i++) {
if (board[i][y] === n || board[x][i] === n) return false;
}
const x0 = Math.floor(x / 3);
const y0 = Math.floor(y / 3);
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (board[x0 + i][y0 + j] === n) return false;
}
}
return true;
};
The possible function check if we can put n in board[x][y] according to sodoku rules
const solve = function (board) {
for (let x = 0; x < 9; x++) {
for (let y = 0; y < 9; y++) {
for (let n = 1; n < 10; n++) {
if (possible(x, y, n, board)) {
board[x][y] = n;
solve(board)
}
}
board[x][y] = 0
}
}
};
solve(board);
The solve function receive a board and solve it using recursion. The board is passed by reference so the board variable at the global scope is modified.
let puzzle = [
[0, 0, 7, 0, 0, 3, 5, 0, 0],
[6, 0, 5, 4, 0, 8, 3, 0, 2],
[0, 0, 4, 5, 2, 0, 9, 0, 6],
[0, 0, 0, 0, 7, 1, 2, 0, 9],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[8, 0, 9, 2, 3, 0, 0, 0, 0],
[9, 0, 1, 0, 8, 5, 6, 0, 0],
[7, 0, 3, 9, 0, 2, 8, 0, 5],
[0, 0, 8, 7, 0, 0, 1, 0, 0]
];
class Sudoku
{
constructor(puzzle)
{
this.sudoku = puzzle;
}
isPossible(y, x, n)
{
for (let i = 0; i < 9; i++)
{
if (this.sudoku[y][i] == n)
return false;
}
for (let i = 0; i < 9; i++)
{
if (this.sudoku[i][x] == n)
return false;
}
let y0 = (Math.floor(y / 3) * 3);
let x0 = (Math.floor(x / 3) * 3);
for (let i = 0; i < 3; i++)
{
for (let j = 0; j < 3; j++)
{
if (this.sudoku[y0 + i][x0 + j] == n)
return false;
}
}
return true;
}
solve()
{
for (let y = 0; y < 9; y++)
{
for (let x = 0; x < 9; x++)
{
if (this.sudoku[y][x] == 0)
{
for (let n = 1; n <= 9; n++)
{
if (this.isPossible(y, x, n))
{
this.sudoku[y][x] = n;
this.solve();
this.sudoku[y][x] = 0;
}
}
return;
}
}
}
console.table(this.sudoku);
}
}
let s = new Sudoku(puzzle);
s.solve();
This works fine the way it is written. However, debugging shows that after the console.table, the code keeps running and takes the matrix back to its original state. But, the console.table line is never executed again. So, outside of the solve method, this.sudoku is just the original puzzle matrix.
Why is this happening? After the output, what is causing the code to keep running? How come it never goes back to the end (console.table), and how can I stop it once it has actually solved the puzzle?
It is important to see that the console output is reached if and only if there are no if no more open fields in the table (programmatically. matrix elements set to zero).
In any other case the control flow returns from the current function invocation before the output statement is reached
The recursive algorithm dwells on the idea that to solve a given sudoku problem, you pick an open field, pick the first number between 1 and 9 that keeps the tableau consistent with the rules and try to solve this new puzzle by recursively calling the solver. Termination is guaranteed as with each recursive call there is one open field less.
After a recursive call has completed, the choice made immediately before the call is retracted and the remaining possibilities to assign a number to the position are tried, once again ascertaining consistency and recursively calling the solver. This way, all solutions to the original puzzle will be found.
The solver is efficient in the sense that it visits every configuration that does not admit another level of recursion ( ie. which is a solution or a dead end ) only once. There is exactly 1 sequence in which the configuration's positions that are open in the start puzzle will be filled.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="expires" content="0">
<meta http-equiv="cache-control" content="private">
<meta http-equiv="pragma" content="no-cache">
<title>SO - Bitmap (svg)</title>
<!--
-->
<style type="text/css">
body {
background-color: #eee;
}
.board {
display: table;
border: solid 3px black
}
.board > div {
display: table-row;
}
.cell {
width: 16px;
height: 16px;
display: table-cell;
border: solid 1px lightgrey;
padding: 5px;
text-align: center;
vertical-align: middle;
font-size: 80%;
}
.last-square-column {
border-right: solid 2px black;
}
.last-square-row {
border-bottom: solid 2px black;
}
.preset {
color: blue;
background-color: #ddddff;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
let puzzle_orig = [ // The original problem
[0, 0, 7, 0, 0, 3, 5, 0, 0],
[6, 0, 5, 4, 0, 8, 3, 0, 2],
[0, 0, 4, 5, 2, 0, 9, 0, 6],
[0, 0, 0, 0, 7, 1, 2, 0, 9],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[8, 0, 9, 2, 3, 0, 0, 0, 0],
[9, 0, 1, 0, 8, 5, 6, 0, 0],
[7, 0, 3, 9, 0, 2, 8, 0, 5],
[0, 0, 8, 7, 0, 0, 1, 0, 0]
]
;
let puzzle = [ // Multiple solutions
[0, 0, 7, 0, 0, 3, 5, 0, 0],
[6, 0, 5, 4, 0, 8, 3, 0, 2],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 7, 1, 2, 0, 9],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[8, 0, 9, 2, 3, 0, 0, 0, 0],
[9, 0, 1, 0, 8, 5, 6, 0, 0],
[7, 0, 3, 9, 0, 2, 8, 0, 5],
[0, 0, 8, 7, 0, 0, 1, 0, 0]
]
;
class Sudoku
{
constructor(puzzle)
{
this.sudoku = puzzle;
this.base = puzzle.map ( a_row => { return a_row.map ( n_cell => n_cell ); });
this.n_solutions = 0;
}
isPossible(y, x, n)
{
for (let i = 0; i < 9; i++)
{
if (this.sudoku[y][i] == n)
return false;
}
for (let i = 0; i < 9; i++)
{
if (this.sudoku[i][x] == n)
return false;
}
let y0 = (Math.floor(y / 3) * 3);
let x0 = (Math.floor(x / 3) * 3);
for (let i = 0; i < 3; i++)
{
for (let j = 0; j < 3; j++)
{
if (this.sudoku[y0 + i][x0 + j] == n)
return false;
}
}
return true;
}
out () {
let e_body = document.querySelector('body')
, e_board = document.createElement('div')
, e_h = document.createElement('h3')
;
e_h.innerText = `Solution #${this.n_solutions++}`;
e_board.setAttribute('class', 'board');
for (let y = 0; y < 9; y++) {
let e_row = document.createElement('div')
;
for (let x = 0; x < 9; x++) {
let e_cell = document.createElement('div')
;
e_cell.innerText = this.sudoku[y][x];
e_cell.setAttribute('class', 'cell');
if (this.base[y][x] !== 0) {
e_cell.classList.add('preset');
}
if ((x === 2) || (x === 5)) {
e_cell.classList.add('last-square-column');
}
if ((y === 2) || (y === 5)) {
e_cell.classList.add('last-square-row');
}
e_row.append(e_cell);
}
e_board.append(e_row);
}
e_body.append(e_h);
e_body.append(e_board);
} // out
solve()
{
for (let y = 0; y < 9; y++)
{
for (let x = 0; x < 9; x++)
{
if (this.sudoku[y][x] == 0)
{
for (let n = 1; n <= 9; n++)
{
if (this.isPossible(y, x, n))
{
this.sudoku[y][x] = n;
this.solve();
this.sudoku[y][x] = 0;
}
}
return;
}
}
}
this.out();
}
}
let s = new Sudoku(puzzle);
s.solve();
});
</script>
</head>
<body>
</body>
</html>
I will do that this way, simply add a solved test and some loop break...
const Sudoku = (()=>
{
let
grid = null
, solved = false
;
const
nums = [1,2,3,4,5,6,7,8,9]
, isPossible = (row, col, num) =>
{
for (let c in grid) if (grid[row][c] === num) return false
for (let r in grid) if (grid[r][col] === num) return false
row -= row %3
col -= col %3
for (let i=0, c=col; i<3; i++,c++)
for (let j=0, r=row; j<3; j++,r++)
if (grid[r][c] === num) return false
return true
}
, solve = () =>
{
for (let row in grid)
{
if (solved) break
for (let col in grid)
{
if (solved) break
if (grid[row][col] === 0)
{
for (let num of nums)
if (isPossible(row, col, num))
{
grid[row][col] = num
solve()
if (solved) break
grid[row][col] = 0
}
return
} } }
solved = true
};
return (puzzle) =>
{
grid = puzzle
solved = false
solve()
return solved
}
})()
const puzzle =
[ [ 0, 0, 7, 0, 0, 3, 5, 0, 0 ]
, [ 6, 0, 5, 4, 0, 8, 3, 0, 2 ]
, [ 0, 0, 4, 5, 2, 0, 9, 0, 6 ]
, [ 0, 0, 0, 0, 7, 1, 2, 0, 9 ]
, [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
, [ 8, 0, 9, 2, 3, 0, 0, 0, 0 ]
, [ 9, 0, 1, 0, 8, 5, 6, 0, 0 ]
, [ 7, 0, 3, 9, 0, 2, 8, 0, 5 ]
, [ 0, 0, 8, 7, 0, 0, 1, 0, 0 ]
]
let resolved = Sudoku(puzzle)
console.log( resolved ? 'resolved !':'not resolved !','\n' )
console.log(JSON.stringify(puzzle).replaceAll('],[',']\n,['))
// console.table( ) doesn't work on snippet
.as-console-wrapper {max-height: 100% !important;top: 0;}
.as-console-row::after {display: none !important;}
let grid = [[2, 5, 0, 0, 3, 0, 9, 0, 1],
[0, 1, 0, 0, 0, 4, 0, 0, 0],
[4, 0, 7, 0, 0, 0, 2, 0, 8],
[0, 0, 5, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 9, 8, 1, 0, 0],
[0, 4, 0, 0, 0, 3, 0, 0, 0],
[0, 0, 0, 3, 6, 0, 0, 7, 2],
[0, 7, 0, 0, 0, 0, 0, 0, 3],
[9, 0, 3, 0, 0, 0, 6, 0, 4]]
function possible(y, x, n){
for (let i = 0; i < 9; i++){
if (grid[i][x] === n){
return false
}
}
for (let i = 0; i < 9; i++){
if (grid[y][i] === n){
return false
}
}
let xx = (Math.floor(x / 3)) * 3
let yy = (Math.floor(y / 3)) * 3
for (let i = 0; i < 3; i++){
for (let j = 0; j < 3; j++){
if (grid[yy + i][xx + j] === n){
return false
}
}
}
return true
}
function solve(){
for (let y = 0; y < 9; y++){
for (let x = 0; x < 9; x++){
if (grid[y][x] === 0){
for (let n = 1; n < 10; n++){
if (possible(y, x, n)){
grid[y][x] = n
solve()
grid[y][x] = 0
}
}
return
}
}
}
console.log(grid)
}
solve()
It'll do recursions but it will return to the original grid. I did code this in python and it worked. I don't know why it wont work in javascript.
The problem is that your code will reset the solution that it finds. Although it prints it correctly, that output is made before the top-level call of the function returns. By the time it returns, all cells have been reverted to 0.
Your code needs to use the return value from the recursive call, and if it is true, it should stop looking further and certainly not put back a 0. It should instead immediately exit, and tell its own caller that the solution is there.
So:
let grid = [[2, 5, 0, 0, 3, 0, 9, 0, 1],
[0, 1, 0, 0, 0, 4, 0, 0, 0],
[4, 0, 7, 0, 0, 0, 2, 0, 8],
[0, 0, 5, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 9, 8, 1, 0, 0],
[0, 4, 0, 0, 0, 3, 0, 0, 0],
[0, 0, 0, 3, 6, 0, 0, 7, 2],
[0, 7, 0, 0, 0, 0, 0, 0, 3],
[9, 0, 3, 0, 0, 0, 6, 0, 4]]
function possible(y, x, n){
for (let i = 0; i < 9; i++){
if (grid[i][x] === n){
return false
}
}
for (let i = 0; i < 9; i++){
if (grid[y][i] === n){
return false
}
}
let xx = (Math.floor(x / 3)) * 3
let yy = (Math.floor(y / 3)) * 3
for (let i = 0; i < 3; i++){
for (let j = 0; j < 3; j++){
if (grid[yy + i][xx + j] === n){
return false
}
}
}
return true
}
function solve(){
for (let y = 0; y < 9; y++){
for (let x = 0; x < 9; x++){
if (grid[y][x] === 0){
for (let n = 1; n < 10; n++){
if (possible(y, x, n)){
grid[y][x] = n;
if (solve()) return true; // <--- success!
grid[y][x] = 0;
}
}
return false; // <-- make it boolean
}
}
}
return true; // grid is complete!
}
solve();
for (let row of grid) console.log(...row);
The next improvement, is to avoid the function from mutating a global variable. Maybe turn the logic into a class, making the grid an instance property.
Basically what I'm dealing with is a 2D arrays that make up the pixels on grid. The 2D array consists of the numbers 0 through 10 which represents what color each pixel is. The number 0 represents that a pixel is not filled with a color, while all the numbers 1 though 10 represent that a pixel is filled with a color. What I'm trying to figure out is when these values within the array makes a rectangle and then getting the upper left hand coordinate [x1, y1] and lower right hand coordinate[x2, y2] of each separate rectangle.
A representation of the 2D array with it's values ranging from 0 to 4, and each rectangle color coated.
A representation of the points on each rectangle that I would like to get the coordinates of. With brown representing [x1, y1] and pink representing [x2, y2].
Here is the desired output of coordinates that I would like to get:
Green 1:
1: [x1: 0] [y1: 0] [x2: 4] [y2: 2]
2: [x1: 0] [y1: 3] [x2: 2] [y2: 5]
3: [x1: 3] [y1: 5] [x2: 7] [y2: 5]
4: [x1: 10] [y1: 7] [x2: 12] [y2: 10]
5:[x1: 6] [y1: 13] [x2: 8] [y1: 15]
Red 2:
1: [x1: 5] [y1: 0] [x2: 7] [y2: 2]
2: [x1: 10] [y1: 4] [x2: 15] [y2: 6]
3: [x1: 13 ] [y1: 7] [x2: 15] [y2: 10]
4: [x1: 1] [y1: 10] [x2: 5] [y2: 15]
Blue [3]:
1: [x1: 3] [y1: 3] [x2: 7] [y2: 4]
Purple [4]:
1: [x1: 14] [y1: 0] [x2: 15] [y2: 1]
Code that I use:
Note that this only gets the coordinates of rectangles with a value of one. How can I make this work for the other values as well?
const array = [
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 4, 4], //0
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 4, 4], //1
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0], //2
[1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0], //3
[1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 2], //4
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 2], //5
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2], //6
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //7
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //8
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //9
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //10
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //11
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //12
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], //13
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], //14
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0] //15
];
const W = array[0].length;
const H = array.length;
// get the area covered by rectangles
let totalRectArea = 0;
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
totalRectArea += array[j][i] > 0 ? 1 : 0;
}
}
const rects = [];
let rectArea = 0;
// find all rectangle until their area matches the total
while (rectArea < totalRectArea) {
const rect = findNextRect();
rects.push(rect);
markRect(rect);
rectArea += (rect.x2 - rect.x1 + 1) * (rect.y2 - rect.y1 + 1);
}
console.log(rects);
function findNextRect() {
// find top left corner
let foundCorner = false;
const rect = { x1: 0, x2: W - 1, y1: 0, y2: H - 1 };
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
if (array[j][i] === 1) {
rect.x1 = i;
rect.y1 = j;
foundCorner = true;
break;
}
}
if (foundCorner) break;
}
// find bottom right corner
for (let i = rect.x1; i <= rect.x2; ++i) {
if (array[rect.y1][i] !== 1) {
rect.x2 = i - 1;
return rect;
}
for (let j = rect.y1; j <= rect.y2; ++j) {
if (array[j][i] !== 1) {
rect.y2 = j - 1;
break;
}
}
}
return rect;
}
// mark rectangle so won't be counted again
function markRect({ x1, y1, x2, y2 }) {
for (let i = x1; i <= x2; ++i) {
for (let j = y1; j <= y2; ++j) {
array[j][i] = 2;
}
}
}
Got the code from: Find the coordinates of all rectangles of contiguous 1s in a 2D array in Javascript
If anyone can help me with doing this or supply some code, that would be absolutely amazing!!!
I found out how to do it, I used some of StackSlave's code on top of the code I was already using and had to create a function for every differently colored rectangle.
function test(){
array = [
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 4, 4], //0
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 4, 4], //1
[1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0], //2
[1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0], //3
[1, 1, 1, 3, 3, 3, 3, 3, 0, 0, 2, 2, 2, 2, 2, 2], //4
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2, 2, 2, 2, 2, 2], //5
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2], //6
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //7
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //8
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //9
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2], //10
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //11
[0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], //12
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], //13
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], //14
[0, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0] //15
];
W = array[0].length;
H = array.length;
green = []
red = []
blue = []
purple = []
// get the area covered by rectangles
greenTotalRectArea = 0;
redTotalRectArea = 0;
blueTotalRectArea = 0;
purpleTotalRectArea = 0;
for (let i = 0, a, l = array.length; i < l; i++) {
a = array[i];
for (let n = 0, q = a.length; n < q; n++) {
switch (a[n]) {
case 1:
green.push(n);
greenTotalRectArea = green.length;
break;
case 2:
red.push(n);
redTotalRectArea = red.length;
break;
case 3:
blue.push(n);
blueTotalRectArea = blue.length;
break;
case 4:
purple.push(n);
purpleTotalRectArea = purple.length;
break;
}
}
}
greenRects = [];
greenRectArea = 0;
while (greenRectArea < greenTotalRectArea) {
const greenRect = findGreenRect();
greenRects.push(greenRect);
markRect(greenRect);
greenRectArea += (greenRect.x2 - greenRect.x1 + 1) * (greenRect.y2 - greenRect.y1 + 1);
}
redRects = [];
redRectArea = 0;
while (redRectArea < redTotalRectArea) {
const redRect = findRedRect();
redRects.push(redRect);
markRect(redRect);
redRectArea += (redRect.x2 - redRect.x1 + 1) * (redRect.y2 - redRect.y1 + 1);
}
blueRects = [];
blueRectArea = 0;
while (blueRectArea < blueTotalRectArea) {
const blueRect = findBlueRect();
blueRects.push(blueRect);
markRect(blueRect);
blueRectArea += (blueRect.x2 - blueRect.x1 + 1) * (blueRect.y2 - blueRect.y1 + 1);
}
purpleRects = [];
purpleRectArea = 0;
while (purpleRectArea < purpleTotalRectArea) {
const purpleRect = findPurpleRect();
purpleRects.push(purpleRect);
markRect(purpleRect);
purpleRectArea += (purpleRect.x2 - purpleRect.x1 + 1) * (purpleRect.y2 - purpleRect.y1 + 1);
}
console.log(greenRects);
console.log(redRects);
console.log(blueRects);
console.log(purpleRects);
}
function findGreenRect() {
// find top left corner
let foundGreenCorner = false;
const greenRect = { x1: 0, x2: W - 1, y1: 0, y2: H - 1 };
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
if (array[j][i] === 1) {
greenRect.x1 = i;
greenRect.y1 = j;
foundGreenCorner = true;
break;
}
}
if (foundGreenCorner) break;
}
// find bottom right corner
for (let i = greenRect.x1; i <= greenRect.x2; ++i) {
if (array[greenRect.y1][i] !== 1) {
greenRect.x2 = i - 1;
return greenRect;
}
for (let j = greenRect.y1; j <= greenRect.y2; ++j) {
if (array[j][i] !== 1) {
greenRect.y2 = j - 1;
break;
}
}
}
return greenRect;
}
function findRedRect() {
// find top left corner
let foundRedCorner = false;
const redRect = { x1: 0, x2: W - 1, y1: 0, y2: H - 1 };
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
if (array[j][i] === 2) {
redRect.x1 = i;
redRect.y1 = j;
foundRedCorner = true;
break;
}
}
if (foundRedCorner) break;
}
// find bottom right corner
for (let i = redRect.x1; i <= redRect.x2; ++i) {
if (array[redRect.y1][i] !== 2) {
redRect.x2 = i - 1;
return redRect;
}
for (let j = redRect.y1; j <= redRect.y2; ++j) {
if (array[j][i] !== 2) {
redRect.y2 = j - 1;
break;
}
}
}
return redRect;
}
function findBlueRect() {
// find top left corner
let foundBlueCorner = false;
const blueRect = { x1: 0, x2: W - 1, y1: 0, y2: H - 1 };
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
if (array[j][i] === 3) {
blueRect.x1 = i;
blueRect.y1 = j;
foundBlueCorner = true;
break;
}
}
if (foundBlueCorner) break;
}
// find bottom right corner
for (let i = blueRect.x1; i <= blueRect.x2; ++i) {
if (array[blueRect.y1][i] !== 3) {
blueRect.x2 = i - 1;
return blueRect;
}
for (let j = blueRect.y1; j <= blueRect.y2; ++j) {
if (array[j][i] !== 3) {
blueRect.y2 = j - 1;
break;
}
}
}
return blueRect;
}
function findPurpleRect() {
// find top left corner
let foundPurpleCorner = false;
const purpleRect = { x1: 0, x2: W - 1, y1: 0, y2: H - 1 };
for (let i = 0; i < W; ++i) {
for (let j = 0; j < H; ++j) {
if (array[j][i] === 4) {
purpleRect.x1 = i;
purpleRect.y1 = j;
foundPurpleCorner = true;
break;
}
}
if (foundPurpleCorner) break;
}
// find bottom right corner
for (let i = purpleRect.x1; i <= purpleRect.x2; ++i) {
if (array[purpleRect.y1][i] !== 4) {
purpleRect.x2 = i - 1;
return purpleRect;
}
for (let j = purpleRect.y1; j <= purpleRect.y2; ++j) {
if (array[j][i] !== 4) {
purpleRect.y2 = j - 1;
break;
}
}
}
return purpleRect;
}
// mark rectangle so won't be counted again
function markRect({ x1, y1, x2, y2 }) {
for (let i = x1; i <= x2; ++i) {
for (let j = y1; j <= y2; ++j) {
array[j][i] = 99;
}
}
}
test();
Say I am representing a very large number using only 8-bit values in an array. Say the array is 32 8-bit values long. It starts out as 0. I'll just draw 4 8-bit values to demonstrate.
[0, 0, 0, 0]
Then it counts up.
[0, 0, 0, 1]
[0, 0, 0, 2]
...
[0, 0, 0, 255]
Once it gets to 255 in the first column, it goes to the next column.
[0, 0, 1, 0]
[0, 0, 1, 1]
[0, 0, 1, 2]
...
[0, 0, 1, 255]
[0, 0, 2, 0]
[0, 0, 2, 1]
...
[0, 0, 2, 255]
[0, 0, 3, 0]
[0, 0, 3, 1]
...
After filling that up, it goes to the 3rd column, then upon filling that out, it goes to the fourth column, etc..
[0, 1, 0, 0]
[0, 1, 0, 1]
[0, 1, 0, 2]
[0, 1, 0, 3]
...
[0, 1, 1, 0]
[0, 1, 1, 1]
[0, 1, 1, 2]
...
[0, 1, 2, 0]
[0, 1, 2, 1]
...
...
[1, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 0, 2]
...
[1, 0, 0, 255]
[1, 0, 1, 0]
[1, 0, 1, 1]
...
...
...
[2, 0, 0, 0]
[2, 0, 0, 1]
...
...
...
and so on.
How do you write an algorithm to increment these values like this. As if it were a single humongous value, which is just represented using smaller 8-bit values. It is mind-bending for me and I haven't been able to accomplish it.
Actually, I'm not sure I have drawn it in reverse, I was thinking about numbers as reading from smallest position on the right to the larger position on the left, which is why I drew it this way.
You can do it with a simple for loop (see snippet below, should be pretty self-explanatory)
let number = [0,0,255,250];
const add = () => {
for ( let i = number.length - 1; i >= 0; i-- ) {
if(number[i]===255){
number[i] = 0;
} else {
number[i]++;
break;
}
}
console.log(number);
}
<button onclick="add()">add</button>
Hope this is what you meant...
function increase(ar){
ar[0] = ar[0] + 1;
for(let i = 0; i < ar.length-1; i++){
ar[i+1]+= ar[i] < 256 ? 0 : 1;
ar[i] = ar[i] < 256 ? ar[i] : 0;
}
return ar;
}
let res = [250,1,0,0];
for(let u = 0; u < 10; u++){
console.log(increase(res));
}
It can be by far more generalized, changing the limit and also increasing by N (in this case it increase only by 1).
A possible implementation is the following:
function increase(ar, step = 1, limit = 256){
ar[0] = ar[0] + step;
for(let i = 0; i < ar.length-1; i++){
ar[i+1]+= ar[i] < limit ? 0 : Math.floor(ar[i] / limit);
ar[i] = ar[i] < limit ? ar[i] : ar[i] % limit;
}
return ar;
}
let res = [248,0,0,0];
for(let u = 0; u < 10; u++){
console.log(increase(res, 3));
}