From 8414b550c387ad544bdb980cf06476cc15ed27f9 Mon Sep 17 00:00:00 2001 From: Mahmud-007 Date: Sat, 16 Apr 2022 22:07:15 +0600 Subject: [PATCH 1/2] add poison feature --- pages/index.js | 62 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/pages/index.js b/pages/index.js index 2f8fb7b..d2f3199 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,6 +121,7 @@ const useSnake = () => { const resetGame = useCallback(() => { setFoods([]); setDirection(getInitialDirection()); + setPoisons([]); }, []); const removeFoods = useCallback(() => { @@ -119,12 +131,24 @@ const useSnake = () => { ); }, []); + const removePoisons = useCallback(() => { + setPoisons((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 +156,25 @@ const useSnake = () => { [snake] ); + const isAllowedCell = useCallback( + (newCell) => isSnake(newCell) || isFood(newCell || isPoison(newCell)), + [isFood, isPoison, isSnake] + ); const addFood = useCallback(() => { let newFood = getRandomCell(); - while (isSnake(newFood) || isFood(newFood)) { + while (isAllowedCell(newFood)) { newFood = getRandomCell(); } setFoods((currentFoods) => [...currentFoods, newFood]); - }, [isFood, isSnake]); + }, [isAllowedCell]); + + const addPoison = useCallback(() => { + let newPoison = getRandomCell(); + while (isAllowedCell(newPoison)) { + newPoison = getRandomCell(); + } + setPoisons((currentPoisons) => [...currentPoisons, newPoison]); + }, [isAllowedCell]); // move the snake const runSingleStep = useCallback(() => { @@ -156,8 +192,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 +212,13 @@ const useSnake = () => { return newSnake; }); - }, [direction, isFood, isSnake, resetGame]); + }, [direction.x, direction.y, isFood, isPoison, isSnake, resetGame]); - useInterval(runSingleStep, 200); + useInterval(runSingleStep, 1); useInterval(addFood, 3000); useInterval(removeFoods, 100); + useInterval(addPoison, 3000); + useInterval(removePoisons, 100); useEffect(() => { const handleDirection = (direction, oppositeDirection) => { @@ -231,6 +269,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( From 5cb5aced5d0ea01827926172189cf3abb3bc6420 Mon Sep 17 00:00:00 2001 From: Mahmud-007 Date: Sat, 23 Apr 2022 01:18:14 +0600 Subject: [PATCH 2/2] add addObject and removeObject function for adding and removing foods and poisons --- pages/index.js | 73 +++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/pages/index.js b/pages/index.js index d2f3199..d2b1968 100644 --- a/pages/index.js +++ b/pages/index.js @@ -124,20 +124,28 @@ const useSnake = () => { 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 removePoisons = useCallback(() => { - setPoisons((currentPoisons) => + // 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 @@ -160,21 +168,29 @@ const useSnake = () => { (newCell) => isSnake(newCell) || isFood(newCell || isPoison(newCell)), [isFood, isPoison, isSnake] ); - const addFood = useCallback(() => { - let newFood = getRandomCell(); - while (isAllowedCell(newFood)) { - newFood = getRandomCell(); - } - setFoods((currentFoods) => [...currentFoods, newFood]); - }, [isAllowedCell]); - const addPoison = useCallback(() => { - let newPoison = getRandomCell(); - while (isAllowedCell(newPoison)) { - newPoison = getRandomCell(); + const getEmptyCell = useCallback(() =>{ + let newCell = getRandomCell(); + while (isAllowedCell(newCell)) { + newCell = getRandomCell(); } - setPoisons((currentPoisons) => [...currentPoisons, newPoison]); - }, [isAllowedCell]); + 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(() => { @@ -213,12 +229,13 @@ const useSnake = () => { return newSnake; }); }, [direction.x, direction.y, isFood, isPoison, isSnake, resetGame]); + - useInterval(runSingleStep, 1); - useInterval(addFood, 3000); - useInterval(removeFoods, 100); - useInterval(addPoison, 3000); - useInterval(removePoisons, 100); + useInterval(runSingleStep, 200); + useInterval(()=>addObject(setFoods), 3000); + useInterval(()=>removeObject(setFoods), 100); + useInterval(()=>addObject(setPoisons), 3000); + useInterval(()=>removeObject(setPoisons), 100); useEffect(() => { const handleDirection = (direction, oppositeDirection) => {