Mercurial
annotate react_games/src/current.tsx @ 44:0cfd7d9277b0
[ReactGame] 2048
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Wed, 03 Dec 2025 18:34:22 -0800 |
| parents | fb9bcd3145cb |
| children | 829623189a57 |
| rev | line source |
|---|---|
| 44 | 1 import { CSSProperties, useEffect, useReducer, useState } from "react"; |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 import ReactDOM from "react-dom/client"; |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 |
| 44 | 4 /** |
| 5 * 2048 | |
| 6 * | |
| 7 * 4 X 4 | |
| 8 */ | |
| 9 | |
| 10 const MAX_WIDTH = 4; | |
| 11 | |
| 12 type Color = 'white' | 'orange' | 'yellow' | 'red'; | |
| 13 | |
| 14 type Cell = { | |
| 15 value: number; | |
| 16 color: Color; | |
| 17 } | |
| 18 | |
| 19 type Board = Cell[][]; | |
| 20 | |
| 21 type GameState = "in_progress" | "lost" | "won"; | |
| 22 | |
| 23 type Game = { | |
| 24 board: Board; | |
| 25 state: GameState; | |
| 26 steps: number; | |
| 27 } | |
| 28 | |
| 29 type Command = "u" | "d" | "l" | "r"; | |
| 30 | |
| 31 type GameAction = | |
| 32 { type: "move", command: Command } | { type: "calculate" }; | |
| 33 | |
| 34 | |
| 35 interface GameStyle { | |
| 36 container: CSSProperties; | |
| 37 board: CSSProperties; | |
| 38 cell: (color: Color) => CSSProperties; | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 } |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 |
| 44 | 41 const gameStyle: GameStyle = { |
| 42 container: { | |
| 43 display: "flex", | |
| 44 flexDirection: "column", | |
| 45 justifyContent: "center", | |
| 46 alignItems: "center", | |
| 47 height: "100vh" | |
| 48 }, | |
| 49 board: { | |
| 50 display: "grid", | |
| 51 gridTemplateColumns: "repeat(4, 50px)", | |
| 52 background: "#EEFFEE", | |
| 53 }, | |
| 54 cell: (color: Color) => ({ | |
| 55 display: "flex", | |
| 56 justifyContent: "center", | |
| 57 alignItems: "center", | |
| 58 aspectRatio: "1 / 1 ", | |
| 59 margin: "10px", | |
| 60 background: color, | |
| 61 }) | |
| 62 } | |
| 63 | |
| 64 function initializeBoard(): Board { | |
| 65 const board = Array.from({ length: MAX_WIDTH }, () => | |
| 66 Array.from({ length: MAX_WIDTH }, (): Cell => ({ value: 0, color: 'orange' })) | |
| 67 ); | |
| 68 let rowIndex: number; | |
| 69 let colIndex: number; | |
| 70 rowIndex = Math.floor(Math.random() * 4); | |
| 71 colIndex = Math.floor(Math.random() * 4); | |
| 72 board[rowIndex][colIndex].value = 2; | |
| 73 board[rowIndex-1][colIndex].value = 2; | |
| 74 return board; | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 } |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 |
| 44 | 77 function initializeGame(): Game { |
| 78 return { | |
| 79 board: initializeBoard(), | |
| 80 state: "in_progress", | |
| 81 steps: 0, | |
| 82 } | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 } |
| 44 | 84 |
| 85 | |
| 86 function handleMove(board: Board, command: Command): Board { | |
| 87 // Deep copy the board and initialize the merged status for the new board | |
| 88 const copiedBoard = board.map(row => | |
| 89 row.map(cell => ({ ...cell, merged: false })) | |
| 90 ); | |
| 91 | |
| 92 let diff: { row: number, col: number }; | |
| 93 let startRow: number, endRow: number, stepRow: number; | |
| 94 let startCol: number, endCol: number, stepCol: number; | |
| 95 | |
| 96 const size = copiedBoard.length; | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 |
| 44 | 98 switch (command) { |
| 99 case "u": | |
| 100 diff = { row: -1, col: 0 }; | |
| 101 startRow = 0; endRow = size; stepRow = 1; | |
| 102 startCol = 0; endCol = size; stepCol = 1; | |
| 103 break; | |
| 104 case "d": | |
| 105 diff = { row: 1, col: 0 }; | |
| 106 startRow = size - 1; endRow = -1; stepRow = -1; | |
| 107 startCol = 0; endCol = size; stepCol = 1; | |
| 108 break; | |
| 109 case "l": | |
| 110 diff = { row: 0, col: -1 }; | |
| 111 startRow = 0; endRow = size; stepRow = 1; | |
| 112 startCol = 0; endCol = size; stepCol = 1; | |
| 113 break; | |
| 114 case "r": | |
| 115 diff = { row: 0, col: 1 }; | |
| 116 startRow = 0; endRow = size; stepRow = 1; | |
| 117 startCol = size - 1; endCol = -1; stepCol = -1; | |
| 118 break; | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
119 } |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
120 |
| 44 | 121 for (let rowIndex = startRow; rowIndex !== endRow; rowIndex += stepRow) { |
| 122 for (let colIndex = startCol; colIndex !== endCol; colIndex += stepCol) { | |
| 123 const currentCell = copiedBoard[rowIndex][colIndex]; | |
| 124 | |
| 125 if (currentCell.value === 0) continue; | |
| 126 | |
| 127 let r = rowIndex; | |
| 128 let c = colIndex; | |
| 129 let emptySlot: { r: number, c: number } = { r: rowIndex, c: colIndex }; | |
| 130 let finalSlot: { r: number, c: number } = { r: rowIndex, c: colIndex }; | |
| 131 | |
| 132 while (true) { | |
| 133 r += diff.row; | |
| 134 c += diff.col; | |
| 135 | |
| 136 if (r < 0 || r >= size || c < 0 || c >= size) { | |
| 137 finalSlot = emptySlot; | |
| 138 break; | |
| 139 } | |
| 140 | |
| 141 const nextCell = copiedBoard[r][c]; | |
| 142 | |
| 143 if (nextCell.value === 0) { | |
| 144 emptySlot = { r, c }; | |
| 145 finalSlot = emptySlot; | |
| 146 } else if (nextCell.value === currentCell.value && !nextCell.merged) { | |
| 147 finalSlot = { r, c }; | |
| 148 break; | |
| 149 } else { | |
| 150 finalSlot = emptySlot; | |
| 151 break; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 const targetCell = copiedBoard[finalSlot.r][finalSlot.c]; | |
| 156 | |
| 157 if (finalSlot.r === rowIndex && finalSlot.c === colIndex) { | |
| 158 continue; | |
| 159 } | |
| 160 | |
| 161 if (targetCell.value === currentCell.value && !targetCell.merged) { | |
| 162 targetCell.value *= 2; | |
| 163 targetCell.merged = true; | |
| 164 | |
| 165 copiedBoard[rowIndex][colIndex].value = 0; | |
| 166 | |
| 167 } else if (targetCell.value === 0) { | |
| 168 targetCell.value = currentCell.value; | |
| 169 copiedBoard[rowIndex][colIndex].value = 0; | |
| 170 } | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 return copiedBoard; | |
| 175 } | |
| 176 | |
| 177 function addNewItemsToTheBoard(board: Board) { | |
| 178 let randomRowIndex: number; | |
| 179 let randomColIndex: number; | |
| 180 | |
| 181 | |
| 182 let zeroPos = 0; | |
| 183 board.forEach((row) => { | |
| 184 row.forEach((cell) => { | |
| 185 if (cell.value === 0) { | |
| 186 zeroPos += 1; | |
| 187 } | |
| 188 }) | |
| 189 }) | |
| 190 if (zeroPos === 0) { | |
| 191 return; | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
192 } |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
193 |
| 44 | 194 let curr = 0; |
| 195 const maxAddedValues = zeroPos < 2 ? 1 : (zeroPos / 2) | 0; | |
| 196 while (curr < maxAddedValues) { | |
| 197 randomRowIndex = Math.floor(Math.random() * board.length) | |
| 198 randomColIndex = Math.floor(Math.random() * board.length) | |
| 199 if (board[randomRowIndex][randomColIndex].value === 0) | |
| 200 { | |
| 201 board[randomRowIndex][randomColIndex].value = 2; | |
| 202 curr++; | |
| 203 } | |
| 204 } | |
| 205 } | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
206 |
| 44 | 207 function gameDispatch(game: Game, gameAction: GameAction): Game { |
| 208 switch(gameAction.type) { | |
| 209 case "move": { | |
| 210 const newBoard = handleMove(game.board, gameAction.command); | |
| 211 addNewItemsToTheBoard(newBoard); | |
| 212 return { | |
| 213 ...game, | |
| 214 board: newBoard, | |
| 215 } | |
| 216 } | |
| 217 case "calculate": { | |
| 218 return { | |
| 219 ...game, | |
| 220 } | |
| 221 } | |
| 222 } | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 } |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 |
| 44 | 225 function Current() { |
| 226 const [game, dispatch] = useReducer(gameDispatch, null, initializeGame); | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 |
| 44 | 228 useEffect(() => { |
| 229 window.addEventListener("keyup", (e) => { | |
| 230 switch(e.key) { | |
| 231 case "ArrowDown": { | |
| 232 dispatch({ type: "move", command: "d" }); | |
| 233 return; | |
| 234 } | |
| 235 case "ArrowUp": { | |
| 236 dispatch({ type: "move", command: "u" }); | |
| 237 return; | |
| 238 } | |
| 239 case "ArrowRight": { | |
| 240 dispatch({ type: "move", command: "r" }); | |
| 241 return; | |
| 242 } | |
| 243 case "ArrowLeft": { | |
| 244 dispatch({ type: "move", command: "l" }); | |
| 245 return; | |
| 246 } | |
| 247 default: | |
| 248 return; | |
| 249 } | |
| 250 }) | |
| 251 | |
| 252 }, []) | |
| 253 return ( | |
| 254 <div style={gameStyle.container}> | |
| 255 <h1> 2048 </h1> | |
| 256 <div style={gameStyle.board}> | |
| 257 {game.board.map((row: Cell[]) => { | |
| 258 return row.map((cell: Cell) => (<div style={gameStyle.cell(cell.color)}> {cell.value} </div>)) | |
| 259 })} | |
| 260 </div> | |
| 261 </div> | |
| 262 ); | |
| 263 } | |
|
37
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
264 |
|
fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
265 ReactDOM.createRoot(document.getElementById("root")!).render(<Current />); |