Skip to content

Commit

Permalink
fix: refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Shibi Suriya committed Oct 1, 2023
1 parent 8adf47f commit 55978a8
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 102 deletions.
132 changes: 35 additions & 97 deletions packages/game-client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect } from 'react';
import { generateKey, getOppositeDirection, generateRandomNumber } from './utils';
import { DIRECTIONS, NUMBER_OF_COLUMNS, NUMBER_OF_ROWS } from './constants';
import { GRID_MAP } from './computed';
import { useFood } from './hooks';
import { NUMBER_OF_COLUMNS, NUMBER_OF_ROWS, DIRECTIONS } from './constants';
import { GRID_MAP, initialSnakesState, defaultDirections } from './computed';
import { useDirection, useFood, useTicks } from './hooks';
import Grid from './Grid';
import styles from './app.module.css';

const SPEED = 1 * 100;
const FOOD_SPAWN_INTERVAL = 1 * 10;
const FOOD_SPAWN_INTERVAL = 1 * 1000;

function App() {
// const socket = useRef();
useTicks();
useEffect(() => {
// For now I am going to be using a simple websocket server for
// developer & testing purposes.
Expand Down Expand Up @@ -38,81 +40,17 @@ function App() {
}, []);

const [snakeId, setSnakeId] = useState(1);
const { food, setFood, removeFood, isFood } = useFood();
const { food, setFood, removeFood } = useFood();
// const playerId = useRef(2);

// Keep the direction of the snakes inside useRef since we don't
// want to force rerender of the component when the user changes
// the direction.
const defaultDirections = {
1: DIRECTIONS.DOWN,
2: DIRECTIONS.RIGHT,
3: DIRECTIONS.RIGHT,
4: DIRECTIONS.RIGHT,
};

const directions = useRef(defaultDirections);
const { getDirection, setDown, setLeft, setRight, setUp, setDirection } = useDirection(defaultDirections);

// Don't keep direction of the snakes insides of useState()...
const initialState = {
1: {
headColor: 'red',
bodyColor: 'green',
hash: {
'0-0': { x: 0, y: 0 },
'0-1': { x: 0, y: 1 },
'0-2': { x: 0, y: 2 },
'0-3': { x: 0, y: 3 },
'0-4': { x: 0, y: 4 },
'0-5': { x: 0, y: 5 },
'0-6': { x: 0, y: 6 },
},
list: ['0-6', '0-5', '0-4', '0-3', '0-2', '0-1', '0-0'],
},
2: {
headColor: 'blue',
bodyColor: 'yellow',
hash: {
'5-0': { x: 5, y: 0 },
'5-1': { x: 5, y: 1 },
'5-2': { x: 5, y: 2 },
'5-3': { x: 5, y: 3 },
'5-4': { x: 5, y: 4 },
'5-5': { x: 5, y: 5 },
'5-6': { x: 5, y: 6 },
'5-7': { x: 5, y: 7 },
},
list: ['5-7', '5-6', '5-5', '5-4', '5-3', '5-2', '5-1', '5-0'],
},
3: {
headColor: 'yellow',
bodyColor: 'red',
hash: {
'10-0': { x: 10, y: 0 },
'10-1': { x: 10, y: 1 },
'10-2': { x: 10, y: 2 },
'10-3': { x: 10, y: 3 },
'10-4': { x: 10, y: 4 },
'10-5': { x: 10, y: 5 },
},
list: ['10-5', '10-4', '10-3', '10-2', '10-1', '10-0'],
},
4: {
headColor: 'green',
bodyColor: 'blue',
hash: {
'12-0': { x: 12, y: 0 },
'12-1': { x: 12, y: 1 },
'12-2': { x: 12, y: 2 },
'12-3': { x: 12, y: 3 },
'12-4': { x: 12, y: 4 },
'12-5': { x: 12, y: 5 },
'12-6': { x: 12, y: 6 },
},
list: ['12-6', '12-5', '12-4', '12-3', '12-2', '12-1', '12-0'],
},
};
const [snakes, setSnakes] = useState(initialState);
const [snakes, setSnakes] = useState(initialSnakesState);

const getSnakeCells = () => {
// return cells that are occupied by snakes.
Expand All @@ -123,6 +61,12 @@ function App() {
}, {});
};

const removeSnake = (snakeId, prevSnakes) => {
const snakes = { ...prevSnakes };
delete snakes[snakeId];
return snakes;
};

const spawnFood = () => {
const snakeCells = getSnakeCells();
const emptyCells = {};
Expand All @@ -147,25 +91,17 @@ function App() {
};
}, [food]);

const getDirection = (snakeId) => {
return directions.current[snakeId];
};

const moveSnakeForward = (snakeId) => {
setSnakes((prevSnakes) => {
const resetSnake = (snakeId) => {
setDirection(snakeId, defaultDirections[snakeId]); // Set to the default initial direction.
return { ...snakes, [snakeId]: initialState[snakeId] };
return { ...snakes, [snakeId]: initialSnakesState[snakeId] };
};

if (snakeId in prevSnakes) {
const updatedHash = { ...prevSnakes[snakeId].hash };
const updatedList = [...prevSnakes[snakeId].list];

// Remove tail.
const tailKey = updatedList.pop(); // mutates.
delete updatedHash[tailKey];

// Create new head using prev head.
const [headKey] = updatedList;
const head = updatedHash[headKey];
Expand Down Expand Up @@ -195,38 +131,41 @@ function App() {
updatedHash[newHeadKey] = newHead;
updatedList.unshift(newHeadKey);
}
if (newHeadKey in prevSnakes[snakeId].hash) {

// Remove tail.
if (newHeadKey in food) {
removeFood(newHead.x, newHead.y);
return { ...prevSnakes, [snakeId]: { ...snakes[snakeId], hash: updatedHash, list: updatedList } };
} else if (newHeadKey in prevSnakes[snakeId].hash) {
// Snake collided with itself.
return resetSnake(snakeId);
return resetSnake(snakeId, prevSnakes);
} else if (
newHead.x < NUMBER_OF_ROWS &&
newHead.x >= 0 &&
newHead.y >= 0 &&
newHead.y < NUMBER_OF_COLUMNS
) {
// Snake moved.
const tailKey = updatedList.pop(); // mutates.
delete updatedHash[tailKey];
return { ...prevSnakes, [snakeId]: { ...snakes[snakeId], hash: updatedHash, list: updatedList } };
} else {
// Snake collided with the wall...
return resetSnake(snakeId);
return resetSnake(snakeId, prevSnakes);
}
} else {
throw new Error('The id mentioned is not in the hash!');
}
});
};

const setDirection = (snakeId, direction) => {
directions.current[snakeId] = direction;
};

const up = (snakeId) => {
const direction = getDirection(snakeId);
if (direction == DIRECTIONS.UP) {
// moving up only.
return;
} else if (getOppositeDirection(direction) !== DIRECTIONS.UP) {
setDirection(snakeId, DIRECTIONS.UP);
setUp(snakeId);
}
};

Expand All @@ -235,7 +174,7 @@ function App() {
if (direction == DIRECTIONS.DOWN) {
return;
} else if (getOppositeDirection(direction) !== DIRECTIONS.DOWN) {
setDirection(snakeId, DIRECTIONS.DOWN);
setDown(snakeId);
}
};

Expand All @@ -244,7 +183,7 @@ function App() {
if (direction == DIRECTIONS.RIGHT) {
return;
} else if (getOppositeDirection(direction) !== DIRECTIONS.RIGHT) {
setDirection(snakeId, DIRECTIONS.RIGHT);
setRight(snakeId);
}
};

Expand All @@ -253,16 +192,15 @@ function App() {
if (direction == DIRECTIONS.LEFT) {
return;
} else if (getOppositeDirection(direction) !== DIRECTIONS.LEFT) {
setDirection(snakeId, DIRECTIONS.LEFT);
setLeft(snakeId);
}
};

useEffect(() => {
const timer = setInterval(() => {
moveSnakeForward(snakeId);
moveSnakeForward(snakeId + 1);
moveSnakeForward(snakeId + 2);
moveSnakeForward(snakeId + 3);
Object.keys(snakes).forEach((snakeId) => {
moveSnakeForward(snakeId);
});
}, SPEED);
const abortController = new AbortController();

Expand Down Expand Up @@ -292,7 +230,7 @@ function App() {
}, [snakes]);

return (
<div>
<div className={styles.game}>
<select value={snakeId} onChange={(e) => setSnakeId(e.target.value)}>
{Object.keys(snakes).map((snakeId, index) => (
<option value={snakeId} key={index}>
Expand Down
10 changes: 10 additions & 0 deletions packages/game-client/src/app.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.game {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}

:global(body) {
margin: 0px;
}
71 changes: 69 additions & 2 deletions packages/game-client/src/computed.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NUMBER_OF_COLUMNS, NUMBER_OF_ROWS } from './constants';
import { NUMBER_OF_COLUMNS, NUMBER_OF_ROWS, DIRECTIONS } from './constants';
import { generateKey, generateValue } from './utils';

const generateGridMap = () => {
Expand All @@ -12,4 +12,71 @@ const generateGridMap = () => {
};

const GRID_MAP = generateGridMap();
export { GRID_MAP };

const initialSnakesState = {
1: {
headColor: '#264653',
bodyColor: '#e9c46a',
hash: {
'0-0': { x: 0, y: 0 },
'0-1': { x: 0, y: 1 },
'0-2': { x: 0, y: 2 },
'0-3': { x: 0, y: 3 },
'0-4': { x: 0, y: 4 },
'0-5': { x: 0, y: 5 },
'0-6': { x: 0, y: 6 },
},
list: ['0-6', '0-5', '0-4', '0-3', '0-2', '0-1', '0-0'],
},
2: {
headColor: 'blue',
bodyColor: 'yellow',
hash: {
'5-0': { x: 5, y: 0 },
'5-1': { x: 5, y: 1 },
'5-2': { x: 5, y: 2 },
'5-3': { x: 5, y: 3 },
'5-4': { x: 5, y: 4 },
'5-5': { x: 5, y: 5 },
'5-6': { x: 5, y: 6 },
'5-7': { x: 5, y: 7 },
},
list: ['5-7', '5-6', '5-5', '5-4', '5-3', '5-2', '5-1', '5-0'],
},
3: {
headColor: 'yellow',
bodyColor: 'red',
hash: {
'10-0': { x: 10, y: 0 },
'10-1': { x: 10, y: 1 },
'10-2': { x: 10, y: 2 },
'10-3': { x: 10, y: 3 },
'10-4': { x: 10, y: 4 },
'10-5': { x: 10, y: 5 },
},
list: ['10-5', '10-4', '10-3', '10-2', '10-1', '10-0'],
},
4: {
headColor: 'green',
bodyColor: 'blue',
hash: {
'12-0': { x: 12, y: 0 },
'12-1': { x: 12, y: 1 },
'12-2': { x: 12, y: 2 },
'12-3': { x: 12, y: 3 },
'12-4': { x: 12, y: 4 },
'12-5': { x: 12, y: 5 },
'12-6': { x: 12, y: 6 },
},
list: ['12-6', '12-5', '12-4', '12-3', '12-2', '12-1', '12-0'],
},
};

const defaultDirections = {
1: DIRECTIONS.DOWN,
2: DIRECTIONS.RIGHT,
3: DIRECTIONS.RIGHT,
4: DIRECTIONS.RIGHT,
};

export { GRID_MAP, initialSnakesState, defaultDirections };
19 changes: 17 additions & 2 deletions packages/game-client/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// in px (pixels)
const GRID_WIDTH = 1500;
const GRID_HEIGHT = 600;
const GRID_WIDTH = 30 * 20;
const GRID_HEIGHT = 30 * 20;
const CELL_DIMENSION = 30;

if (GRID_HEIGHT % CELL_DIMENSION !== 0) {
throw new Error('GRID_HEIGHT is not divislbe by CELL_DIMENSION');
}

if (GRID_WIDTH % CELL_DIMENSION !== 0) {
throw new Error('GRID_WIDTH is not divislbe by CELL_DIMENSION');
}

const NUMBER_OF_ROWS = GRID_HEIGHT / CELL_DIMENSION;
const NUMBER_OF_COLUMNS = GRID_WIDTH / CELL_DIMENSION;

Expand All @@ -19,6 +27,12 @@ const FOOD_TYPES = {
PROTEIN: 'protein',
};

const TICKS = {
1: 1 * 1000,
0.5: 0.5 * 1000,
0.25: 0.25 * 1000,
};

export {
GRID_HEIGHT,
GRID_WIDTH,
Expand All @@ -28,4 +42,5 @@ export {
DIRECTIONS,
DEFAULT_DIRECTION,
FOOD_TYPES,
TICKS,
};
2 changes: 1 addition & 1 deletion packages/game-client/src/grid.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}

.protein {
background-color: cyan;
background-color: #d62828;

/* Enter */
-webkit-animation: scale-in-center 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
Expand Down
2 changes: 2 additions & 0 deletions packages/game-client/src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { useFood } from './useFood';
export { useDirection } from './useDirection';
export { useTicks } from './useTicks';
Loading

0 comments on commit 55978a8

Please sign in to comment.