Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module #1 (Nowshin Owishi) #17

Open
wants to merge 6 commits into
base: module-1
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 78 additions & 23 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ const getRandomCell = () => ({
y: Math.floor(Math.random() * Config.width),
});

const Snake = () => {
//custom hook
//controller
const UseSnake = () => {
const getDefaultSnake = () => [
{ x: 8, y: 12 },
{ x: 7, y: 12 },
Expand All @@ -75,67 +77,113 @@ const Snake = () => {
const [snake, setSnake] = useState(getDefaultSnake());
const [direction, setDirection] = useState(Direction.Right);

const [food, setFood] = useState({ x: 4, y: 10 });
const [score, setScore] = useState(0);
const [foods, setFoods] = useState([]);
const score = snake.length-3;

const resetGame = () => {
setSnake(getDefaultSnake())
setDirection(Direction.Right)
setFoods([])
}
// move the snake
useEffect(() => {
const runSingleStep = () => {
setSnake((snake) => {
const head = snake[0];
const newHead = { x: head.x + direction.x, y: head.y + direction.y };
const newHead = { x: (head.x + direction.x + Config.width) % Config.width,
y: (head.y + direction.y + Config.height) % Config.height };

// make a new snake by extending head
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
const newSnake = [newHead, ...snake];

// remove tail
newSnake.pop();
// remove tail when head doesnt eat food
if(!isFood(newHead)){
newSnake.pop();
}
if(isSnake(newHead)){
resetGame()
}

return newSnake;
});
};

runSingleStep();
const timer = setInterval(runSingleStep, 500);
const timer = setInterval(runSingleStep, 300);

return () => clearInterval(timer);
}, [direction, food]);
}, [direction]);

// update score whenever head touches a food
useEffect(() => {
const head = snake[0];
if (isFood(head)) {
setScore((score) => {
return score + 1;
});
setFoods(currentFoods =>currentFoods.filter(food => food.x!==head.x && food.y!==head.y)

);
}
}, [snake]);

//food after 3s
useEffect(() => {
const interval = setInterval(()=> {
let newFood = getRandomCell();
while (isSnake(newFood)) {
while (isSnake(newFood) || isFood(newFood)) {
newFood = getRandomCell();
}

setFood(newFood);
}
}, [snake]);
setFoods(currentFoods => [...currentFoods,newFood]);
setTimeout(() => {
setFoods((f) => f.filter(e => e.x !=newFood.x && e.y !=newFood.y))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Corei13 is this a good approach? registering a timeout while creating to execute a removal after 10 seconds

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@owishiboo think of this,
on 11th second you registered a timeout to remove a food on 21th second on a coordinate.
the snake eats the food within 14th second and another food appears on the exact coordinate that should get deleted on 24th second.
but the later food will get deleted on 21th second because the timeout clears that coordinate, it doesn't care about which food. right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@royantar0311 I'm so sorry I didn't think of this. I thought the code was working fine.
How can I solve it? I'm really out of ideas.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one idea is to assign an unique id to each of the foods, and then remove the food by id inside setInterval callback
another is to keep the created time with the food and each second keep only foods that were created within last 10s

}, 10*1000)
},3000);

return ( () =>
clearInterval(interval)
)

},[])

//food after 10s
//doesnt work
useEffect(() => {
const interval = setInterval(()=> {
// setFoods(currentFoods => currentFoods.slice(1))
// currentFoods.shift(); --> doesnt work either

},10000);

return ( () =>
clearInterval(interval)
)

},[])

const changeDir = (checkDir, newDir) => {
setDirection((direction) => {
if(direction!=checkDir)
return newDir;
return direction;
})

}

useEffect(() => {
const handleNavigation = (event) => {
switch (event.key) {
case "ArrowUp":
setDirection(Direction.Top);
changeDir(Direction.Bottom,Direction.Top);
break;

case "ArrowDown":
setDirection(Direction.Bottom);
changeDir(Direction.Top,Direction.Bottom);
break;

case "ArrowLeft":
setDirection(Direction.Left);
changeDir(Direction.Right,Direction.Left);
break;

case "ArrowRight":
setDirection(Direction.Right);
changeDir(Direction.Left,Direction.Right);
break;
}
};
Expand All @@ -145,12 +193,19 @@ const Snake = () => {
}, []);

// ?. is called optional chaining
// see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
const isFood = ({ x, y }) => food?.x === x && food?.y === y;
const isFood = ({ x, y }) =>
foods.find((position)=> position.x === x && position.y === y);

const isSnake = ({ x, y }) =>
snake.find((position) => position.x === x && position.y === y);


return {score,isFood, isSnake}
}

//view
const Snake = () => {
const {score, isFood, isSnake} = UseSnake()
const cells = [];
for (let x = 0; x < Config.width; x++) {
for (let y = 0; y < Config.height; y++) {
Expand Down