mancala/src/components/BoardView.tsx

250 lines
5.9 KiB
TypeScript
Raw Normal View History

2022-05-08 17:13:21 +03:00
import { Bank, MancalaGame, Pit } from "mancala.js";
import * as React from "react";
import { FunctionComponent, useState } from "react";
2021-06-29 03:29:46 +03:00
2021-06-30 16:11:22 +03:00
type Theme = {
2022-05-08 17:13:21 +03:00
background: string;
boardColor: string;
boardColorWhenPlayerTurn: string;
storeColor: string;
storeColorWhenPlayerTurn: string;
holeColor: string;
ballColor: string;
2022-05-12 23:41:24 +03:00
ballLightColor: string;
holeAnimateColor: string;
2022-05-08 17:13:21 +03:00
};
2021-06-30 16:11:22 +03:00
const theme: Theme = {
2022-05-08 17:13:21 +03:00
background: "#EEEEEE",
boardColor: "#4D606E",
boardColorWhenPlayerTurn: "#84b8a6",
storeColor: "#3FBAC2",
storeColorWhenPlayerTurn: "#6cab94",
holeColor: "#D3D4D8",
ballColor: "#393E46",
2022-05-12 23:41:24 +03:00
ballLightColor: "#393E46",
holeAnimateColor: "#afb3a4",
2022-05-08 17:13:21 +03:00
};
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
const BallView: FunctionComponent<{ color: string }> = ({ color }) => {
return (
<div
style={{
2021-06-30 16:11:22 +03:00
background: color,
2021-06-29 03:29:46 +03:00
margin: "1px",
2021-06-30 16:11:22 +03:00
width: "1vw",
height: "1vw",
2022-05-08 17:13:21 +03:00
borderRadius: "10vw",
}}
></div>
);
};
2021-06-29 03:29:46 +03:00
function range(size: number) {
2022-05-08 17:13:21 +03:00
var ans = [];
for (let i = 0; i < size; i++) {
ans.push(i);
}
return ans;
2021-06-29 03:29:46 +03:00
}
2022-05-12 23:41:24 +03:00
const PitContainer: FunctionComponent<{
pit: Pit;
isAnimating: boolean;
onClick: () => void;
}> = ({ pit, isAnimating, onClick }) => {
if (isAnimating) {
pit.stoneCount += 1;
}
return (
<>
<HoleView
hole={pit}
color={isAnimating ? theme.holeAnimateColor : theme.holeColor}
stoneColor={isAnimating ? theme.ballLightColor : theme.ballColor}
onClick={onClick}
/>
</>
);
};
2022-05-08 17:13:21 +03:00
const HoleView: FunctionComponent<{
hole: Pit;
color: string;
2022-05-12 23:41:24 +03:00
stoneColor: string;
2022-05-08 17:13:21 +03:00
onClick: () => void;
2022-05-12 23:41:24 +03:00
}> = ({ hole, color, stoneColor, onClick }) => {
2022-05-08 17:13:21 +03:00
const balls = [...range(hole.stoneCount)].map((i) => (
2022-05-12 23:41:24 +03:00
<BallView color={stoneColor} />
2022-05-08 17:13:21 +03:00
));
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
return (
<div
onClick={onClick}
style={{
background: color,
margin: "5px",
padding: "5px",
borderRadius: "10vw",
display: "flex",
alignItems: "center",
alignContent: "center",
justifyContent: "center",
justifyItems: "center",
flexWrap: "wrap",
}}
>
{balls}
</div>
);
};
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
const StoreView: FunctionComponent<{
store: Bank;
color: string;
2022-05-12 23:41:24 +03:00
stoneColor: string;
2022-05-08 17:13:21 +03:00
gridColumn: string;
gridRow: string;
2022-05-12 23:41:24 +03:00
}> = ({ store, color, stoneColor, gridColumn, gridRow }) => {
2022-05-08 17:13:21 +03:00
const balls = [...range(store.stoneCount)].map((i) => (
2022-05-12 23:41:24 +03:00
<BallView color={stoneColor} />
2022-05-08 17:13:21 +03:00
));
return (
<div
style={{
gridColumn: gridColumn,
gridRow: gridRow,
background: color,
margin: "5px",
borderRadius: "10vw",
display: "flex",
alignItems: "center",
justifyContent: "center",
alignContent: "center",
flexWrap: "wrap",
}}
>
{balls}
</div>
);
};
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
const BoardView: FunctionComponent<{
game?: MancalaGame;
userKey: string;
onHoleSelect: (index: number, hole: Pit) => void;
2022-05-12 23:41:24 +03:00
animationPitIndex: number;
}> = ({ game, userKey, onHoleSelect, animationPitIndex }) => {
const player1Pits = game?.board.player1Pits.map((pit) => {
const isAnimating = pit.index === animationPitIndex;
return (
<PitContainer
pit={pit}
isAnimating={isAnimating}
onClick={() => {
if (game.turnPlayerId === game.player1Id)
onHoleSelect(game.board.player1Pits.indexOf(pit), pit);
}}
/>
);
});
2021-06-29 03:29:46 +03:00
2022-05-12 23:41:24 +03:00
const player2Pits = game!!.board.player2Pits.map((pit) => {
const isAnimating = pit.index === animationPitIndex;
return (
<PitContainer
pit={pit}
isAnimating={isAnimating}
onClick={() => {
if (game.turnPlayerId === game.player2Id)
onHoleSelect(game.board.player2Pits.indexOf(pit), pit);
}}
/>
);
});
2022-05-08 17:13:21 +03:00
const isUserTurn = game.checkIsPlayerTurn(userKey);
2022-05-12 23:41:24 +03:00
const animatingPlayer1Bank =
game.board.player1Bank.index === animationPitIndex;
const animatingPlayer2Bank =
game.board.player2Bank.index === animationPitIndex;
const storeColorPlayer1 = animatingPlayer1Bank
? theme.holeAnimateColor
: isUserTurn
? theme.storeColor
: theme.storeColorWhenPlayerTurn;
const storeStoneColorPlayer1 = animatingPlayer1Bank
? theme.ballLightColor
: theme.ballColor;
const storeColorPlayer2 = animatingPlayer2Bank
? theme.holeAnimateColor
: isUserTurn
2022-05-08 17:13:21 +03:00
? theme.storeColor
: theme.storeColorWhenPlayerTurn;
2021-06-29 03:29:46 +03:00
2022-05-12 23:41:24 +03:00
const storeStoneColorPlayer2 = animatingPlayer2Bank
? theme.ballLightColor
: theme.ballColor;
2022-05-08 17:13:21 +03:00
return (
<div
style={{
margin: "10px",
padding: "20px",
display: "grid",
gridTemplateColumns: "repeat(8, 11vw)",
gridTemplateRows: "repeat(2, 11vw)",
borderRadius: "3vw",
background: isUserTurn
? theme.boardColor
: theme.boardColorWhenPlayerTurn,
}}
>
{userKey === game.player2Id ? (
<>
<StoreView
store={game!!.board.player1Bank}
2022-05-12 23:41:24 +03:00
color={storeColorPlayer1}
stoneColor={storeStoneColorPlayer1}
2022-05-08 17:13:21 +03:00
gridColumn="1 / 2"
gridRow="1 / 3"
/>
<StoreView
store={game!!.board.player2Bank}
2022-05-12 23:41:24 +03:00
color={storeColorPlayer2}
stoneColor={storeStoneColorPlayer2}
2022-05-08 17:13:21 +03:00
gridColumn="8 / 9"
gridRow="1 / 3"
/>
{player1Pits.reverse()}
{player2Pits}
</>
) : (
<>
<StoreView
store={game!!.board.player2Bank}
2022-05-12 23:41:24 +03:00
color={storeColorPlayer2}
stoneColor={storeStoneColorPlayer2}
2022-05-08 17:13:21 +03:00
gridColumn="1 / 2"
gridRow="1 / 3"
/>
<StoreView
store={game!!.board.player1Bank}
2022-05-12 23:41:24 +03:00
color={storeColorPlayer1}
stoneColor={storeStoneColorPlayer1}
2022-05-08 17:13:21 +03:00
gridColumn="8 / 9"
gridRow="1 / 3"
/>
{player2Pits.reverse()}
{player1Pits}
</>
)}
</div>
);
};
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
export default BoardView;