Skip to content

Commit

Permalink
Implement frontend colors
Browse files Browse the repository at this point in the history
  • Loading branch information
Comeza committed May 24, 2024
1 parent ac7541a commit 4990cfc
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 27 deletions.
2 changes: 1 addition & 1 deletion backend/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ fn main() -> std::io::Result<()> {
listener.set_nonblocking(true)?;
ws_listener.set_nonblocking(true)?;
let mut game = GameState {
board: Board::new(5, 5),
board: Board::new(20, 20),
chars: vec![None; 'z' as usize - 'A' as usize],
..Default::default()
};
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ def main():
init(url='localhost', port=1312)
width = int(getWidth())
height = int(getHeight())
for i in range(width * height):
while True:
# put random moves
put(random.randint(0, width - 1), random.randint(0, height - 1))
print(getBoard())
s.close()

if __name__ == '__main__':
main()
main()
Binary file modified frontend/bun.lockb
Binary file not shown.
38 changes: 30 additions & 8 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { Board } from "Board"
import { GameStateContext, GameStateProvider, parseMsg } from "lib/game";
import { GameStateContext, GameStateExt, GameStateProvider, parseMsg } from "lib/game";
import { WebSocketProvider, } from "lib/ws";
import { QRCodeSVG } from "qrcode.react"
import { useContext } from "react";
import { useContext, useEffect, useState } from "react";

export function App() {

function updateState(msg: string, gameStateExt: GameStateExt | null) {
return gameStateExt?.setState((state) => {
return ({
board: parseMsg(msg),
turn: state.turn + 1
})
});
}

return (<GameStateProvider>

<GameStateContext.Consumer>
{gameState =>
<WebSocketProvider url="ws://localhost:1213" onMsg={(msg) => gameState?.setState({ ...gameState, ...parseMsg(msg) })}>
<WebSocketProvider url="ws://localhost:1213" onMsg={(msg) => updateState(msg, gameState)}>

<div className="flex justify-center items-center w-dvw h-dvh">
<div className="flex flex-row h-dvh py-10">
Expand All @@ -30,20 +38,34 @@ export function App() {
function BoardWrapper() {
const gameState = useContext(GameStateContext);

const width = gameState?.width || 3;
const height = gameState?.height || 3;
const width = gameState?.board.width || 3;
const height = gameState?.board.height || 3;

return <Board width={width} height={height} board={gameState?.board || undefined} />
return <Board width={width} height={height} board={gameState?.board.board || undefined} />
}


function Sidebar() {
const gameState = useContext(GameStateContext);
const [start] = useState(new Date());
const [time, setTime] = useState("00:00");

return <div className="px-5 flex">
useEffect(() => {
const timeout = setInterval(() => {
const diff = new Date().getTime() - start.getTime();
const mins = Math.floor(diff / 60000);
const secs = Math.floor(diff / 1000) % 60;
setTime(mins.toString().padStart(2, '0') + ':' + secs.toString().padStart(2, '0'));
});

return () => clearInterval(timeout);
})

return <div className="px-5 flex mt-4">
<div className="h-full whitespace-nowrap font-mono font-bold text-xl flex flex-col leading-5">
<span>TURN: {gameState?.turn || 0}</span>
<span>SIZE: {gameState?.width || 3}x{gameState?.height || 3}</span>
<span>TIME: {time}</span>
<span>SIZE: {gameState?.board.width || 3}x{gameState?.board.height || 3}</span>
<hr className="bg-black h-[3px] py-2 mb-4" />
<a href="https://github.com/Lila-Kuhlt/mmgo" rel="noreferrer" target="_blank" >
<QRCodeSVG value="https://github.com/Lila-Kuhlt/mmgo" />
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/Board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ type BoardProps = {
width: number,
height: number,
board?: Player[]
backgroundColor?: string,
}

export function Board(props: React.PropsWithChildren<BoardProps>) {

const padding = 3;
const padding = 1;
const border = padding * 2;

const width = Math.max(props.width, 3) - 1;
Expand All @@ -35,6 +36,8 @@ export function Board(props: React.PropsWithChildren<BoardProps>) {

const spaceMin = Math.max(spaceV, spaceH);

const backgroundColor = props.backgroundColor || "#ffffff";

const range = (to: number) => [...new Array(to)].map((_, i) => i);

return <svg
Expand All @@ -46,7 +49,7 @@ export function Board(props: React.PropsWithChildren<BoardProps>) {
<rect
width={viewboxWidth + 2 * padding}
height={viewboxHeight + 2 * padding}
fill="#DCB35C"
fill={backgroundColor}
/>

{range(height + 1).map(i =>
Expand All @@ -73,7 +76,9 @@ export function Board(props: React.PropsWithChildren<BoardProps>) {
cx={p.x * spaceH + padding}
cy={p.y * spaceV + padding}
fill={p.color}
r={(Math.min(spaceMin / 2, padding)) * 0.9}
stroke={backgroundColor}
strokeWidth={.1}
r={(padding > 0 ? Math.min(spaceMin / 2, padding) : spaceMin / 2)}
/>)}

</svg>
Expand Down
46 changes: 46 additions & 0 deletions frontend/src/lib/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export const COLORS = [
"#63b598", "#ce7d78", "#ea9e70", "#a48a9e", "#c6e1e8", "#648177", "#0d5ac1",
"#f205e6", "#1c0365", "#14a9ad", "#4ca2f9", "#a4e43f", "#d298e2", "#6119d0",
"#d2737d", "#c0a43c", "#f2510e", "#651be6", "#79806e", "#61da5e", "#cd2f00",
"#9348af", "#01ac53", "#c5a4fb", "#996635", "#b11573", "#4bb473", "#75d89e",
"#2f3f94", "#2f7b99", "#da967d", "#34891f", "#b0d87b", "#ca4751", "#7e50a8",
"#c4d647", "#e0eeb8", "#11dec1", "#289812", "#566ca0", "#ffdbe1", "#2f1179",
"#935b6d", "#916988", "#513d98", "#aead3a", "#9e6d71", "#4b5bdc", "#0cd36d",
"#250662", "#cb5bea", "#228916", "#ac3e1b", "#df514a", "#539397", "#880977",
"#f697c1", "#ba96ce", "#679c9d", "#c6c42c", "#5d2c52", "#48b41b", "#e1cf3b",
"#5be4f0", "#57c4d8", "#a4d17a", "#be608b", "#96b00c", "#088baf", "#f158bf",
"#e145ba", "#ee91e3", "#05d371", "#5426e0", "#4834d0", "#802234", "#6749e8",
"#0971f0", "#8fb413", "#b2b4f0", "#c3c89d", "#c9a941", "#41d158", "#fb21a3",
"#51aed9", "#5bb32d", "#21538e", "#89d534", "#d36647", "#7fb411", "#0023b8",
"#3b8c2a", "#986b53", "#f50422", "#983f7a", "#ea24a3", "#79352c", "#521250",
"#c79ed2", "#d6dd92", "#e33e52", "#b2be57", "#fa06ec", "#1bb699", "#6b2e5f",
"#64820f", "#21538e", "#89d534", "#d36647", "#7fb411", "#0023b8", "#3b8c2a",
"#986b53", "#f50422", "#983f7a", "#ea24a3", "#79352c", "#521250", "#c79ed2",
"#d6dd92", "#e33e52", "#b2be57", "#fa06ec", "#1bb699", "#6b2e5f", "#64820f",
"#9cb64a", "#996c48", "#9ab9b7", "#06e052", "#e3a481", "#0eb621", "#fc458e",
"#b2db15", "#aa226d", "#792ed8", "#73872a", "#520d3a", "#cefcb8", "#a5b3d9",
"#7d1d85", "#c4fd57", "#f1ae16", "#8fe22a", "#ef6e3c", "#243eeb", "#dd93fd",
"#3f8473", "#e7dbce", "#421f79", "#7a3d93", "#635f6d", "#93f2d7", "#9b5c2a",
"#15b9ee", "#0f5997", "#409188", "#911e20", "#1350ce", "#10e5b1", "#fff4d7",
"#cb2582", "#ce00be", "#32d5d6", "#608572", "#c79bc2", "#00f87c", "#77772a",
"#6995ba", "#fc6b57", "#f07815", "#8fd883", "#060e27", "#96e591", "#21d52e",
"#d00043", "#b47162", "#1ec227", "#4f0f6f", "#1d1d58", "#947002", "#bde052",
"#e08c56", "#28fcfd", "#36486a", "#d02e29", "#1ae6db", "#3e464c", "#a84a8f",
"#911e7e", "#3f16d9", "#0f525f", "#ac7c0a", "#b4c086", "#c9d730", "#30cc49",
"#3d6751", "#fb4c03", "#640fc1", "#62c03e", "#d3493a", "#88aa0b", "#406df9",
"#615af0", "#2a3434", "#4a543f", "#79bca0", "#a8b8d4", "#00efd4", "#7ad236",
"#7260d8", "#1deaa7", "#06f43a", "#823c59", "#e3d94c", "#dc1c06", "#f53b2a",
"#b46238", "#2dfff6", "#a82b89", "#1a8011", "#436a9f", "#1a806a", "#4cf09d",
"#c188a2", "#67eb4b", "#b308d3", "#fc7e41", "#af3101", "#71b1f4", "#a2f8a5",
"#e23dd0", "#d3486d", "#00f7f9", "#474893", "#3cec35", "#1c65cb", "#5d1d0c",
"#2d7d2a", "#ff3420", "#5cdd87", "#a259a4", "#e4ac44", "#1bede6", "#8798a4",
"#d7790f", "#b2c24f", "#de73c2", "#d70a9c", "#88e9b8", "#c2b0e2", "#86e98f",
"#ae90e2", "#1a806b", "#436a9e", "#0ec0ff", "#f812b3", "#b17fc9", "#8d6c2f",
"#d3277a", "#2ca1ae", "#9685eb", "#8a96c6", "#dba2e6", "#76fc1b", "#608fa4",
"#20f6ba", "#07d7f6", "#dce77a", "#77ecca"
];

export function getColorFromChar(char: string): string {
return COLORS[char.charCodeAt(0) - 65];
}

36 changes: 23 additions & 13 deletions frontend/src/lib/game.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PropsWithChildren, createContext, useState } from "react";
import { getColorFromChar } from "./colors";

export type Player = {
x: number,
Expand All @@ -7,44 +8,53 @@ export type Player = {
}

export interface GameState {
board: Board,
turn: number,
}

export interface Board {
board: Player[],
width: number,
height: number,
turn: number,
height: number
}

export type GameStateExt = GameState & { setState: (state: GameState) => void };

export type GameStateExt = GameState & { setState: React.Dispatch<React.SetStateAction<GameState>> };

export const GameStateContext = createContext<GameStateExt | null>(null);

export function GameStateProvider(props: PropsWithChildren) {
const [gameState, setState] = useState(() => ({ width: 3, height: 3, turn: 0, board: parseBoard('.........', 3, 3) }));
const stateExt: GameStateExt = { ...gameState, setState: (game: GameState) => setState(game) };
const [gameState, setState] = useState<GameState>({
turn: 0,
board: parseBoard('.........', 3, 3)
});

const stateExt: GameStateExt = { ...gameState, setState };

return <GameStateContext.Provider value={stateExt}>
{props.children}
</GameStateContext.Provider>
}


export function parseMsg(msg: string): { board: Player[], width: number, height: number } {
export function parseMsg(msg: string): Board {
const [_, widthStr, heightStr, pieces] = msg.split(" ");

const width = parseInt(widthStr)
const height = parseInt(heightStr)

const board = parseBoard(pieces, width, height);

return { width, height, board }
return parseBoard(pieces, width, height)
}

export function parseBoard(encBoard: string, width: number, height: number): Player[] {
return encBoard.split('')
export function parseBoard(encBoard: string, width: number, height: number): Board {
const board = encBoard.split('')
.map((color, index) => ({
x: index % width,
y: height - 1 - Math.floor((index) / width),
color
})
)
}))
.filter(piece => piece.color !== '.')
.map(piece => ({ ...piece, color: getColorFromChar(piece.color) }))

return { board, width, height }
}

0 comments on commit 4990cfc

Please sign in to comment.