-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial. board is grid. pieces can move forward.
- Loading branch information
Showing
12 changed files
with
346 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { NumPlayers, Player, PlayerId, createPlayers } from "./Player"; | ||
import { DiceRoll } from "./reducer/reducerFunction"; | ||
|
||
export type DiveRoute = Piece[]; | ||
export interface GameState { | ||
remainingAir: number; | ||
diveRoute: DiveRoute; | ||
players: Player[]; | ||
whoseTurn: PlayerId; | ||
lastRoll: DiceRoll | null; | ||
} | ||
|
||
export type Piece = TreasurePiece | BlankPiece; | ||
export type PieceId = string & { readonly __brand: "pieceId" }; | ||
export type TreasurePiece = { | ||
id: PieceId; | ||
tag: "treasure"; | ||
state: "faceUp" | "faceDown"; | ||
shape: TreasureShape; | ||
value: TreasureValue; | ||
}; | ||
export type BlankPiece = { tag: "blank"; id: string }; | ||
export type TreasureShape = "triangle" | "square" | "pentagon" | "hexagon"; | ||
export type TreasureValue = number; | ||
export type TreasureLevel = 1 | 2 | 3 | 4; | ||
|
||
export function createInitialState(numPlayers: NumPlayers): GameState { | ||
const treasurePieces: TreasurePiece[] = shuffle(createTreasurePieces()); | ||
const players: Player[] = createPlayers(numPlayers); | ||
return { | ||
players, | ||
remainingAir: 25, | ||
diveRoute: treasurePieces, | ||
whoseTurn: players[0].id, | ||
lastRoll: null, | ||
}; | ||
} | ||
function shuffle<T>(arr: T[]): T[] { | ||
return [...arr].sort(() => (Math.random() < 0.5 ? -1 : 1)); | ||
} | ||
|
||
function createTreasurePieces(): TreasurePiece[] { | ||
const pieces: TreasurePiece[] = []; | ||
let pieceId = 1; | ||
for (let value = 0; value < 16; value++) { | ||
const level = (1 + Math.floor(value / 4)) as TreasureLevel; | ||
if (!isTreasureLevel(level)) { | ||
throw new Error( | ||
"illegal treasure level: " + level + " from value: " + value | ||
); | ||
} | ||
|
||
for (let i = 0; i < 2; i++) { | ||
const piece: TreasurePiece = { | ||
id: ("" + pieceId++) as PieceId, | ||
tag: "treasure", | ||
state: "faceDown", | ||
shape: shapeForTreasureLevel(level), | ||
value, | ||
}; | ||
pieces.push(piece); | ||
} | ||
} | ||
return pieces; | ||
} | ||
function shapeForTreasureLevel(level: TreasureLevel): TreasureShape { | ||
const lookup: Record<TreasureLevel, TreasureShape> = { | ||
1: "triangle", | ||
2: "square", | ||
3: "pentagon", | ||
4: "hexagon", | ||
}; | ||
const s = lookup[level]; | ||
if (s === undefined) { | ||
throw new Error("missing shape for level: " + level); | ||
} | ||
return s; | ||
} | ||
function isTreasureLevel(level: number): level is TreasureLevel { | ||
return [1, 2, 3, 4].includes(level); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { TreasurePiece } from "./GameState"; | ||
|
||
export type NumPlayers = 2 | 3 | 4 | 5 | 6; | ||
export type DiveRoutePosition = number & { __brand: "diveRoutePosition" }; | ||
export type PlayerId = string & { readonly __brand: "playerId" }; | ||
export interface Player { | ||
id: PlayerId; | ||
isDescending: boolean; | ||
num: NumPlayers; | ||
score: number; | ||
position: DiveRoutePosition | "on-boat"; | ||
carried: TreasurePiece[]; | ||
} | ||
export function createPlayers(numPlayers: NumPlayers): Player[] { | ||
const players: Player[] = []; | ||
|
||
for (let i = 0; i < numPlayers; i++) { | ||
const id = ("player_" + (players.length + 1)) as PlayerId; | ||
const p: Player = { | ||
id, | ||
num: (i + 1) as NumPlayers, | ||
score: 10, | ||
carried: [], | ||
isDescending: true, | ||
position: | ||
i === 0 | ||
? "on-boat" | ||
: (Math.floor(Math.random() * 10) as DiveRoutePosition), //"on-boat", | ||
}; | ||
players.push(p); | ||
} | ||
return players; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,65 @@ | ||
html { | ||
background: #f8f8f8; | ||
font-size: 30px; | ||
} | ||
|
||
.diveRoute { | ||
display: flex; | ||
flex-direction: row; | ||
gap: 0.5rem; | ||
flex-wrap: wrap; | ||
} | ||
|
||
.diveRoutePiece { | ||
background: lightblue; | ||
padding: 0.5rem; | ||
aspect-ratio: 1; | ||
display: grid; | ||
place-items: center; | ||
width: 100px; | ||
} | ||
|
||
.diveRoutePiece.blank { | ||
border-radius: 50%; | ||
} | ||
|
||
.diveRoutePiece.pentagon { | ||
clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); | ||
} | ||
.diveRoutePiece.hexagon { | ||
clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%); | ||
} | ||
.diveRoutePiece.triangle { | ||
clip-path: polygon(50% 0%, 100% 100%, 0% 100%); | ||
} | ||
|
||
.player { | ||
border-radius: 50%; | ||
aspect-ratio: 1; | ||
width: 1.5rem; | ||
display: grid; | ||
place-items: center; | ||
} | ||
|
||
.player.p1 { | ||
background: lime; | ||
} | ||
.player.p2 { | ||
background: tomato; | ||
} | ||
.player.p3 { | ||
background: yellow; | ||
} | ||
.player.p4 { | ||
background: purple; | ||
} | ||
.player.p5 { | ||
background: black; | ||
} | ||
.player.p6 { | ||
background: white; | ||
} | ||
|
||
button { | ||
font-size: 2rem; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import clsx from "clsx"; | ||
import { Piece } from "../GameState"; | ||
import { ReactNode } from "react"; | ||
|
||
export function DiveRoutePieceView({ | ||
piece, | ||
children, | ||
}: { | ||
piece: Piece; | ||
children: ReactNode; | ||
}): JSX.Element { | ||
return ( | ||
<div | ||
className={clsx( | ||
"diveRoutePiece", | ||
piece.tag, | ||
piece.tag === "treasure" && piece.shape | ||
)} | ||
> | ||
{piece.tag === "blank" ? "C" : piece.id} | ||
{children} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Player } from "../Player"; | ||
|
||
export function PlayerSummary({ player }: { player: Player }): JSX.Element { | ||
return ( | ||
<div className="playerSummary"> | ||
id: {player.id} | ||
score: {player.score} | ||
carried: {player.carried.length} | ||
position: {player.position} | ||
</div> | ||
); | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export type Action = NoOpAction | RollToSwimAction; | ||
interface NoOpAction { | ||
tag: "no-op"; | ||
} | ||
interface RollToSwimAction { | ||
tag: "roll-to-swim"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { GameState } from "../GameState"; | ||
import { DiveRoutePosition } from "../Player"; | ||
import { randomRoll } from "./reducerFunction"; | ||
|
||
export function doRollToSwim(draft: GameState) { | ||
const roll = randomRoll(); | ||
const p = draft.players[0]; | ||
|
||
if (p.position === "on-boat") { | ||
p.position = (roll.sum - 1) as DiveRoutePosition; | ||
} else { | ||
if (p.isDescending) { | ||
p.position = Math.min( | ||
p.position + roll.sum, | ||
draft.diveRoute.length - 1 | ||
) as DiveRoutePosition; | ||
if (p.position === draft.diveRoute.length - 1) { | ||
p.isDescending = false; | ||
} | ||
} else { | ||
const result = Math.max(p.position + roll.sum, -1); | ||
p.position = | ||
result === -1 ? "on-boat" : (result as DiveRoutePosition); | ||
} | ||
} | ||
draft.lastRoll = roll; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { original } from "immer"; | ||
import { Action } from "./Action"; | ||
import { GameState } from "../GameState"; | ||
import { doRollToSwim } from "./doRollToSwim"; | ||
|
||
export function reducerFunction(draft: GameState, action: Action): void { | ||
console.log(original(draft)); | ||
switch (action.tag) { | ||
case "no-op": | ||
return; | ||
case "roll-to-swim": { | ||
doRollToSwim(draft); | ||
|
||
return; | ||
} | ||
} | ||
} | ||
|
||
export function randomRoll(): DiceRoll { | ||
const a = pick([1, 2, 3] as DieFace[]); | ||
const b = pick([1, 2, 3] as DieFace[]); | ||
const sum = (a + b) as DiceSum; | ||
return { sum, faces: [a, b] }; | ||
} | ||
export type DiceRoll = { sum: DiceSum; faces: [DieFace, DieFace] }; | ||
export type DiceSum = 2 | 3 | 4 | 5 | 6; | ||
export type DieFace = 1 | 2 | 3; | ||
|
||
function pick<T>(arr: T[]): T { | ||
return arr[Math.floor(Math.random() * arr.length)]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters