diff --git a/src/components/BattleTable.tsx b/src/components/BattleTable.tsx new file mode 100644 index 0000000..3623206 --- /dev/null +++ b/src/components/BattleTable.tsx @@ -0,0 +1,113 @@ +import type { BasePlayer } from "../types"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { calculate, getRoundTable } from "../utils/common"; +import { Card, Divider, Flex, Space } from "antd"; +import styled from "styled-components"; +import { cloneDeep } from "lodash"; + +const StyledContainer = styled(Flex)` + .winer { + color: red; + position: relative; + ::after { + content: '胜'; + font-size: 0.8em; + background-color: red; + color: white; + padding: 0; + border-radius: 50%; + position: absolute; + } + } +`; + +function BattleTable({ + players: list, +}: { + players: BasePlayer[]; +}) { + const playerList = useMemo(() => list.length % 2 === 0 ? list : [...list, { + uid: '', + score: '', + name: '-', + }], [list]); + const resultMap = useMemo(() => new Map(), []); + const buildMatchGroupTable = useCallback((list: (BasePlayer | null)[]) => { + const roundNum = list.length - 1; + const dataList = cloneDeep(list); + const roundTable = new Array(roundNum).fill(0).map((_, i) => { + const [left, right] = getRoundTable(dataList, i); + left?.forEach((l, i) => { + const r = right?.[i]; + const key = `${l?.uid}-${r?.uid}`; + const winer = resultMap.get(key)?.winer; + const score = resultMap.get(key)?.score; + if (winer && l && r) { + if (winer === l?.uid) { + l.score = (+l.score + (score ?? 0)).toFixed(); + r.score = (+r.score - (score ?? 0)).toFixed(); + } else { + r.score = (+r.score + (score ?? 0)).toFixed(); + l.score = (+l.score - (score ?? 0)).toFixed(); + } + } + }); + return cloneDeep([left, right]); + }); + console.debug(roundTable); + return roundTable.filter(Boolean); + }, []); + const [matchGroupTable, setMatchGroupTable] = useState>([]); + + const handleWiner = useCallback((l?: BasePlayer, r?: BasePlayer, winer?: BasePlayer, loser?: BasePlayer) => { + if (!l?.uid || !r?.uid || !winer?.uid || !loser?.uid) return; + const key = `${l.uid}-${r.uid}`; + const score = calculate(+winer.score, +loser.score); + if (resultMap.get(key)?.winer) { + resultMap.delete(key); + } else { + resultMap.set(key, { winer: winer?.uid!, score }); + } + setMatchGroupTable(buildMatchGroupTable(playerList)); + }, []); + useEffect(() => { + const roundTable = buildMatchGroupTable(playerList); + setMatchGroupTable(roundTable); + }, [playerList]); + // console.debug('matchGroupTable', matchGroupTable, gameResultMap); + return ( + + {matchGroupTable.map(([left, right], i) => { + return ( + + {left?.map((l, i) => { + const r = right?.[i]; + const key = `${l?.uid}-${r?.uid}`; + const winer = resultMap.get(key)?.winer; + const score = resultMap.get(key)?.score; + const resultL = winer ? winer === l?.uid ? ` +${score}` : `-${score}` : '' + const resultR = winer ? winer === r?.uid ? ` +${score}` : `-${score}` : '' + const nameL = l?.uid ? `${l?.name}(${l?.score})${resultL}` : '-'; + const nameR = r?.uid ? `${r?.name}(${r?.score})${resultR}` : '-'; + return ( +
+ +
handleWiner(l!, r!, l!, r!)} style={{ width: 120 }}>{nameL}
+ VS +
handleWiner(l!, r!, r!, l!)} style={{ width: 120 }}>{nameR}
+
+ {i < left.length - 1 && } +
+ ); + })} +
+ ); + })} +
+ ); +} + +export default BattleTable; \ No newline at end of file diff --git a/src/components/GroupMember.tsx b/src/components/GroupMember.tsx index e9fc84b..f83ec33 100644 --- a/src/components/GroupMember.tsx +++ b/src/components/GroupMember.tsx @@ -1,8 +1,8 @@ import { useMemo, useState } from "react"; -import { Button, Card, Divider, Drawer, Flex, Space, Table } from "antd"; +import { Button, Card, Drawer, Table } from "antd"; import type { BasePlayer } from "../types"; -import { getRoundTable } from "../utils/common"; import User from "./User"; +import BattleTable from "./BattleTable"; interface Props { index: number; @@ -45,44 +45,8 @@ export const GroupMember: React.FC = props => { size={'80vh'} placement="bottom" > - e.name ? `(${i + 1}) ${e.name}(${e.score})` : '-') - ?? [] - } - /> + ); } - -function BattleTable({ nameList }: { - nameList: string[] -}) { - const list = nameList.length % 2 === 0 ? nameList : [...nameList, '-']; - return ( - - {new Array(list.length - 1).fill(0).map((_, i) => { - const [left, right] = getRoundTable(list, i); - return ( - - {left?.map((e, r) => { - return ( -
- -
{e}
- VS -
{right?.[r]}
-
- {r < left.length && } -
- ); - })} -
- ); - })} -
- ); -} diff --git a/src/utils/common.ts b/src/utils/common.ts index d7dd0d8..ef74086 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -22,8 +22,8 @@ export function sneckGroup(size: number, groupLen: number) { return newGroups; } -export function getRoundTable(nameList: T[], round: number) { - const list = [...nameList]; +export function getRoundTable(dataList: T[], round: number) { + const list = [...dataList]; const half = list.length / 2; if (round > list.length - 1) { const left = [...list].slice(0, half); @@ -44,4 +44,43 @@ export function getRoundTable(nameList: T[], round: number) { export function createGameID(matchId: string, user1: string, user2: string) { return [matchId, user1, user2].join('-'); +} + +export function higherWin(absScore: number) { + if (absScore <= 12) return 8; + if (absScore <= 37) return 7; + if (absScore <= 62) return 6; + if (absScore <= 87) return 5; + if (absScore <= 112) return 4; + if (absScore <= 137) return 3; + if (absScore <= 162) return 2; + if (absScore <= 187) return 2; + if (absScore <= 212) return 1; + if (absScore <= 237) return 1; + return 0; +} + +export function lowerWin(absScore: number) { + if (absScore <= 12) return 8; + if (absScore <= 37) return 10; + if (absScore <= 62) return 13; + if (absScore <= 87) return 16; + if (absScore <= 112) return 20; + if (absScore <= 137) return 25; + if (absScore <= 162) return 30; + if (absScore <= 187) return 35; + if (absScore <= 212) return 40; + if (absScore <= 237) return 45; + return 50; +} + +export function calculate(winerScore: number, loserScore: number) { + const absScore = Math.abs(winerScore - loserScore); + if (winerScore >= loserScore) { + console.debug('higherWin', absScore, { winerScore, loserScore }); + return higherWin(absScore); + } else { + console.debug('lowerWin', absScore, { winerScore, loserScore }); + return lowerWin(absScore); + } } \ No newline at end of file