diff react_games/src/Robot/main.tsx @ 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/react_games/src/Robot/main.tsx	Mon Dec 01 20:22:47 2025 -0800
@@ -0,0 +1,180 @@
+/**
+ * Scenario
+ *  Design a miniature browser game in which a single “robot” sprite navigates a 
+ *  rectangular grid to reach a goal while avoiding obstacles. Everything—from bootstrapping the project
+ *  to shipping a playable, restartable game—must be accomplished within one hour.
+ *
+ *
+ * Grid 10 x 10
+ * Robot top left corner
+ * Obstical is going to be 10
+ *
+ * one of the grid is going to be the goal
+ *
+ * Movement logic keyboard or WASD okay
+ */
+
+import React, { CSSProperties, memo, useEffect, useReducer } from "react";
+
+enum CellValue {
+  PLAYER,
+  GOAL,
+  OBSTICAL,
+  EMPTY
+}
+
+interface Cell {
+  value: CellValue;
+}
+
+interface RowProp {
+  rowValue: Cell[];
+}
+
+interface CellComponentProp {
+  cell: Cell;
+}
+
+enum GameStatus {
+  PLAYABLE,
+  WON,
+}
+
+interface RobotState {
+  x: number;
+  y: number,
+}
+
+interface GameState {
+  board: Cell[][];
+  status: GameStatus;
+  robotState: RobotState;
+}
+
+enum GameActionType {
+  MOVE,
+  RESET,
+}
+
+type GameAction = {type: GameActionType.MOVE, command: string } | { type: GameActionType.RESET }
+
+const MAX_WIDTH: number = 10;
+const MAX_COLUMN: number  = 10;
+const BOARD: Cell[][] = Array.from(
+  { length: MAX_WIDTH },
+  () => Array(MAX_COLUMN).fill({value: CellValue.EMPTY})
+);
+
+BOARD[0][0] = {
+  value: CellValue.PLAYER
+}
+BOARD[0][5] = {
+  value: CellValue.OBSTICAL
+}
+BOARD[6][5] = {
+  value: CellValue.GOAL
+}
+
+
+const getCellValue = (cell: Cell) => {
+  switch(cell.value) {
+    case CellValue.EMPTY:
+      return (
+        <></>
+      )
+    case CellValue.PLAYER:
+      return (
+        <>🤖</>
+      )
+    case CellValue.OBSTICAL:
+      return (
+        <>🧱</>
+      )
+    case CellValue.GOAL:
+      return (
+        <>🪙</>
+      )
+  }
+}
+
+const CellComponent = memo(({cell}: CellComponentProp) => {
+  const cellStyle: CSSProperties = {
+    padding: "10px",
+    width: "50px",
+    height: "50px",
+    border: "1px solid #ccc",
+  }
+  return (
+    <div style={cellStyle}>
+      {getCellValue(cell)}
+    </div>
+  )
+})
+
+const Row = memo(({rowValue}: RowProp) => {
+  const rowStyle: CSSProperties = {
+    display: "flex",
+  }
+  return (
+    <div style={rowStyle}>
+      {rowValue.map((cell, idx) => {return <CellComponent key={idx} cell={cell} />})}
+    </div>
+  )
+})
+
+function boardReducer(state: GameState, action: GameAction): GameState {
+  if (action.type === GameActionType.RESET) return INITIAL_GAME_STATE;
+
+  const { x, y } = state.robotState;
+  let newX = x;
+  let newY = y;
+
+  switch (action.command) {
+    case "W": newX = Math.max(0, x - 1); break;
+    case "A": newY = Math.max(0, y - 1); break;
+    case "S": newX = Math.min(MAX_WIDTH - 1, x + 1); break;
+    case "D": newY = Math.min(MAX_COLUMN - 1, y + 1); break;
+    default:  return state;
+  }
+
+  const newBoard = state.board.map(row => row.slice());
+
+  newBoard[x][y]       = { value: CellValue.EMPTY  };   // old spot
+  newBoard[newX][newY] = { value: CellValue.PLAYER };   // new spot
+
+  return {
+    board: newBoard,
+    status: GameStatus.PLAYABLE,
+    robotState: { x: newX, y: newY },
+  };
+}
+
+const INITIAL_GAME_STATE: GameState = {
+  board: BOARD,
+  status: GameStatus.PLAYABLE,
+  robotState: { x: 0, y: 0 },
+}
+
+const Current = () => {
+  const [state, dispatch] = useReducer(boardReducer, INITIAL_GAME_STATE);
+
+  useEffect(() => {
+    const handleKeyDown = (event: KeyboardEvent) => {
+      dispatch({type: GameActionType.MOVE, command: event.key.toUpperCase()})
+    };
+
+    document.addEventListener("keydown", handleKeyDown);
+  }, [])
+
+
+
+  return (
+    <>
+      {state.board.map((row, idx) => { return <Row key={idx} rowValue={row} />})}
+    </>
+  );
+}
+
+export {
+  Current
+}