diff --git a/Games/sand_tetris/assets/1.md b/Games/sand_tetris/assets/1.md new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Games/sand_tetris/assets/1.md @@ -0,0 +1 @@ +1 diff --git a/Games/sand_tetris/assets/screenshot_sand_tetris.png b/Games/sand_tetris/assets/screenshot_sand_tetris.png new file mode 100644 index 0000000000..cd3d4012e4 Binary files /dev/null and b/Games/sand_tetris/assets/screenshot_sand_tetris.png differ diff --git a/Games/sand_tetris/handleinput.js b/Games/sand_tetris/handleinput.js new file mode 100644 index 0000000000..a70a290075 --- /dev/null +++ b/Games/sand_tetris/handleinput.js @@ -0,0 +1,45 @@ +// Left Arrow Key: 37 +// Up Arrow Key: 38 +// Right Arrow Key: 39 +// Down Arrow Key: 40 + +document.addEventListener('keydown', event => { + if ([32, 37, 38, 39, 40].includes(event.keyCode)) { + event.preventDefault(); + } + switch (event.keyCode) { + + // Down arrow + case 40: + fallingPiece.moveDown(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveUp() + else + fallingPiece.resetBuffer() + break; + // Top arrow + case 38: + fallingPiece.rotateCW(); + + // if not valid, rotate back + if (!playfield.isValid(fallingPiece)) + fallingPiece.rotateCCW(); + + break; + + // Left arrow + case 37: + fallingPiece.moveLeft(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveRight() + break; + + // Right Arrow + case 39: + fallingPiece.moveRight(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveLeft() + break; + } + +}); \ No newline at end of file diff --git a/Games/sand_tetris/index.html b/Games/sand_tetris/index.html new file mode 100644 index 0000000000..2327c3f4d4 --- /dev/null +++ b/Games/sand_tetris/index.html @@ -0,0 +1,129 @@ + + + + + + + Sand Tetris Demo + + + + + + + + + + + +
+ + + + + +
+
+
+ + + + + + + + +
+
+ +
+ + + +
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
Score: 0
+ + +
+
+ +
+
+
+ + + + + +
+
+
+ + +
+
+ +
+ + +
+
+ + +
+ + +
+
+ +
+
+ +
+ +
+ + + + + + + + \ No newline at end of file diff --git a/Games/sand_tetris/logo.png b/Games/sand_tetris/logo.png new file mode 100644 index 0000000000..9d896615a8 Binary files /dev/null and b/Games/sand_tetris/logo.png differ diff --git a/Games/sand_tetris/piece.js b/Games/sand_tetris/piece.js new file mode 100644 index 0000000000..5c6453e14d --- /dev/null +++ b/Games/sand_tetris/piece.js @@ -0,0 +1,258 @@ +class Piece { + + constructor(type, playfield) { + // cells of this piece + this.type = type; + this.color = random(tetrisColors); + + // this.cells = types[type]; + this.cells = replaceStringIn2DArray(types[type], '#f43', this.color); + // console.log(this.color) + this.size = this.cells.length; // assumed square matrix + + // drawing sizes + this.cellSize = playfield.cellSize; + this.offset = playfield.borderSize; + + // position of top-left piece relative to playfield + this.x = floor((playfield.cols - this.size) / 2); + this.y = 0; + + // gravity + this.dropInterval = 300 // in ms + this.dropBuffer = 0; // time since last drop + + } + + + update(time) { + this.dropBuffer += time; + } + + + timeToFall() { + return this.dropBuffer > this.dropInterval + } + + resetBuffer() { + this.dropBuffer = 0; + } + + show() { + + // for each non-null cell in this piece, fill in + // the specified color and draw the rectangle + for (let row = 0; row < this.size; row++) { + for (let col = 0; col < this.size; col++) { + + if (this.cells[row][col]) { + let x = this.x + col; + let y = this.y + row; + + let cs = this.cellSize; + let off = this.offset; + + // fill(this.cells[row][col]) + stroke(this.cells[row][col]) + fill(this.cells[row][col]) + + rect(off + cs * x, off + cs * y, cs - 1, cs - 1); + } + + } + } + + } + + moveDown() { + this.y++; + } + moveRight() { + this.x++; + } + moveLeft() { + this.x--; + } + moveUp() { + this.y--; + } + + + // Rotate functions + rotateCW() { + let newCells = []; + + for (let col = 0; col < this.size; col++) { + + let newRow = []; + for (let row = this.size - 1; row >= 0; row--) { + newRow.push(this.cells[row][col]); + } + newCells.push(newRow); + + } + this.cells = newCells; + } + + rotateCCW() { + let newCells = []; + for (let col = this.size - 1; col >= 0; col--) { + + let newRow = []; + for (let row = 0; row < this.size; row++) { + newRow.push(this.cells[row][col]); + } + newCells.push(newRow); + + } + this.cells = newCells; + } + +} + +let types = { + + O: [ + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + ], + + + J: [ + ['#f43', '#f43', '#f43', '#f43', null, null, null, null, null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', null, null, null, null, null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', null, null, null, null, null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', null, null, null, null, null, null, null, null], + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + + ], + + + L: [ + [null, null, null, null, null, null, null, null, '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, null, null, null, null, '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, null, null, null, null, '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, null, null, null, null, '#f43', '#f43', '#f43', '#f43'], + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + ], + + + S: [ + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + ], + + + Z: [ + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', null, null, null, null], + + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + ], + + + T: [ + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', null, null, null, null], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', null, null, null, null], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', null, null, null, null], + [null, null, null, null, '#f43', '#f43', '#f43', '#f43', null, null, null, null], + + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + ], + + + I: [ + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + + + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + ['#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43', '#f43'], + + + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + [null, null, null, null, null, null, null, null, null, null, null, null], + + + ] + +} + + +function replaceStringIn2DArray(arr, textToReplace, replacementText) { + const replacedArray = arr.map(row => { + return row.map(item => { + if (item === textToReplace) { + return replacementText; + } + return item; + }); + }); + return replacedArray; +} + + diff --git a/Games/sand_tetris/playfield.js b/Games/sand_tetris/playfield.js new file mode 100644 index 0000000000..daaca85230 --- /dev/null +++ b/Games/sand_tetris/playfield.js @@ -0,0 +1,125 @@ +class Playfield { + + constructor(w, h) { + // colors + // this.foreground = [230]; + this.foreground = 230; + this.background = [255]; + + // dimensions and grid + this.cols = w; + this.rows = h; + this.grid = []; + this.resetGrid(); + + // drawing sizes + const canvasContainer = select('#canvasBox'); + this.cellSize = canvasContainer.width / w + this.borderSize = 2; + + // whether or not gridlines are seen + this.gridlines = false; + } + + addToGrid(piece) { + for (let row = 0; row < piece.size; row++) { + for (let col = 0; col < piece.size; col++) { + + if (piece.cells[row][col] != null) { + let gridRow = piece.y + row; + let gridCol = piece.x + col; + + this.grid[gridRow][gridCol] = + piece.cells[row][col]; + } + + } + } + + } + + + clearLines() { + + linetest() + } + + isValid(piece) { + + for (let row = 0; row < piece.size; row++) { + for (let col = 0; col < piece.size; col++) { + + if (piece.cells[row][col] != null) { + + let gridRow = piece.y + row; + let gridCol = piece.x + col; + + if (gridRow < 0 || gridRow >= this.rows || + gridCol < 0 || gridCol >= this.cols || + this.grid[gridRow][gridCol] != this.foreground) + return false; + } + + } + } + + return true; + + } + + resetGrid() { + // console.log("reset grid called!") + for (let i = 0; i < this.rows; i++) { + this.grid[i] = new Array(this.cols).fill(this.foreground); + } + } + + + show() { + // Draw the rectangle behind all the cells + // for the border and gridlines + + + let bs = this.borderSize + let cs = this.cellSize + + if (this.gridlines) fill(this.background); + else fill(this.foreground); + + stroke(this.background) + strokeWeight(bs); + + // offset the rectangle so that + // top and right borders stay in canvas + let offset = floor(bs / 2) + rect(offset, offset, cs * this.cols + bs - 1, cs * this.rows + bs - 1) + + + //=========================== + // Draw cells over the big rectangle + //=========================== + + for (let row = 0; row < this.grid.length; row++) { + for (let col = 0; col < this.grid[row].length; col++) { + + // offset the cells by the size of the border + let offset = this.borderSize; + + let cs = this.cellSize; + + // this.grid contains the colors of each cell + stroke(this.grid[row][col]) + fill(this.grid[row][col]); + + // noStroke(); + rect(cs * col + offset, cs * row + offset, cs - 1, cs - 1); + } + } + + } // end of show() + + +} + + + diff --git a/Games/sand_tetris/readme.md b/Games/sand_tetris/readme.md new file mode 100644 index 0000000000..8178c76d62 --- /dev/null +++ b/Games/sand_tetris/readme.md @@ -0,0 +1 @@ +readme diff --git a/Games/sand_tetris/script.js b/Games/sand_tetris/script.js new file mode 100644 index 0000000000..5f0a0076df --- /dev/null +++ b/Games/sand_tetris/script.js @@ -0,0 +1,508 @@ +let playfield +let fallingPiece +let paused = false +const width = 40 +const height = 80 +// to calculate delta time +let prev = 0; +let score = 0 + +let difficulty = "Intermediate"; +let totalWidth +let totalHeight + +// mobile touch debounce +let lastTouchTime = 0; +const debounceDelay = 100; // Adjust the debounce delay as needed + + +let scoreui = document.getElementById("scoreui") +let scrshotbtn = document.getElementById("scrshotbtn") +let pausebtn = document.getElementById("pausebtn") +let resetbtn = document.getElementById("resetbtn") +const radioInputs = document.getElementsByName("difficultyradio"); + + + + +pausebtn.addEventListener("click", e => { + paused = !paused + pausebtn.innerHTML = paused ? ` Play` : ` Pause`; +}) + +resetbtn.addEventListener("click", e => { + spawnNewPiece(); + playfield.resetGrid(); + score = 0 + // update score ui + scoreui.innerText = score + +}) + +scrshotbtn.addEventListener("click", e => { + saveCanvas('screenshot', 'png'); // Save as PNG file +}) + +radioInputs.forEach(input => { + input.addEventListener("change", function () { + if (input.checked) { + if (input.id === "difficultyradio1") { + difficulty = "Intermediate"; + } else if (input.id === "difficultyradio2") { + difficulty = "Expert"; + } + // You can add more conditions for other difficulty levels if needed + } + }); +}); + + + + +function setup() { + playfield = new Playfield(width, height); + + totalWidth = playfield.cellSize * width + playfield.borderSize * 2; + totalHeight = playfield.cellSize * height + playfield.borderSize * 2; + // frameRate(10) + const canvas = createCanvas(totalWidth, totalHeight); + canvas.parent('canvasBox'); + + spawnNewPiece(); +} + + +function draw() { + + // Handle touch events + for (let i = 0; i < touches.length; i++) { + let touchX = touches[i].x; + let touchY = touches[i].y; + + // Calculate the time since the last touch event + const currentTime = millis(); + const timeSinceLastTouch = currentTime - lastTouchTime; + + if (timeSinceLastTouch > debounceDelay) { + if (touchY < totalHeight / 4) { + // Top side touch: + fallingPiece.rotateCW(); + + // if not valid, rotate back + if (!playfield.isValid(fallingPiece)) + fallingPiece.rotateCCW(); + + } + } + // Update the last touch time + lastTouchTime = currentTime; + + // Check if the touch event occurred in the left, right, up, or down area + if (touchX < totalWidth / 4) { + // Left side touch: Move left + fallingPiece.moveLeft(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveRight() + + + } else if (touchX > (totalWidth / 4) * 3) { + // Right side touch: Move right + fallingPiece.moveRight(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveLeft() + + + } else if (touchY > (totalHeight / 4) * 3) { + // Bottom side touch: Move down + fallingPiece.moveDown(); + if (!playfield.isValid(fallingPiece)) + fallingPiece.moveUp() + else + fallingPiece.resetBuffer() + } + } + + // Get time passed since last frame + let curr = millis(); + let delta = curr - prev; + prev = curr; + + // Update + + if (!paused) { + fallingPiece.update(delta); + } + + + // move down piece and spawn a new one + // if necessary + if (fallingPiece.timeToFall()) { + fallingPiece.resetBuffer(); + fallingPiece.moveDown(); + + if (!playfield.isValid(fallingPiece)) { + // console.log("not valid") + fallingPiece.moveUp(); + spawnNewPiece(); + } + } + playfield.clearLines(); + + + // Draw + background(251); + automatonRules(playfield.grid) + playfield.show(); + fallingPiece.show(); +} + + +function spawnNewPiece() { + if (fallingPiece) { + playfield.addToGrid(fallingPiece); + // console.log("added to grid") + } + + const pieces = ['O', 'J', 'L', 'S', 'Z', 'T', 'I']; + const choice = random(pieces); + fallingPiece = new Piece(choice, playfield); + redraw(); + +} + + + + + +function automatonRules(grid) { + + + let case0 = 230 + let case1 = '#f43' + + + + + for (let i = height - 2; i >= 0; i--) { + for (let j = 0; j < width; j++) { + // Extract values of the 2x2 block clockwise from the top-left cell + + + let topleftcolor + let toprightcolor + let bottomrightcolor + let bottomleftcolor + + let topLeft + if (isInArray(tetrisColors, grid[i][j])) { + topLeft = 1 + topleftcolor = grid[i][j] + } else if (grid[i][j] == case0) { + topLeft = 0 + } + + let topRight + if (isInArray(tetrisColors, grid[i][j + 1])) { + topRight = 1 + toprightcolor = grid[i][j + 1] + } else if (grid[i][j + 1] == case0) { + topRight = 0 + } + + + let bottomRight + if (isInArray(tetrisColors, grid[i + 1][j + 1])) { + bottomRight = 1 + bottomrightcolor = grid[i + 1][j + 1] + + } else if (grid[i + 1][j + 1] == case0) { + bottomRight = 0 + } + + let bottomLeft + if (isInArray(tetrisColors, grid[i + 1][j])) { + bottomLeft = 1 + bottomleftcolor = grid[i + 1][j] + } else if (grid[i + 1][j] == case0) { + bottomLeft = 0 + } + + + // Create an array to represent the 2x2 block + let block = [topLeft, topRight, bottomRight, bottomLeft]; + + // Define rules for each possible block state + + if (arraysEqual(block, [0, 0, 0, 0])) { + // case 1 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = case0; + grid[i + 1][j] = case0; + } else if (arraysEqual(block, [0, 0, 1, 0])) { + // case 2 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = case0; + } else if (arraysEqual(block, [0, 0, 0, 1])) { + // case 3 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = case0; + grid[i + 1][j] = bottomleftcolor + } else if (arraysEqual(block, [0, 0, 1, 1])) { + // case 4 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = bottomleftcolor + } else if (arraysEqual(block, [0, 1, 0, 0])) { + // case 5 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = toprightcolor; + grid[i + 1][j] = case0; + } else if (arraysEqual(block, [0, 1, 1, 0])) { + // case 6 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = toprightcolor; + grid[i + 1][j] = bottomrightcolor + } else if (arraysEqual(block, [0, 1, 0, 1])) { + // case 7 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = toprightcolor + grid[i + 1][j] = bottomleftcolor + } else if (arraysEqual(block, [0, 1, 1, 1])) { + // case 8 + grid[i][j] = case0; + grid[i][j + 1] = toprightcolor + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = bottomleftcolor + } else if (arraysEqual(block, [1, 0, 0, 0])) { + // case 9 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = case0; + grid[i + 1][j] = topleftcolor + } else if (arraysEqual(block, [1, 0, 1, 0])) { + // case 10 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = topleftcolor + } else if (arraysEqual(block, [1, 0, 0, 1])) { + // case 11 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = bottomleftcolor + grid[i + 1][j] = topleftcolor + } else if (arraysEqual(block, [1, 0, 1, 1])) { + // case 12 + grid[i][j] = topleftcolor + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = bottomleftcolor; + } else if (arraysEqual(block, [1, 1, 0, 0])) { + // case 13 + grid[i][j] = case0; + grid[i][j + 1] = case0; + grid[i + 1][j + 1] = toprightcolor + grid[i + 1][j] = topleftcolor + } else if (arraysEqual(block, [1, 1, 1, 0])) { + // case 14 + grid[i][j] = case0; + grid[i][j + 1] = toprightcolor + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = topleftcolor + } else if (arraysEqual(block, [1, 1, 0, 1])) { + // case 15 + grid[i][j] = topleftcolor + grid[i][j + 1] = case0 + grid[i + 1][j + 1] = toprightcolor + grid[i + 1][j] = bottomleftcolor + } else if (arraysEqual(block, [1, 1, 1, 1])) { + // case 16 + grid[i][j] = topleftcolor + grid[i][j + 1] = toprightcolor + grid[i + 1][j + 1] = bottomrightcolor + grid[i + 1][j] = bottomleftcolor + } + + // Add more rules as needed + } + } +} + +function arraysEqual(arr1, arr2) { + if (arr1.length !== arr2.length) return false; + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] !== arr2[i]) return false; + } + return true; +} + + + +function isInArray(arr, value) { + return arr.includes(value); +} + +const tetrisColors = [ + "#00FFFF", // Cyan + "#0000FF", // Blue + "#FFA500", // Orange + "#FFFF00", // Yellow + "#00FF00", // Green + "#800080", // Purple + "#FF0000" // Red +]; + + + + +function getLeftSideCells(grid) { + const leftSideCells = []; + const rows = grid.length; + + for (let row = 0; row < rows; row++) { + const value = grid[row][0]; // Get the value at the leftmost cell + if (value !== 230) { + // Check if the previous cell had the same color + const previousRow = leftSideCells[leftSideCells.length - 1]; + if (!previousRow || previousRow.color !== value) { + leftSideCells.push({ row, col: 0, color: value }); + } + } + } + + return leftSideCells; +} + +function findConnectedCells(grid, startRow, startCol) { + const rows = grid.length; + const cols = grid[0].length; + const targetValue = grid[startRow][startCol]; + + // Initialize a 2D array to track visited cells + const visited = new Array(rows).fill(false).map(() => new Array(cols).fill(false)); + + // Define the eight possible neighbor directions, including diagonals + const directions = [ + [-1, -1], [-1, 0], [-1, 1], + [0, -1], [0, 1], + [1, -1], [1, 0], [1, 1] + ]; + + // Helper function to perform depth-first search + function dfs(row, col, connectedCells) { + if (row < 0 || row >= rows || col < 0 || col >= cols || visited[row][col]) { + return; + } + + visited[row][col] = true; + + if (grid[row][col] === targetValue) { + connectedCells.push({ row, col }); + + // Check all neighbors, including diagonals + for (const [dx, dy] of directions) { + dfs(row + dx, col + dy, connectedCells); + } + } + } + + const connectedCells = []; + dfs(startRow, startCol, connectedCells); + + return connectedCells; +} + + + +// this function does not check diagonal neighboring cells + +function findConnectedCellsnodiagonal(grid, startRow, startCol) { + const rows = grid.length; + const cols = grid[0].length; + const targetValue = grid[startRow][startCol]; + + // Initialize a 2D array to track visited cells + const visited = new Array(rows).fill(false).map(() => new Array(cols).fill(false)); + + // Helper function to perform depth-first search + function dfs(row, col, connectedCells) { + if (row < 0 || row >= rows || col < 0 || col >= cols || visited[row][col]) { + return; + } + + visited[row][col] = true; + + if (grid[row][col] === targetValue) { + connectedCells.push({ row, col }); + + // Check all neighbors + dfs(row - 1, col, connectedCells); // Up + dfs(row + 1, col, connectedCells); // Down + dfs(row, col - 1, connectedCells); // Left + dfs(row, col + 1, connectedCells); // Right + } + } + + const connectedCells = []; + dfs(startRow, startCol, connectedCells); + + return connectedCells; +} + + + +function linetest() { + + + let uniqueleftcolors = getLeftSideCells(playfield.grid) + // console.log(uniqueleftcolors) + + for (let index = 0; index < uniqueleftcolors.length; index++) { + + + // get the cluster + let connectedcells + // console.log(connectedcells) + + if (difficulty == "Intermediate") { + connectedcells = findConnectedCells(playfield.grid, uniqueleftcolors[index].row, uniqueleftcolors[index].col) + } else if (difficulty == "Expert") { + connectedcells = findConnectedCellsnodiagonal(playfield.grid, uniqueleftcolors[index].row, uniqueleftcolors[index].col) + + } + + + + + const hasCol = connectedcells.some(obj => obj.col === width - 1); + + if (hasCol) { + // console.log("Found an object with col = 39"); + + // loop over the cluster and set their location in grid to 230 + for (let index = 0; index < connectedcells.length; index++) { + playfield.grid[connectedcells[index].row][connectedcells[index].col] = 230 + } + + + score += connectedcells.length + // update score ui + scoreui.innerText = score + + } + + + } + + + +} + diff --git a/Games/sand_tetris/style.css b/Games/sand_tetris/style.css new file mode 100644 index 0000000000..8379ed6016 --- /dev/null +++ b/Games/sand_tetris/style.css @@ -0,0 +1,10 @@ +body { + background-color: rgba(200, 200, 200); +} +*{ + background-color: rgb(255, 255, 255); + color: rgb(0, 0, 0); +} +html{ + background-color: bisque; +} \ No newline at end of file diff --git a/README.md b/README.md index ef93715e40..cc75b4373a 100644 --- a/README.md +++ b/README.md @@ -431,11 +431,17 @@ Terms and conditions for use, reproduction and distribution are under the [Apach | [Emoji_Intruder](https://github.com/kunjgit/GameZone/tree/main/Games/Emoji_Intruder) | [Guess The Weapon](https://github.com/kunjgit/GameZone/tree/main/Games/Guess_The_Weapon) | [TriHand_Tactics](https://github.com/kunjgit/GameZone/tree/main/Games/TriHand_Tactics) | [Earth_Guardian](https://github.com/kunjgit/GameZone/tree/main/Games/Earth_Guardian) | [CatchTheBall](https://github.com/kunjgit/GameZone/tree/main/Games/CatchTheBall) | | [Candy_Crush_Saga](https://github.com/kunjgit/GameZone/tree/main/Games/Candy_Crush_Saga) | [numeral-whiz](https://github.com/Ishan-77/GameZone/tree/main/Games/numeral-whiz) | [candy_match](https://github.com/kunjgit/GameZone/tree/main/Games/Candy_Match_Saga) | [Crossy_Road](https://github.com/tanujbordikar/GameZone/tree/Crossy_Road) | [HueHero](https://github.com/kunjgit/GameZone/tree/main/Games/HueHero) | [Puzzel_Winner](https://github.com/kunjgit/GameZone/tree/main/Games/Puzzel_Winner) | +| [Emoji_Intruder](https://github.com/kunjgit/GameZone/tree/main/Games/Emoji_Intruder) | [Guess The Weapon](https://github.com/kunjgit/GameZone/tree/main/Games/Guess_The_Weapon) | [Guess Who](https://github.com/kunjgit/GameZone/tree/main/Games/Guess_Who) | [Pop My Balloon](https://github.com/kunjgit/GameZone/tree/main/Games/Pop_My_Balloon) | [Tower Stack](https://github.com/kunjgit/GameZone/tree/main/Games/Tower_Stack) | [Sand Tetris](https://github.com/kunjgit/GameZone/tree/main/Games/sand_tetris) | | + +| [Emoji_Intruder](https://github.com/kunjgit/GameZone/tree/main/Games/Emoji_Intruder) | [Guess The Weapon](https://github.com/kunjgit/GameZone/tree/main/Games/Guess_The_Weapon) | [Guess Who](https://github.com/kunjgit/GameZone/tree/main/Games/Guess_Who) | [Pop My Balloon](https://github.com/kunjgit/GameZone/tree/main/Games/Pop_My_Balloon) | [Tower Stack](https://github.com/kunjgit/GameZone/tree/main/Games/Tower_Stack) | +| [Boom_Blast](https://github.com/kunjgit/GameZone/tree/main/Games/Boom_Blast) | + | [DNA_Sequencer](https://github.com/kunjgit/GameZone/tree/main/Games/DNA_Sequencer) | | [Boom_Blast](https://github.com/kunjgit/GameZone/tree/main/Games/Boom_Blast) | | [Shadow_Runner](https://github.com/kunjgit/GameZone/tree/main/Games/Shadow_Runner) | | [Underwater_Shoot](https://github.com/kunjgit/GameZone/tree/main/Games/Underwater_Shoot) | +

Back to top

diff --git a/assets/js/gamesData.json b/assets/js/gamesData.json index a1ad7cafbf..d4de4a5f27 100644 --- a/assets/js/gamesData.json +++ b/assets/js/gamesData.json @@ -3351,10 +3351,11 @@ "thumbnailUrl": "Atlas_Game.png" }, "629":{ - "gameTitle" : "Word Search Game", - "gameUrl": "Word_Search_Game", - "thumbnailUrl": "Word_Search_Game.jpeg" - }, + "gameTitle" : "Sand Tetris", + "gameUrl": "sand_tetris", + "thumbnailUrl": "logo.png" + } +{ "gameTitle" : "Hangman Game", "gameUrl": "Hangman_Game", "thumbnailUrl": "Hangman_Game.png"