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