Mercurial
comparison react_games/public/games/main-QNFKFAB2.js @ 37:fb9bcd3145cb
[ReactGames] Few games I made using react just to practice few things.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 01 Dec 2025 20:22:47 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 36:84672efec192 | 37:fb9bcd3145cb |
|---|---|
| 1 import { | |
| 2 __toESM, | |
| 3 require_jsx_runtime, | |
| 4 require_react | |
| 5 } from "./chunk-AX5M7HF6.js"; | |
| 6 | |
| 7 // src/Minesweeper/main.tsx | |
| 8 var import_react = __toESM(require_react()); | |
| 9 var import_jsx_runtime = __toESM(require_jsx_runtime()); | |
| 10 var MAX_SIZE_LEN = 10; | |
| 11 var N_BOMBS = 10; | |
| 12 var DIRECTION = [ | |
| 13 [0, 1], | |
| 14 [1, 1], | |
| 15 [1, 0], | |
| 16 [1, -1], | |
| 17 [0, -1], | |
| 18 [-1, -1], | |
| 19 [-1, 0], | |
| 20 [-1, 1] | |
| 21 ]; | |
| 22 var constructGameState = () => { | |
| 23 let board = Array.from( | |
| 24 { length: MAX_SIZE_LEN }, | |
| 25 () => Array.from( | |
| 26 { length: MAX_SIZE_LEN }, | |
| 27 () => ({ | |
| 28 value: 0 /* EMPTY */, | |
| 29 numberOfAdjacentBomb: 0, | |
| 30 isShown: false, | |
| 31 isFlag: false | |
| 32 }) | |
| 33 ) | |
| 34 ); | |
| 35 let placedBomb = 0; | |
| 36 const bombPlacments = []; | |
| 37 while (placedBomb < N_BOMBS) { | |
| 38 const bombRowIdx = Math.floor(Math.random() * MAX_SIZE_LEN); | |
| 39 const bombColIdx = Math.floor(Math.random() * MAX_SIZE_LEN); | |
| 40 if (board[bombRowIdx][bombColIdx].value === 0 /* EMPTY */) { | |
| 41 board[bombRowIdx][bombColIdx] = { | |
| 42 ...board[bombRowIdx][bombColIdx], | |
| 43 value: 1 /* BOMB */ | |
| 44 }; | |
| 45 placedBomb++; | |
| 46 bombPlacments.push([bombRowIdx, bombColIdx]); | |
| 47 } | |
| 48 } | |
| 49 for (const [bombR, bombC] of bombPlacments) { | |
| 50 for (const [dr, dc] of DIRECTION) { | |
| 51 if (board[bombR + dr]?.[bombC + dc]?.value === 0 /* EMPTY */) { | |
| 52 board[bombR + dr][bombC + dc] = { | |
| 53 ...board[bombR + dr][bombC + dc], | |
| 54 numberOfAdjacentBomb: board[bombR + dr][bombC + dc].numberOfAdjacentBomb + 1 | |
| 55 }; | |
| 56 } | |
| 57 } | |
| 58 } | |
| 59 return { | |
| 60 board, | |
| 61 status: "Reveal all the map while not clicking on mine" /* PLAYABLE */ | |
| 62 }; | |
| 63 }; | |
| 64 var gameStateReducer = (state, action) => { | |
| 65 switch (action.type) { | |
| 66 case 0 /* CHECK */: | |
| 67 const { position } = action; | |
| 68 const board = state.board.map((row) => row.map((col) => ({ ...col }))); | |
| 69 const start = board[position.row][position.col]; | |
| 70 if (start.value === 1 /* BOMB */) { | |
| 71 for (const row of board) for (const cell of row) cell.isShown = true; | |
| 72 return { board, status: "YOU LOST" /* LOST */ }; | |
| 73 } | |
| 74 if (!start.isShown) start.isShown = true; | |
| 75 if (start.numberOfAdjacentBomb === 0) { | |
| 76 const q = [position]; | |
| 77 while (q.length) { | |
| 78 const { row, col } = q.shift(); | |
| 79 for (const [dr, dc] of DIRECTION) { | |
| 80 const r = row + dr, c = col + dc; | |
| 81 const n = board[r]?.[c]; | |
| 82 if (!n || n.isShown || n.value === 1 /* BOMB */) continue; | |
| 83 n.isShown = true; | |
| 84 if (n.numberOfAdjacentBomb === 0) q.push({ row: r, col: c }); | |
| 85 } | |
| 86 } | |
| 87 } | |
| 88 const hidden = board.flat().filter((c) => !c.isShown).length; | |
| 89 const status = hidden === N_BOMBS ? "YOU WON" /* WON */ : "Reveal all the map while not clicking on mine" /* PLAYABLE */; | |
| 90 return { board, status }; | |
| 91 case 2 /* FLAG */: | |
| 92 const newBoard = state.board.map( | |
| 93 (row, rowIdx) => rowIdx === action.position.row ? row.map( | |
| 94 (col, colIdx) => colIdx === action.position.col ? { ...col, isFlag: true } : col | |
| 95 ) : row | |
| 96 ); | |
| 97 console.log(newBoard); | |
| 98 return { | |
| 99 ...state, | |
| 100 board: newBoard | |
| 101 }; | |
| 102 case 1 /* RESET */: | |
| 103 return constructGameState(); | |
| 104 } | |
| 105 }; | |
| 106 var styles = { | |
| 107 board: { | |
| 108 display: "grid", | |
| 109 gridTemplateColumns: `repeat(${MAX_SIZE_LEN}, 1fr)`, | |
| 110 width: 400 | |
| 111 }, | |
| 112 cell: { | |
| 113 display: "flex", | |
| 114 justifyContent: "center", | |
| 115 alignItems: "center", | |
| 116 width: "100%", | |
| 117 aspectRatio: "1 / 1", | |
| 118 border: "1px solid black", | |
| 119 backgroundColor: "#e6e6e6" | |
| 120 } | |
| 121 }; | |
| 122 var CellComponent = (0, import_react.memo)(({ | |
| 123 cellValue, | |
| 124 row, | |
| 125 col, | |
| 126 placeDispatch, | |
| 127 flagDispatch | |
| 128 }) => { | |
| 129 console.log("re-render"); | |
| 130 const handleOnClikck = (0, import_react.useCallback)(() => { | |
| 131 placeDispatch(row, col); | |
| 132 }, [row, col, placeDispatch]); | |
| 133 const handleOnRightClikck = (0, import_react.useCallback)((event) => { | |
| 134 event.preventDefault(); | |
| 135 flagDispatch(row, col); | |
| 136 }, [row, col, placeDispatch]); | |
| 137 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| 138 "div", | |
| 139 { | |
| 140 style: { | |
| 141 ...styles.cell, | |
| 142 cursor: "pointer", | |
| 143 backgroundColor: cellValue.isShown ? "#fafafa" : "#e6e6e6" | |
| 144 }, | |
| 145 onClick: handleOnClikck, | |
| 146 onContextMenu: handleOnRightClikck, | |
| 147 children: cellValue.isShown ? cellValue.value === 1 /* BOMB */ ? "\u{1F4A3}" : cellValue.numberOfAdjacentBomb || "" : cellValue.isFlag ? "\u{1F6A9}" : "" | |
| 148 } | |
| 149 ); | |
| 150 }, (prev, next) => prev.cellValue.isShown === next.cellValue.isShown && prev.cellValue.isFlag === next.cellValue.isFlag); | |
| 151 var Minesweeper = () => { | |
| 152 const [state, dispatch] = (0, import_react.useReducer)(gameStateReducer, null, constructGameState); | |
| 153 const placeDispatch = (0, import_react.useCallback)( | |
| 154 (row, col) => { | |
| 155 dispatch({ type: 0 /* CHECK */, position: { row, col } }); | |
| 156 }, | |
| 157 [dispatch] | |
| 158 ); | |
| 159 const flagDispatch = (0, import_react.useCallback)( | |
| 160 (row, col) => { | |
| 161 dispatch({ type: 2 /* FLAG */, position: { row, col } }); | |
| 162 }, | |
| 163 [dispatch] | |
| 164 ); | |
| 165 return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ | |
| 166 /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h1", { children: [ | |
| 167 " ", | |
| 168 state.status, | |
| 169 " " | |
| 170 ] }), | |
| 171 /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.board, children: state.board.map( | |
| 172 (row, rowIdx) => row.map( | |
| 173 (cell, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)( | |
| 174 CellComponent, | |
| 175 { | |
| 176 cellValue: cell, | |
| 177 row: rowIdx, | |
| 178 col: colIdx, | |
| 179 placeDispatch, | |
| 180 flagDispatch | |
| 181 }, | |
| 182 `${rowIdx}-${colIdx}` | |
| 183 ) | |
| 184 ) | |
| 185 ) }), | |
| 186 /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => { | |
| 187 dispatch({ type: 1 /* RESET */ }); | |
| 188 }, children: " reset " }) | |
| 189 ] }); | |
| 190 }; | |
| 191 export { | |
| 192 Minesweeper | |
| 193 }; | |
| 194 //# sourceMappingURL=main-QNFKFAB2.js.map |