Snake and ladder game

Ayushi Priya
9 min readDec 11, 2022

--

Snake and ladder game all from scartch in react hooks , I hope that you will love making this game with the help of this blog. Here the straight line represents a ladder and the black one represents a snake.

During my childhood my father had a Nokia mobile phone in which I used to play snake game in which snake gets longer and longer by eating the food and by at the end the snake would die when it becomes very long and eat itself.

Today I feel amazed that I am able to build such type of games on my own.

App.js

import logo from './logo.svg';
import './App.css';
import SnakeAndLadder from './SnakeAndLadder';

function App() {
return (
<div className="App">
<SnakeAndLadder nextStep={10} />
</div>
);
}

export default App;

SnakeAndLadder.js

import React, { useState, useEffect } from 'react';
import useSnakeLadder from './useSnakeLadder';
import styles from './snakeAndLadderStyle';
import SnakeAndLadderBoard from './snakeLadderBoard';

function SnakeAndLadder(props) {
const {
playerAIndex1,
playerAIndex2,
playerBIndex1,
playerBIndex2,
diceDotPlayer1,
player,
winner,
showDotInDice,
diceClicked,
snakeAndLadderArray,
} = useSnakeLadder(props);

return (
<>
<div style={styles.boardStyle}>
<SnakeAndLadderBoard
snakeAndLadderArray={snakeAndLadderArray}
playerAIndex1={playerAIndex1}
playerAIndex2={playerAIndex2}
playerBIndex1={playerBIndex1}
playerBIndex2={playerBIndex2}
/>
<div style={styles.playerStyle}>Player {player}</div>
<div
onClick={() => {
diceClicked();
}}
style={styles.diceStyle}
>
{diceDotPlayer1 && showDotInDice(diceDotPlayer1)}
</div>
{winner && (
<div>
Winner is <b>Player{winner}</b>
</div>
)}
</div>
</>
);
}

export default SnakeAndLadder;

playerAIndex1,playerAIndex2- representing the indexes of first player.

playerBIndex1, playerBIndex2 — representing the indexes of second player.

diceDotPlayer1 — showing the number on dice

player- current player

winner- current winner

snakeAndLadderArray- representing array in which we are showing the snake and ladder game

SnakeLadderBoard.js

import React from 'react';
import styles from './snakeAndLadderStyle';

const SnakeAndLadderBoard = (props) => {
const {
snakeAndLadderArray,
playerAIndex1,
playerAIndex2,
playerBIndex1,
playerBIndex2,
} = props;
return (
<>
{snakeAndLadderArray &&
snakeAndLadderArray[0][0] !== '' &&
snakeAndLadderArray.map((ele, index1) => (
<div style={styles.boxRowStyle}>
{ele.map((element, index2) => {
if (index1 === playerAIndex1 && index2 === playerAIndex2) {
return (
<>
<div style={styles.elementStyle}>
<div style={styles.sizeOfDot}></div>
</div>
</>
);
}
if (index1 === playerBIndex1 && index2 === playerBIndex2) {
return (
<>
<div style={styles.elementStyle}>
<div style={styles.secondDot}></div>
</div>
</>
);
}
return (
<div style={styles.elementStyle}>
{snakeAndLadderArray[index1][index2]}
</div>
);
})}
</div>
))}
<div style={styles.lineMaintainStyle}></div>
<div style={styles.curvedLine}></div>
<div style={styles.curvedLine1}></div>
<div style={styles.curvedLine2}></div>
<div style={styles.curvedLine3}></div>
<div style={styles.curvedLine4}></div>
<div style={styles.curvedLine5}></div>
<div style={styles.curvedLine6}></div>
<div style={styles.curvedLine7}></div>
<div style={styles.straightLine}></div>
<div style={styles.straightLine1}></div>
<div style={styles.straightLine2}></div>
<div style={styles.straightLine3}></div>
<div style={styles.straightLine4}></div>
<div style={styles.straightLine5}></div>
<div style={styles.straightLine6}></div>
</>
);
};

export default SnakeAndLadderBoard;
  1. At first iterating through whole array and checking if the current array index is equivalent to the index of the players.
  2. If the current player index is equal to the array indexes then displaying the player via <div style={styles.sizeOfDot}></div> for first player and <div style={styles.secondDot}></div> for second player.
  3. If the indexes donot match then representing the element through <div style={styles.elementStyle}>
    {snakeAndLadderArray[index1][index2]}
    </div>
  4. curvedLine, curvedLine1, curvedLine2,…., curvedLine7 displays the eight snakes on the board
  5. straightLine, straightLine1,… straightLine6 displays the seven straight lines as “ladders” on the board.

snakeAndLadderStyle.js

const styles = {
boxRowStyle: {
display: 'flex',
flexDirection: 'row',
},
elementStyle: {
border: '1px solid black',
width: 50,
height: 50,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
sizeOfDot: {
height: 25,
width: 25,
backgroundColor: '#bbb',
borderRadius: '50%',
},
secondDot: {
backgroundColor: 'red',
height: 25,
width: 25,
borderRadius: '50%',
},
diceStyle: {
border: '1px solid black',
padding: 30,
width: 20,
height: 20,
marginTop: 10,
marginLeft: 10,
},
smallDot: {
backgroundColor: 'black',
height: 10,
width: 10,
borderRadius: '50%',
},
dotsDisplay: {
display: 'flex',
justifyContent: 'space-between',
width: 30,
},
dotsFourDisplay: {
marginTop: 10,
},
playerStyle: {
display: 'flex',
},
lineStyle: {
stroke: 'red',
strokeWidth: 2,
},
boardStyle: {
padding: 20,
margin: 20,
},
redLine: {
stroke: 'red',
strokeWidth: 2,
},
lineMaintainStyle: {
width: '80%',
margin: 'auto',
marginTop: '5%',
marginBottom: '5%',
transform: 'rotate(-25deg)',
borderColor: '#1A85FD',
},
midDotStyle: {
display: 'flex',
alignSelf: 'center',
backgroundColor: 'black',
height: 10,
width: 10,
borderRadius: '50%',
},
curvedLine: {
width: 300,
height: 100,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 50%/60px',
position: 'absolute',
transform: 'rotate(90deg)',
top: 300,
bottom: 20,
},
curvedLine1: {
width: 300,
height: 100,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 50%/60px',
position: 'absolute',
transform: 'rotate(110deg)',
top: 130,
bottom: 20,
left: 180,
},
curvedLine2: {
width: 280,
height: 60,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 50%/60px',
position: 'absolute',
transform: 'rotate(-10deg)',
top: 100,
bottom: 20,
left: 120,
},
curvedLine3: {
width: 430,
height: 300,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 40%/60px',
position: 'absolute',
transform: 'rotate(120deg)',
top: 180,
bottom: 20,
left: 210,
},
curvedLine4: {
width: 200,
height: 70,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 40%/60px',
position: 'absolute',
transform: 'rotate(-110deg)',
top: 420,
bottom: 20,
left: 180,
},
curvedLine5: {
width: 200,
height: 70,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 40%/60px',
position: 'absolute',
transform: 'rotate(-110deg)',
top: 420,
bottom: 20,
left: 180,
},
curvedLine6: {
width: 200,
height: 100,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 240px 40%/60px',
position: 'absolute',
transform: 'rotate(130deg)',
top: 350,
bottom: 0,
left: 300,
},
curvedLine7: {
width: 200,
height: 100,
border: 'solid 5px #000',
borderColor: 'transparent transparent #000 transparent',
borderRadius: '0 0 250px 60%/90px',
position: 'absolute',
transform: 'rotate(80deg)',
top: 400,
bottom: 0,
left: 440,
},
straightLine: {
borderLeft: '6px solid green',
height: 150,
position: 'absolute',
left: 100,
top: 43,
transform: 'rotate(200deg)',
},
straightLine1: {
borderLeft: '6px solid green',
height: 150,
position: 'absolute',
left: 100,
top: 300,
transform: 'rotate(200deg)',
},
straightLine2: {
borderLeft: '6px solid green',
height: 200,
position: 'absolute',
left: 150,
top: 350,
transform: 'rotate(20deg)',
},
straightLine3: {
borderLeft: '6px solid green',
height: 150,
position: 'absolute',
left: 300,
top: 430,
transform: 'rotate(250deg)',
},
straightLine4: {
borderLeft: '6px solid green',
height: 150,
position: 'absolute',
left: 480,
top: 400,
transform: 'rotate(230deg)',
},
straightLine5: {
borderLeft: '6px solid green',
height: 200,
position: 'absolute',
left: 450,
top: 180,
transform: 'rotate(-240deg)',
},
straightLine6: {
borderLeft: '6px solid green',
height: 150,
position: 'absolute',
left: 500,
top: 43,
transform: 'rotate(-210deg)',
},
};

export default styles;

useSnakeAndLadder.js

import React, { useEffect, useState } from 'react';
import styles from './snakeAndLadderStyle';

function useSnakeLadder(props) {
const [snakeAndLadderArray, setSnakeAndLadderArray] = useState(
new Array(10).fill(null).map((item) => new Array(10).fill(''))
);
const [jumpTo, setJumpTo] = useState(0);
const [playerAIndex1, setPlayerAIndex1] = useState(9);
const [playerAIndex2, setPlayerAIndex2] = useState(0);
const [playerBIndex1, setPlayerBIndex1] = useState(9);
const [playerBIndex2, setPlayerBIndex2] = useState(0);
const [diceDotPlayer1, setDiceDotPlayer2] = useState(5);
const [player, setPlayer] = useState(1);
const [playerAValue, setPlayerAValue] = useState(1);
const [playerBValue, setPlayerBValue] = useState(1);
const [winner, setWinner] = useState(null);
const [snakeVal, setSnakeVal] = useState([63, 95, 87, 88, 36, 48, 32]);

const lineBetweenTwo = (start, end) => {};

useEffect(() => {
const timer = setTimeout(() => {
console.log('playerAValue', playerAValue);
console.log('playerBValue', playerBValue);

if (playerBValue === 8) {
console.log('hello I am 8');
}

if (playerAValue === 8 || playerBValue === 8) {
console.log('player value ', playerBValue);
updateJumpTo(30);
}

if (playerAValue === 63 || playerBValue === 63) {
updateJumpTo(18);
} else if (playerAValue === 95 || playerBValue === 95) {
updateJumpTo(56);
} else if (playerAValue === 87 || playerBValue === 87) {
updateJumpTo(78);
} else if (playerAValue === 88 || playerBValue === 88) {
updateJumpTo(24);
} else if (playerAValue === 36 || playerBValue === 36) {
updateJumpTo(6);
} else if (playerAValue === 48 || playerBValue === 48) {
updateJumpTo(26);
} else if (playerAValue === 32 || playerBValue === 32) {
updateJumpTo(10);
} else if (playerAValue === 80 || playerBValue === 80) {
updateJumpTo(99);
} else if (playerAValue === 21 || playerBValue === 21) {
updateJumpTo(42);
} else if (playerAValue === 2 || playerBValue === 2) {
updateJumpTo(38);
} else if (playerAValue === 4 || playerBValue === 4) {
updateJumpTo(14);
} else if (playerAValue === 8 || playerBValue === 8) {
updateJumpTo(30);
} else if (playerAValue === 50 || playerBValue === 50) {
updateJumpTo(67);
} else if (playerAValue === 71 || playerBValue === 71) {
updateJumpTo(92);
}
}, 1000);
return () => clearTimeout(timer);
}, [playerBValue, playerAValue]);

useEffect(() => {
function settingArray() {
var numP = 100;
var numQ = 81;
const newSnakeAndLadder = [...snakeAndLadderArray];
newSnakeAndLadder &&
newSnakeAndLadder.map((ele, index1) => {
{
ele.map((element, index2) => {
if (index1 % 2 === 0) {
newSnakeAndLadder[index1][index2] = numP--;
} else {
newSnakeAndLadder[index1][index2] = numQ++;
if (index2 === 9) {
numQ = numQ - 30;
}
numP--;
}
});
}
});
// setPlayerAIndex(0);
// lineBetweenTwo(2, 23);
setSnakeAndLadderArray(newSnakeAndLadder);
}

settingArray();
}, []);

const updateJumpTo = (index) => {
if (index > 100) {
if (player === 1) {
setPlayer(2);
} else {
setPlayer(1);
}
return;
}
if (player === 1) {
setPlayerAValue(index);
if (index === 100) {
setWinner(1);
}
} else {
setPlayerBValue(index);
if (index === 100) {
setWinner(2);
}
}
{
snakeAndLadderArray &&
snakeAndLadderArray.map((ele, index1) => {
ele.map((element, index2) => {
if (snakeAndLadderArray[index1][index2] === index) {
if (player == 1) {
setPlayerAIndex1(index1);
setPlayerAIndex2(index2);
if (
index !== 63 &&
index !== 95 &&
index !== 87 &&
index !== 88 &&
index !== 36 &&
index !== 48 &&
index !== 32 &&
index !== 80 &&
index !== 21 &&
index !== 2 &&
index !== 4 &&
index !== 8 &&
index !== 50 &&
index !== 71
) {
setPlayer(2);
}
} else {
setPlayerBIndex1(index1);
setPlayerBIndex2(index2);
if (
index !== 63 &&
index !== 95 &&
index !== 87 &&
index !== 88 &&
index !== 36 &&
index !== 48 &&
index !== 32 &&
index !== 80 &&
index !== 21 &&
index !== 2 &&
index !== 4 &&
index !== 8 &&
index !== 50 &&
index !== 71
) {
setPlayer(1);
}
}

return;
}
});
});
}
};

const showDotInDice = (dotNum) => {
let jsxEle;
console.log(dotNum);
switch (dotNum) {
case 1:
jsxEle = <div style={styles.smallDot}></div>;
break;
case 2:
jsxEle = (
<div style={styles.dotsDisplay}>
{' '}
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
);
break;
case 3:
jsxEle = (
<div style={styles.dotsDisplay}>
{' '}
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
);
break;
case 4:
jsxEle = (
<div style={styles.dotsDisplay}>
{' '}
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
</div>
);
break;
case 5:
jsxEle = (
<div style={styles.dotsDisplay}>
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
<div style={styles.midDotStyle}></div>
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
</div>
);
break;
case 6:
jsxEle = (
<div style={styles.dotsDisplay}>
{' '}
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
<div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
<div style={styles.smallDot}></div>
</div>
</div>
);
break;

default:
jsxEle = <div style={styles.smallDot}></div>;
break;
}

return jsxEle;
};

const diceClicked = () => {
var randNum = Math.floor(Math.random() * 6) + 1;
let playerVal;
setDiceDotPlayer2(randNum);
if (player === 1) {
playerVal = playerAValue;
} else {
playerVal = playerBValue;
}
let nextElement = playerVal + randNum;

let elementTimer = setTimeout(() => {
updateJumpTo(nextElement);
}, 2000);
};

return {
jumpTo,
setJumpTo,
playerAIndex1,
setPlayerAIndex1,
playerAIndex2,
setPlayerAIndex2,
playerBIndex1,
setPlayerBIndex1,
playerBIndex2,
setPlayerBIndex2,
diceDotPlayer1,
setDiceDotPlayer2,
player,
setPlayer,
playerAValue,
setPlayerAValue,
playerBValue,
setPlayerBValue,
winner,
setWinner,
snakeVal,
setSnakeVal,
updateJumpTo,
showDotInDice,
diceClicked,
snakeAndLadderArray,
};
}

export default useSnakeLadder;

useSnakeAndLadder.js is a custom hook with the help of which we will handle all the logics behind snake and ladder game

  1. snakeAndLadderArray — This represents a 2-D array 10*10 which has initial value of empty string.
  2. playerAIndex1- This represents the what row number player1 is present which is (9) initially.
  3. playerAIndex2- This represents the what column number player1 is present which is (0) initially.
  4. playerBIndex1- This represents the what row number player2 is present which is (9) initially.
  5. playerBIndex2- This represents the what column number player2 is present which is (0) initially.
  6. diceDotPlayer1- This represents the initial number in the dice.(5)
  7. player- This represents which player will go for it’s turn.
  8. playerAValue- This represents at which box the first player is present and what is the value of that box
  9. playerBValue- This represents at which box the second player is present and what is the value of that box.
  10. winner- This represents the winner
  11. First useEffect this helps us handling all the cases where we have to handle the case whenever players encounter a ladder or a snake. updateJumpTo function helps in updating the current value of the player. The if block checks if the current Player value needs to be updated.
  12. setTimeOut is used in this usEffect so that we can delay the process of changing the player’s value from one index to another and actually see how it is getting updated.
  13. Second useEffect set the value of our whole snakeLadderBoard.
  14. Here we have two variables numP and numQ . numP is used for setting the values of the row which is at even index. When we will look at the board closely the even index row are having values which are decreasing by one. (100,99,98,….91).
  15. numQ is used for setting the values of row which is at odd index. Which is starting at 81 (that’s why initializing numQ by 81) and increasing one by one at a time (81, 82, 83,…, 90) and when the next odd index will start it will again be decreased by 30 . As we can see in the board at index 3 the values are (61,62,…,70).
  16. updateJumpTo function This function updates the indexes of the current player and set the next player.
  17. If (index>100) indexes of the current player will not be updated . It will remain on the place where it was present earlier.
  18. If index is 100 set the current player as winner 🏆
  19. Loop through snakeAndLadderArray and set the index of the current player to the index of the final Value where player has to move .
  20. Check whether the finalValue where player has to move doesnot concide with the final value when the player encounter snake or ladder then only toggle the player.
  21. showDotInDice is used to represent the dots on the dice
  22. diceClicked- The function takes the random number and set that value to the dice.
  23. Calculate the nextElement using the currentPlayerValuer and the diceValue(randNum) and update that using updateJumpTo function.
  24. setTimeout is used here to make the process of changing the player’s position more clear.

--

--