Skip to main content
edited tags
Link
edited tags
Link
toolic
  • 15.9k
  • 6
  • 29
  • 217
deleted 57 characters in body
Source Link
toolic
  • 15.9k
  • 6
  • 29
  • 217

I've pasted here a basic implementation I've done of a Minesweeper game. This is not the full functionality, only the populating/revealing of squares. The idea is that the user inputs a string rows,cols,list-of-bombs as a string, and the game generates a board of the input dimensions, with bombs at the input indices.

Thank you in advance for all of your comments!


// LIB
const generateMap = <vals = number | boolean,>(
  rows: number,
  cols: number,
  defVal: vals
) => range(rows * cols).reduce((acc, curr) => ({ ...acc, [curr]: defVal }), {});

const range = (num: number) => {
  const res = [];
  let count = 0;
  while (count < num) {
    res.push(count++);
  }
  return res;
};

const addBombs = (values: Record<string, number>, bombs: string[]) => ({
  ...values,
  ...bombs.reduce((acc, curr) => ({ ...acc, [curr]: -1 }), {}),
});

const addValues = (
  values: Record<string, number>,
  row: number,
  col: number
) => {
  const getCount = (key: number) => (values[key] == -1 ? 1 : 0);

  for (const key in values) {
    if (values[key] == -1) {
      continue;
    }
    const keyNum = Number(key);
    const rowCount = Math.floor(keyNum / row);
    const colCount = keyNum % col;

    const left = colCount > 0 ? getCount(keyNum - 1) : 0;
    const right = colCount < col - 1 ? getCount(keyNum + 1) : 0;
    const up = rowCount > 0 ? getCount(keyNum - col) : 0;
    const down = rowCount < row - 1 ? getCount(keyNum + col) : 0;
    const topLeft =
      colCount > 0 && rowCount > 0 ? getCount(keyNum - col - 1) : 0;
    const topRight =
      colCount < col - 1 && rowCount > 0 ? getCount(keyNum - col + 1) : 0;
    const downLeft =
      colCount > 0 && rowCount < row - 1 ? getCount(keyNum + col - 1) : 0;
    const downRight =
      colCount < col - 1 && rowCount < row - 1 ? getCount(keyNum + col + 1) : 0;

    values[key] =
      left + right + up + down + topLeft + topRight + downLeft + downRight;
  }
  return values;
};



// COMPONENTS
const Input = ({ handlePlay }: { handlePlay: (val: string) => void }) => {
  const [val, setVal] = useState("");

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        marginBottom: 20,
      }}
    >
      <input type="text" value={val} onChange={(e) => setVal(e.target.value)} />
      <button onClick={() => handlePlay(val)}>Play</button>
    </div>
  );
};

const Cell = React.memo(
  ({
    visible,
    value,
    handleClick,
  }: {
    visible: boolean;
    value: number;
    handleClick: () => void;
  }) => {
    console.log('cell rendering')
    return (
      <div
        onClick={() => handleClick()}
        style={{
          padding: 10,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          width: "30px",
          height: "30px",
          border: "1px solid grey",
          backgroundColor: visible ? "white" : "lightgrey",
        }}
      >
        {visible && (value > -1 ? value : "💣")}
      </div>
    );
  }
);

const Grid = ({
  seen,
  values,
  rows,
  cols,
  handleCellClick,
}: {
  seen: Record<string, boolean>;
  values: Record<string, number>;
  rows: number;
  cols: number;
  handleCellClick: (key: string) => void;
}) => {
  const key = (row: number, col: number) => (row * cols + col).toString();

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      {range(rows).map((r) => (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          {range(cols).map((c) => (
            <Cell
              key={key(r, c)}
              handleClick={() => handleCellClick(key(r, c))}
              value={values[key(r, c)]}
              visible={seen[key(r, c)]}
            />
          ))}
        </div>
      ))}
    </div>
  );
};

function App() {
  const [values, setValues] = useState<Record<string, number>>({});
  const [seen, setSeen] = useState<Record<string, boolean>>({});
  const [[rows, cols], setRowCol] = useState<number[]>([]);

  const handlePlay = (val: string) => {
    const [row, col, ...bombs] = val.split(",");

    const valuesMap = generateMap(Number(row), Number(col), 0);
    const seenMap = generateMap(Number(row), Number(col), false);

    setValues(addValues(addBombs(valuesMap, bombs), Number(row), Number(col)));
    setSeen(seenMap);
    setRowCol([Number(row), Number(col)]);
  };

  const handleCellClick = useCallback(
    (key: string) => {
      setSeen({
        ...seen,
        [key]: true,
      });
    },
    [seen]
  );

  return (
    <div>
      <Input handlePlay={handlePlay} />
      <Grid
        rows={rows}
        cols={cols}
        seen={seen}
        values={values}
        handleCellClick={handleCellClick}
      />
    </div>
  );
}

export default App;
```

I've pasted here a basic implementation I've done of a Minesweeper game. This is not the full functionality, only the populating/revealing of squares. The idea is that the user inputs a string rows,cols,list-of-bombs as a string, and the game generates a board of the input dimensions, with bombs at the input indices.

Thank you in advance for all of your comments!


// LIB
const generateMap = <vals = number | boolean,>(
  rows: number,
  cols: number,
  defVal: vals
) => range(rows * cols).reduce((acc, curr) => ({ ...acc, [curr]: defVal }), {});

const range = (num: number) => {
  const res = [];
  let count = 0;
  while (count < num) {
    res.push(count++);
  }
  return res;
};

const addBombs = (values: Record<string, number>, bombs: string[]) => ({
  ...values,
  ...bombs.reduce((acc, curr) => ({ ...acc, [curr]: -1 }), {}),
});

const addValues = (
  values: Record<string, number>,
  row: number,
  col: number
) => {
  const getCount = (key: number) => (values[key] == -1 ? 1 : 0);

  for (const key in values) {
    if (values[key] == -1) {
      continue;
    }
    const keyNum = Number(key);
    const rowCount = Math.floor(keyNum / row);
    const colCount = keyNum % col;

    const left = colCount > 0 ? getCount(keyNum - 1) : 0;
    const right = colCount < col - 1 ? getCount(keyNum + 1) : 0;
    const up = rowCount > 0 ? getCount(keyNum - col) : 0;
    const down = rowCount < row - 1 ? getCount(keyNum + col) : 0;
    const topLeft =
      colCount > 0 && rowCount > 0 ? getCount(keyNum - col - 1) : 0;
    const topRight =
      colCount < col - 1 && rowCount > 0 ? getCount(keyNum - col + 1) : 0;
    const downLeft =
      colCount > 0 && rowCount < row - 1 ? getCount(keyNum + col - 1) : 0;
    const downRight =
      colCount < col - 1 && rowCount < row - 1 ? getCount(keyNum + col + 1) : 0;

    values[key] =
      left + right + up + down + topLeft + topRight + downLeft + downRight;
  }
  return values;
};



// COMPONENTS
const Input = ({ handlePlay }: { handlePlay: (val: string) => void }) => {
  const [val, setVal] = useState("");

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        marginBottom: 20,
      }}
    >
      <input type="text" value={val} onChange={(e) => setVal(e.target.value)} />
      <button onClick={() => handlePlay(val)}>Play</button>
    </div>
  );
};

const Cell = React.memo(
  ({
    visible,
    value,
    handleClick,
  }: {
    visible: boolean;
    value: number;
    handleClick: () => void;
  }) => {
    console.log('cell rendering')
    return (
      <div
        onClick={() => handleClick()}
        style={{
          padding: 10,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          width: "30px",
          height: "30px",
          border: "1px solid grey",
          backgroundColor: visible ? "white" : "lightgrey",
        }}
      >
        {visible && (value > -1 ? value : "💣")}
      </div>
    );
  }
);

const Grid = ({
  seen,
  values,
  rows,
  cols,
  handleCellClick,
}: {
  seen: Record<string, boolean>;
  values: Record<string, number>;
  rows: number;
  cols: number;
  handleCellClick: (key: string) => void;
}) => {
  const key = (row: number, col: number) => (row * cols + col).toString();

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      {range(rows).map((r) => (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          {range(cols).map((c) => (
            <Cell
              key={key(r, c)}
              handleClick={() => handleCellClick(key(r, c))}
              value={values[key(r, c)]}
              visible={seen[key(r, c)]}
            />
          ))}
        </div>
      ))}
    </div>
  );
};

function App() {
  const [values, setValues] = useState<Record<string, number>>({});
  const [seen, setSeen] = useState<Record<string, boolean>>({});
  const [[rows, cols], setRowCol] = useState<number[]>([]);

  const handlePlay = (val: string) => {
    const [row, col, ...bombs] = val.split(",");

    const valuesMap = generateMap(Number(row), Number(col), 0);
    const seenMap = generateMap(Number(row), Number(col), false);

    setValues(addValues(addBombs(valuesMap, bombs), Number(row), Number(col)));
    setSeen(seenMap);
    setRowCol([Number(row), Number(col)]);
  };

  const handleCellClick = useCallback(
    (key: string) => {
      setSeen({
        ...seen,
        [key]: true,
      });
    },
    [seen]
  );

  return (
    <div>
      <Input handlePlay={handlePlay} />
      <Grid
        rows={rows}
        cols={cols}
        seen={seen}
        values={values}
        handleCellClick={handleCellClick}
      />
    </div>
  );
}

export default App;
```

I've pasted here a basic implementation I've done of a Minesweeper game. This is not the full functionality, only the populating/revealing of squares. The idea is that the user inputs rows,cols,list-of-bombs as a string, and the game generates a board of the input dimensions, with bombs at the input indices.


// LIB
const generateMap = <vals = number | boolean,>(
  rows: number,
  cols: number,
  defVal: vals
) => range(rows * cols).reduce((acc, curr) => ({ ...acc, [curr]: defVal }), {});

const range = (num: number) => {
  const res = [];
  let count = 0;
  while (count < num) {
    res.push(count++);
  }
  return res;
};

const addBombs = (values: Record<string, number>, bombs: string[]) => ({
  ...values,
  ...bombs.reduce((acc, curr) => ({ ...acc, [curr]: -1 }), {}),
});

const addValues = (
  values: Record<string, number>,
  row: number,
  col: number
) => {
  const getCount = (key: number) => (values[key] == -1 ? 1 : 0);

  for (const key in values) {
    if (values[key] == -1) {
      continue;
    }
    const keyNum = Number(key);
    const rowCount = Math.floor(keyNum / row);
    const colCount = keyNum % col;

    const left = colCount > 0 ? getCount(keyNum - 1) : 0;
    const right = colCount < col - 1 ? getCount(keyNum + 1) : 0;
    const up = rowCount > 0 ? getCount(keyNum - col) : 0;
    const down = rowCount < row - 1 ? getCount(keyNum + col) : 0;
    const topLeft =
      colCount > 0 && rowCount > 0 ? getCount(keyNum - col - 1) : 0;
    const topRight =
      colCount < col - 1 && rowCount > 0 ? getCount(keyNum - col + 1) : 0;
    const downLeft =
      colCount > 0 && rowCount < row - 1 ? getCount(keyNum + col - 1) : 0;
    const downRight =
      colCount < col - 1 && rowCount < row - 1 ? getCount(keyNum + col + 1) : 0;

    values[key] =
      left + right + up + down + topLeft + topRight + downLeft + downRight;
  }
  return values;
};



// COMPONENTS
const Input = ({ handlePlay }: { handlePlay: (val: string) => void }) => {
  const [val, setVal] = useState("");

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        marginBottom: 20,
      }}
    >
      <input type="text" value={val} onChange={(e) => setVal(e.target.value)} />
      <button onClick={() => handlePlay(val)}>Play</button>
    </div>
  );
};

const Cell = React.memo(
  ({
    visible,
    value,
    handleClick,
  }: {
    visible: boolean;
    value: number;
    handleClick: () => void;
  }) => {
    console.log('cell rendering')
    return (
      <div
        onClick={() => handleClick()}
        style={{
          padding: 10,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          width: "30px",
          height: "30px",
          border: "1px solid grey",
          backgroundColor: visible ? "white" : "lightgrey",
        }}
      >
        {visible && (value > -1 ? value : "💣")}
      </div>
    );
  }
);

const Grid = ({
  seen,
  values,
  rows,
  cols,
  handleCellClick,
}: {
  seen: Record<string, boolean>;
  values: Record<string, number>;
  rows: number;
  cols: number;
  handleCellClick: (key: string) => void;
}) => {
  const key = (row: number, col: number) => (row * cols + col).toString();

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      {range(rows).map((r) => (
        <div
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          {range(cols).map((c) => (
            <Cell
              key={key(r, c)}
              handleClick={() => handleCellClick(key(r, c))}
              value={values[key(r, c)]}
              visible={seen[key(r, c)]}
            />
          ))}
        </div>
      ))}
    </div>
  );
};

function App() {
  const [values, setValues] = useState<Record<string, number>>({});
  const [seen, setSeen] = useState<Record<string, boolean>>({});
  const [[rows, cols], setRowCol] = useState<number[]>([]);

  const handlePlay = (val: string) => {
    const [row, col, ...bombs] = val.split(",");

    const valuesMap = generateMap(Number(row), Number(col), 0);
    const seenMap = generateMap(Number(row), Number(col), false);

    setValues(addValues(addBombs(valuesMap, bombs), Number(row), Number(col)));
    setSeen(seenMap);
    setRowCol([Number(row), Number(col)]);
  };

  const handleCellClick = useCallback(
    (key: string) => {
      setSeen({
        ...seen,
        [key]: true,
      });
    },
    [seen]
  );

  return (
    <div>
      <Input handlePlay={handlePlay} />
      <Grid
        rows={rows}
        cols={cols}
        seen={seen}
        values={values}
        handleCellClick={handleCellClick}
      />
    </div>
  );
}

export default App;
edited title
Source Link
Loading
Source Link
Loading