mancala/apps/frontend/src/components/board/BoardView.tsx

91 lines
3.9 KiB
TypeScript
Raw Normal View History

2022-05-08 17:13:21 +03:00
import * as React from "react";
import { FunctionComponent, useState } from "react";
import { useTranslation } from "react-i18next";
import { BoardViewModel, Game, getSowingPath } from "@mancala/core";
import { Pit } from "mancala.js";
2022-07-14 13:38:00 +03:00
import { Context } from "../../context/context";
import { getWebTheme } from "../../theme/themes";
import PitView, { PitMarks } from "./PitView";
2022-07-14 08:53:26 +03:00
import StoreView from "./StoreView";
import "./BoardView.css";
2021-06-29 03:29:46 +03:00
// The board as the bottom player sees it: their pits along the bottom from left to right, their store on the right.
// It fills its container's width.
2022-05-08 17:13:21 +03:00
const BoardView: FunctionComponent<{
2022-08-01 22:24:48 +03:00
game: Game;
context: Context;
boardViewModel: BoardViewModel;
// Show player 2 at the bottom.
2022-09-02 00:10:41 +03:00
revert: boolean;
topName: string;
bottomName: string;
// Makes the bottom player's pits buttons.
onPitSelect?: (index: number, pit: Pit) => void;
// The bottom player can move now: their pits with stones are highlighted and preview their move.
canPlay?: boolean;
// Board index of the pit the last move was played from.
lastMoveIndex?: number;
// Board index where the shown move's last stone landed.
landIndex?: number;
}> = ({ game, context, boardViewModel, revert, topName, bottomName, onPitSelect, canPlay, lastMoveIndex, landIndex }) => {
const { t } = useTranslation();
const [previewIndex, setPreviewIndex] = useState<number | undefined>(undefined);
const board = game.mancalaGame.board;
const themeId = getWebTheme(context.themeManager.theme).id;
const stones = boardViewModel.pits.map((pit) => pit.stoneCount);
2022-09-02 00:10:41 +03:00
// Pits the hovered move drops stones into, with how many each, and where its last stone lands.
const preview: Record<number, number> = {};
const path = canPlay && previewIndex !== undefined ? getSowingPath(stones, previewIndex) : [];
path.forEach((index) => (preview[index] = (preview[index] ?? 0) + 1));
const previewLand = path.length > 0 ? path[path.length - 1] : undefined;
const marksOf = (index: number): PitMarks => ({
highlight: boardViewModel.pits[index]?.highlight,
preview: preview[index],
land: previewLand !== undefined ? index === previewLand : index === landIndex,
last: index === lastMoveIndex,
});
const topPits = revert ? board.player1Pits : board.player2Pits;
const bottomPits = revert ? board.player2Pits : board.player1Pits;
const [topStore, bottomStore] = revert
? [board.player1BankIndex(), board.player2BankIndex()]
: [board.player2BankIndex(), board.player1BankIndex()];
2022-09-02 00:10:41 +03:00
const pitView = (pit: Pit, position: number, top: boolean) => {
const stoneCount = stones[pit.index];
const playable = !top && !!canPlay && stoneCount > 0;
const pitNumber = (top ? 5 - position : position) + 1;
return (
<PitView
key={pit.index}
index={pit.index}
stoneCount={stoneCount}
top={top}
position={position}
themeId={themeId}
label={t("PitLabel", { name: top ? topName : bottomName, pit: pitNumber, count: stoneCount })}
marks={marksOf(pit.index)}
playable={playable}
onClick={!top && onPitSelect ? () => onPitSelect(pit.index, board.pits[pit.index]) : undefined}
onPreview={(active) => setPreviewIndex(active ? pit.index : undefined)} />
);
};
2022-05-08 17:13:21 +03:00
return (
<div className="bwrap">
<div className="board">
<StoreView index={topStore} stoneCount={stones[topStore]} side="l" themeId={themeId}
label={t("StoreLabel", { name: topName, count: stones[topStore] })} marks={marksOf(topStore)} />
{[...topPits].reverse().map((pit, position) => pitView(pit, position, true))}
{bottomPits.map((pit, position) => pitView(pit, position, false))}
<StoreView index={bottomStore} stoneCount={stones[bottomStore]} side="r" themeId={themeId}
label={t("StoreLabel", { name: bottomName, count: stones[bottomStore] })} marks={marksOf(bottomStore)} />
</div>
2022-05-08 17:13:21 +03:00
</div>
);
};
2021-06-29 03:29:46 +03:00
2022-05-08 17:13:21 +03:00
export default BoardView;