diff --git a/pages/index.js b/pages/index.js index 2f8fb7b..d2b1968 100644 --- a/pages/index.js +++ b/pages/index.js @@ -12,6 +12,7 @@ const CellType = { Snake: "snake", Food: "food", Empty: "empty", + Poison: "poison", }; const Direction = { @@ -40,6 +41,15 @@ const Cell = ({ x, y, type, remaining }) => { transform: `scale(${0.5 + remaining / 20})`, }; + case CellType.Poison: + return { + backgroundColor: "blue", + borderRadius: 20, + width: 32, + height: 32, + transform: `scale(${0.5 + remaining / 20})`, + }; + default: return {}; } @@ -100,6 +110,7 @@ const useSnake = () => { const [direction, setDirection] = useState(getInitialDirection()); const [foods, setFoods] = useState([]); + const [poisons, setPoisons] = useState([]); const score = snake.length - 3; @@ -110,21 +121,42 @@ const useSnake = () => { const resetGame = useCallback(() => { setFoods([]); setDirection(getInitialDirection()); + setPoisons([]); }, []); - const removeFoods = useCallback(() => { - // only keep those foods which were created within last 10s. - setFoods((currentFoods) => - currentFoods.filter((food) => Date.now() - food.createdAt <= 10 * 1000) + // const removeFoods = useCallback(() => { + // // only keep those foods which were created within last 10s. + // setFoods((currentFoods) => + // currentFoods.filter((food) => Date.now() - food.createdAt <= 10 * 1000) + // ); + // }, []); + + // const removePoisons = useCallback(() => { + // setPoisons((currentPoisons) => + // currentPoisons.filter( + // (poison) => Date.now() - poison.createdAt <= 10 * 1000 + // ) + // ); + // }, []); + + const removeObject = useCallback((setState)=>{ + setState((currentPoisons) => + currentPoisons.filter( + (poison) => Date.now() - poison.createdAt <= 10 * 1000 + ) ); - }, []); + },[]); // ?. is called optional chaining // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining const isFood = useCallback( - ({ x, y }) => foods.some((food) => food.x === x && food.y === y), + ({ x, y }) => foods.find((food) => food.x === x && food.y === y), [foods] ); + const isPoison = useCallback( + ({ x, y }) => poisons.find((poison) => poison.x === x && poison.y === y), + [poisons] + ); const isSnake = useCallback( ({ x, y }) => @@ -132,13 +164,33 @@ const useSnake = () => { [snake] ); - const addFood = useCallback(() => { - let newFood = getRandomCell(); - while (isSnake(newFood) || isFood(newFood)) { - newFood = getRandomCell(); + const isAllowedCell = useCallback( + (newCell) => isSnake(newCell) || isFood(newCell || isPoison(newCell)), + [isFood, isPoison, isSnake] + ); + + const getEmptyCell = useCallback(() =>{ + let newCell = getRandomCell(); + while (isAllowedCell(newCell)) { + newCell = getRandomCell(); } - setFoods((currentFoods) => [...currentFoods, newFood]); - }, [isFood, isSnake]); + return newCell; + },[isAllowedCell]); + + // const addFood = useCallback(() => { + // const newFood = getEmptyCell(); + // setFoods((currentFoods) => [...currentFoods, newFood]); + // }, [getEmptyCell]); + + // const addPoison = useCallback(() => { + // const newPoison = getEmptyCell(); + // setPoisons((currentPoisons) => [...currentPoisons, newPoison]); + // }, [getEmptyCell]); + + const addObject = useCallback((setState)=>{ + const newObject = getEmptyCell(); + setState((currentPoisons) => [...currentPoisons, newObject]); + },[getEmptyCell]) // move the snake const runSingleStep = useCallback(() => { @@ -156,8 +208,8 @@ const useSnake = () => { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax const newSnake = [newHead, ...snake]; - // reset the game if the snake hit itself - if (isSnake(newHead)) { + // reset the game if the snake hit itself or poison + if (isSnake(newHead) || isPoison(newHead)) { resetGame(); return getDefaultSnake(); } @@ -176,11 +228,14 @@ const useSnake = () => { return newSnake; }); - }, [direction, isFood, isSnake, resetGame]); + }, [direction.x, direction.y, isFood, isPoison, isSnake, resetGame]); + useInterval(runSingleStep, 200); - useInterval(addFood, 3000); - useInterval(removeFoods, 100); + useInterval(()=>addObject(setFoods), 3000); + useInterval(()=>removeObject(setFoods), 100); + useInterval(()=>addObject(setPoisons), 3000); + useInterval(()=>removeObject(setPoisons), 100); useEffect(() => { const handleDirection = (direction, oppositeDirection) => { @@ -231,6 +286,16 @@ const useSnake = () => { ); } else if (isSnake({ x, y })) { type = CellType.Snake; + } else if (isPoison({ x, y })) { + type = CellType.Poison; + remaining = + 10 - + Math.round( + (Date.now() - + poisons.find((poison) => poison.x === x && poison.y === y) + .createdAt) / + 1000 + ); } cells.push(