feat: integrate memory pairs game with arena champions and N-player support
- Update MemoryPairsContext to use GameMode arena champions instead of UserProfile - Extend game support from 2 players to N players with dynamic player IDs - Update PlayerScore interface from fixed structure to dynamic object mapping - Modify GamePhase to display actual arena champion names, emojis, and colors - Update ResultsPhase to show all arena champions with proper winner calculation - Add getMultiplayerWinner utility function for N-player winner determination - Fix TypeScript errors from GameMode type changes (single | multiplayer) - Ensure proper score tracking and turn switching for any number of players 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
'use client'
|
||||
|
||||
import { useMemoryPairs } from '../context/MemoryPairsContext'
|
||||
import { useUserProfile } from '../../../../contexts/UserProfileContext'
|
||||
import { useGameMode } from '../../../../contexts/GameModeContext'
|
||||
import { MemoryGrid } from './MemoryGrid'
|
||||
import { css } from '../../../../../styled-system/css'
|
||||
|
||||
export function GamePhase() {
|
||||
const { state, resetGame } = useMemoryPairs()
|
||||
const { profile } = useUserProfile()
|
||||
const { state, resetGame, activePlayers } = useMemoryPairs()
|
||||
const { players } = useGameMode()
|
||||
|
||||
// Get the current player from the arena champions
|
||||
const currentPlayerData = players.find(p => p.id === state.currentPlayer)
|
||||
const activePlayerData = players.filter(p => activePlayers.includes(p.id))
|
||||
|
||||
return (
|
||||
<div className={css({
|
||||
@@ -73,7 +77,7 @@ export function GamePhase() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{state.gameMode === 'two-player' && (
|
||||
{state.gameMode === 'multiplayer' && (
|
||||
<div className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -85,7 +89,7 @@ export function GamePhase() {
|
||||
})}>
|
||||
<span className={css({ fontSize: '20px' })}>⚔️</span>
|
||||
<span className={css({ fontWeight: 'bold', color: 'gray.700' })}>
|
||||
Two Players
|
||||
{activePlayers.length} Players
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -129,8 +133,8 @@ export function GamePhase() {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Timer (if two-player mode) */}
|
||||
{state.gameMode === 'two-player' && (
|
||||
{/* Timer (if multiplayer mode) */}
|
||||
{state.gameMode === 'multiplayer' && (
|
||||
<div className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -149,8 +153,8 @@ export function GamePhase() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current Player Indicator (Two-Player Mode) */}
|
||||
{state.gameMode === 'two-player' && (
|
||||
{/* Current Player Indicator (Multiplayer Mode) */}
|
||||
{state.gameMode === 'multiplayer' && currentPlayerData && (
|
||||
<div className={css({
|
||||
marginTop: '16px',
|
||||
textAlign: 'center'
|
||||
@@ -160,9 +164,7 @@ export function GamePhase() {
|
||||
alignItems: 'center',
|
||||
gap: '12px',
|
||||
padding: '12px 24px',
|
||||
background: state.currentPlayer === 1
|
||||
? 'linear-gradient(135deg, #74b9ff, #0984e3)'
|
||||
: 'linear-gradient(135deg, #fd79a8, #e84393)',
|
||||
background: `linear-gradient(135deg, ${currentPlayerData.color}, ${currentPlayerData.color}dd)`,
|
||||
color: 'white',
|
||||
borderRadius: '20px',
|
||||
fontSize: '18px',
|
||||
@@ -170,11 +172,11 @@ export function GamePhase() {
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.2)'
|
||||
})}>
|
||||
<span className={css({ fontSize: '48px' })}>
|
||||
{state.currentPlayer === 1 ? profile.player1Emoji : profile.player2Emoji}
|
||||
{currentPlayerData.emoji}
|
||||
</span>
|
||||
<span>Your Turn</span>
|
||||
<span>{currentPlayerData.name}'s Turn</span>
|
||||
<span className={css({ fontSize: '24px' })}>
|
||||
{state.currentPlayer === 1 ? '🎯' : '🎮'}
|
||||
🎯
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -205,7 +207,7 @@ export function GamePhase() {
|
||||
}
|
||||
</p>
|
||||
|
||||
{state.gameMode === 'two-player' && (
|
||||
{state.gameMode === 'multiplayer' && (
|
||||
<p className={css({
|
||||
fontSize: '14px',
|
||||
color: 'gray.500',
|
||||
|
||||
@@ -86,8 +86,8 @@ export function MemoryGrid() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Two-Player Scores */}
|
||||
{state.gameMode === 'two-player' && (
|
||||
{/* Multiplayer Scores */}
|
||||
{state.gameMode === 'multiplayer' && (
|
||||
<div className={css({ display: 'flex', alignItems: 'center', gap: '24px' })}>
|
||||
<button
|
||||
className={css({
|
||||
@@ -115,7 +115,7 @@ export function MemoryGrid() {
|
||||
{profile.player1Emoji}
|
||||
</div>
|
||||
<div className={css({ fontSize: '28px', fontWeight: 'bold', color: 'blue.600' })}>
|
||||
{state.scores.player1}
|
||||
{state.scores[1] || 0}
|
||||
</div>
|
||||
<div className={css({ fontSize: '12px', color: 'gray.600', marginTop: '4px' })}>
|
||||
Click to change character
|
||||
@@ -156,7 +156,7 @@ export function MemoryGrid() {
|
||||
{profile.player2Emoji}
|
||||
</div>
|
||||
<div className={css({ fontSize: '28px', fontWeight: 'bold', color: 'red.600' })}>
|
||||
{state.scores.player2}
|
||||
{state.scores[2] || 0}
|
||||
</div>
|
||||
<div className={css({ fontSize: '12px', color: 'gray.600', marginTop: '4px' })}>
|
||||
Click to change character
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
'use client'
|
||||
|
||||
import { useMemoryPairs } from '../context/MemoryPairsContext'
|
||||
import { useUserProfile } from '../../../../contexts/UserProfileContext'
|
||||
import { formatGameTime, getTwoPlayerWinner, getPerformanceAnalysis } from '../utils/gameScoring'
|
||||
import { useGameMode } from '../../../../contexts/GameModeContext'
|
||||
import { formatGameTime, getMultiplayerWinner, getPerformanceAnalysis } from '../utils/gameScoring'
|
||||
import { css } from '../../../../../styled-system/css'
|
||||
|
||||
export function ResultsPhase() {
|
||||
const { state, resetGame } = useMemoryPairs()
|
||||
const { profile } = useUserProfile()
|
||||
const { state, resetGame, activePlayers } = useMemoryPairs()
|
||||
const { players } = useGameMode()
|
||||
|
||||
// Get active player data
|
||||
const activePlayerData = players.filter(p => activePlayers.includes(p.id))
|
||||
|
||||
const gameTime = state.gameEndTime && state.gameStartTime
|
||||
? state.gameEndTime - state.gameStartTime
|
||||
: 0
|
||||
|
||||
const analysis = getPerformanceAnalysis(state)
|
||||
const twoPlayerResult = state.gameMode === 'two-player' ? getTwoPlayerWinner(state) : null
|
||||
const multiplayerResult = state.gameMode === 'multiplayer' ? getMultiplayerWinner(state, activePlayers) : null
|
||||
|
||||
return (
|
||||
<div className={css({
|
||||
@@ -43,23 +46,31 @@ export function ResultsPhase() {
|
||||
})}>
|
||||
Congratulations on completing the memory challenge!
|
||||
</p>
|
||||
) : twoPlayerResult && (
|
||||
) : multiplayerResult && (
|
||||
<div className={css({ marginBottom: '20px' })}>
|
||||
{twoPlayerResult.winner === 'tie' ? (
|
||||
{multiplayerResult.isTie ? (
|
||||
<p className={css({
|
||||
fontSize: '24px',
|
||||
color: 'purple.600',
|
||||
fontWeight: 'bold'
|
||||
})}>
|
||||
🤝 It's a tie! Both players are memory champions!
|
||||
🤝 It's a tie! All champions are memory masters!
|
||||
</p>
|
||||
) : (
|
||||
) : multiplayerResult.winners.length === 1 ? (
|
||||
<p className={css({
|
||||
fontSize: '24px',
|
||||
color: 'blue.600',
|
||||
fontWeight: 'bold'
|
||||
})}>
|
||||
🏆 Player {twoPlayerResult.winner} Wins!
|
||||
🏆 {activePlayerData.find(p => p.id === multiplayerResult.winners[0])?.name || `Player ${multiplayerResult.winners[0]}`} Wins!
|
||||
</p>
|
||||
) : (
|
||||
<p className={css({
|
||||
fontSize: '24px',
|
||||
color: 'purple.600',
|
||||
fontWeight: 'bold'
|
||||
})}>
|
||||
🏆 {multiplayerResult.winners.length} Champions tied for victory!
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -154,51 +165,45 @@ export function ResultsPhase() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Two-Player Scores */}
|
||||
{state.gameMode === 'two-player' && twoPlayerResult && (
|
||||
{/* Multiplayer Scores */}
|
||||
{state.gameMode === 'multiplayer' && multiplayerResult && (
|
||||
<div className={css({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
gap: '20px',
|
||||
marginBottom: '40px'
|
||||
marginBottom: '40px',
|
||||
flexWrap: 'wrap'
|
||||
})}>
|
||||
<div className={css({
|
||||
background: twoPlayerResult.winner === 1 ? 'linear-gradient(135deg, #ffd700, #ff8c00)' : 'linear-gradient(135deg, #c0c0c0, #808080)',
|
||||
color: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '16px',
|
||||
textAlign: 'center',
|
||||
minWidth: '150px'
|
||||
})}>
|
||||
<div className={css({ fontSize: '48px', marginBottom: '8px' })}>
|
||||
{profile.player1Emoji}
|
||||
</div>
|
||||
<div className={css({ fontSize: '36px', fontWeight: 'bold' })}>
|
||||
{state.scores.player1}
|
||||
</div>
|
||||
{twoPlayerResult.winner === 1 && (
|
||||
<div className={css({ fontSize: '24px' })}>👑</div>
|
||||
)}
|
||||
</div>
|
||||
{activePlayerData.map((player) => {
|
||||
const score = multiplayerResult.scores[player.id] || 0
|
||||
const isWinner = multiplayerResult.winners.includes(player.id)
|
||||
|
||||
<div className={css({
|
||||
background: twoPlayerResult.winner === 2 ? 'linear-gradient(135deg, #ffd700, #ff8c00)' : 'linear-gradient(135deg, #c0c0c0, #808080)',
|
||||
color: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '16px',
|
||||
textAlign: 'center',
|
||||
minWidth: '150px'
|
||||
})}>
|
||||
<div className={css({ fontSize: '48px', marginBottom: '8px' })}>
|
||||
{profile.player2Emoji}
|
||||
</div>
|
||||
<div className={css({ fontSize: '36px', fontWeight: 'bold' })}>
|
||||
{state.scores.player2}
|
||||
</div>
|
||||
{twoPlayerResult.winner === 2 && (
|
||||
<div className={css({ fontSize: '24px' })}>👑</div>
|
||||
)}
|
||||
</div>
|
||||
return (
|
||||
<div key={player.id} className={css({
|
||||
background: isWinner
|
||||
? 'linear-gradient(135deg, #ffd700, #ff8c00)'
|
||||
: 'linear-gradient(135deg, #c0c0c0, #808080)',
|
||||
color: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '16px',
|
||||
textAlign: 'center',
|
||||
minWidth: '150px'
|
||||
})}>
|
||||
<div className={css({ fontSize: '48px', marginBottom: '8px' })}>
|
||||
{player.emoji}
|
||||
</div>
|
||||
<div className={css({ fontSize: '14px', marginBottom: '4px', opacity: 0.9 })}>
|
||||
{player.name}
|
||||
</div>
|
||||
<div className={css({ fontSize: '36px', fontWeight: 'bold' })}>
|
||||
{score}
|
||||
</div>
|
||||
{isWinner && (
|
||||
<div className={css({ fontSize: '24px' })}>👑</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -33,14 +33,15 @@ export function SetupPhase() {
|
||||
state,
|
||||
setGameType,
|
||||
setDifficulty,
|
||||
dispatch
|
||||
dispatch,
|
||||
activePlayers
|
||||
} = useMemoryPairs()
|
||||
|
||||
const { activePlayerCount, gameMode: globalGameMode } = useGameMode()
|
||||
|
||||
const handleStartGame = () => {
|
||||
const cards = generateGameCards(state.gameType, state.difficulty)
|
||||
dispatch({ type: 'START_GAME', cards })
|
||||
dispatch({ type: 'START_GAME', cards, activePlayers })
|
||||
}
|
||||
|
||||
const getButtonStyles = (isSelected: boolean, variant: 'primary' | 'secondary' | 'difficulty' = 'primary') => {
|
||||
|
||||
@@ -10,7 +10,8 @@ import type {
|
||||
MemoryPairsContextValue,
|
||||
GameCard,
|
||||
GameStatistics,
|
||||
CelebrationAnimation
|
||||
CelebrationAnimation,
|
||||
PlayerScore
|
||||
} from './types'
|
||||
|
||||
// Initial state (gameMode removed - now derived from global context)
|
||||
@@ -31,7 +32,8 @@ const initialState: MemoryPairsState = {
|
||||
matchedPairs: 0,
|
||||
totalPairs: 6,
|
||||
moves: 0,
|
||||
scores: { player1: 0, player2: 0 },
|
||||
scores: {},
|
||||
activePlayers: [],
|
||||
|
||||
// Timing
|
||||
gameStartTime: null,
|
||||
@@ -71,6 +73,12 @@ function memoryPairsReducer(state: MemoryPairsState, action: MemoryPairsAction):
|
||||
}
|
||||
|
||||
case 'START_GAME':
|
||||
// Initialize scores for all active players
|
||||
const scores: PlayerScore = {}
|
||||
action.activePlayers.forEach(playerId => {
|
||||
scores[playerId] = 0
|
||||
})
|
||||
|
||||
return {
|
||||
...state,
|
||||
gamePhase: 'playing',
|
||||
@@ -79,8 +87,9 @@ function memoryPairsReducer(state: MemoryPairsState, action: MemoryPairsAction):
|
||||
flippedCards: [],
|
||||
matchedPairs: 0,
|
||||
moves: 0,
|
||||
scores: { player1: 0, player2: 0 },
|
||||
currentPlayer: 1,
|
||||
scores,
|
||||
activePlayers: action.activePlayers,
|
||||
currentPlayer: action.activePlayers[0] || 1,
|
||||
gameStartTime: Date.now(),
|
||||
gameEndTime: null,
|
||||
currentMoveStartTime: Date.now(),
|
||||
@@ -123,8 +132,7 @@ function memoryPairsReducer(state: MemoryPairsState, action: MemoryPairsAction):
|
||||
const newMatchedPairs = state.matchedPairs + 1
|
||||
const newScores = {
|
||||
...state.scores,
|
||||
[`player${state.currentPlayer}` as keyof typeof state.scores]:
|
||||
state.scores[`player${state.currentPlayer}` as keyof typeof state.scores] + 1
|
||||
[state.currentPlayer]: (state.scores[state.currentPlayer] || 0) + 1
|
||||
}
|
||||
|
||||
// Check if game is complete
|
||||
@@ -141,7 +149,7 @@ function memoryPairsReducer(state: MemoryPairsState, action: MemoryPairsAction):
|
||||
gamePhase: isGameComplete ? 'results' : 'playing',
|
||||
gameEndTime: isGameComplete ? Date.now() : null,
|
||||
isProcessingMove: false
|
||||
// Note: Player keeps turn after successful match in two-player mode
|
||||
// Note: Player keeps turn after successful match in multiplayer mode
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,11 +165,15 @@ function memoryPairsReducer(state: MemoryPairsState, action: MemoryPairsAction):
|
||||
}
|
||||
}
|
||||
|
||||
case 'SWITCH_PLAYER':
|
||||
case 'SWITCH_PLAYER': {
|
||||
// Cycle through all active players
|
||||
const currentIndex = state.activePlayers.indexOf(state.currentPlayer)
|
||||
const nextIndex = (currentIndex + 1) % state.activePlayers.length
|
||||
return {
|
||||
...state,
|
||||
currentPlayer: state.currentPlayer === 1 ? 2 : 1
|
||||
currentPlayer: state.activePlayers[nextIndex] || state.activePlayers[0]
|
||||
}
|
||||
}
|
||||
|
||||
case 'ADD_CELEBRATION':
|
||||
return {
|
||||
@@ -221,10 +233,13 @@ const MemoryPairsContext = createContext<MemoryPairsContextValue | null>(null)
|
||||
// Provider component
|
||||
export function MemoryPairsProvider({ children }: { children: ReactNode }) {
|
||||
const [state, dispatch] = useReducer(memoryPairsReducer, initialState)
|
||||
const { activePlayerCount } = useGameMode()
|
||||
const { activePlayerCount, players } = useGameMode()
|
||||
|
||||
// Get active players from GameMode context
|
||||
const activePlayers = players.filter(player => player.isActive).map(player => player.id)
|
||||
|
||||
// Derive game mode from active player count
|
||||
const gameMode = activePlayerCount > 1 ? 'two-player' : 'single'
|
||||
const gameMode = activePlayerCount > 1 ? 'multiplayer' : 'single'
|
||||
|
||||
// Handle card matching logic when two cards are flipped
|
||||
useEffect(() => {
|
||||
@@ -240,8 +255,8 @@ export function MemoryPairsProvider({ children }: { children: ReactNode }) {
|
||||
dispatch({ type: 'MATCH_FOUND', cardIds: [card1.id, card2.id] })
|
||||
} else {
|
||||
dispatch({ type: 'MATCH_FAILED', cardIds: [card1.id, card2.id] })
|
||||
// Switch player only in two-player mode
|
||||
if (gameMode === 'two-player') {
|
||||
// Switch player only in multiplayer mode
|
||||
if (gameMode === 'multiplayer') {
|
||||
dispatch({ type: 'SWITCH_PLAYER' })
|
||||
}
|
||||
}
|
||||
@@ -292,7 +307,7 @@ export function MemoryPairsProvider({ children }: { children: ReactNode }) {
|
||||
// Action creators
|
||||
const startGame = () => {
|
||||
const cards = generateGameCards(state.gameType, state.difficulty)
|
||||
dispatch({ type: 'START_GAME', cards })
|
||||
dispatch({ type: 'START_GAME', cards, activePlayers })
|
||||
}
|
||||
|
||||
const flipCard = (cardId: string) => {
|
||||
@@ -325,7 +340,8 @@ export function MemoryPairsProvider({ children }: { children: ReactNode }) {
|
||||
resetGame,
|
||||
setGameType,
|
||||
setDifficulty,
|
||||
gameMode // Expose derived gameMode
|
||||
gameMode, // Expose derived gameMode
|
||||
activePlayers // Expose active players
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// TypeScript interfaces for Memory Pairs Challenge game
|
||||
|
||||
export type GameMode = 'single' | 'two-player'
|
||||
export type GameMode = 'single' | 'multiplayer'
|
||||
export type GameType = 'abacus-numeral' | 'complement-pairs'
|
||||
export type GamePhase = 'setup' | 'playing' | 'results'
|
||||
export type CardType = 'abacus' | 'number' | 'complement'
|
||||
export type Difficulty = 6 | 8 | 12 | 15 // Number of pairs
|
||||
export type Player = 1 | 2
|
||||
export type Player = number // Now supports any player ID
|
||||
export type TargetSum = 5 | 10 | 20
|
||||
|
||||
export interface GameCard {
|
||||
@@ -20,8 +20,7 @@ export interface GameCard {
|
||||
}
|
||||
|
||||
export interface PlayerScore {
|
||||
player1: number
|
||||
player2: number
|
||||
[playerId: number]: number
|
||||
}
|
||||
|
||||
export interface CelebrationAnimation {
|
||||
@@ -59,6 +58,7 @@ export interface MemoryPairsState {
|
||||
totalPairs: number
|
||||
moves: number
|
||||
scores: PlayerScore
|
||||
activePlayers: Player[] // Track active player IDs
|
||||
|
||||
// Timing
|
||||
gameStartTime: number | null
|
||||
@@ -77,7 +77,7 @@ export type MemoryPairsAction =
|
||||
| { type: 'SET_GAME_TYPE'; gameType: GameType }
|
||||
| { type: 'SET_DIFFICULTY'; difficulty: Difficulty }
|
||||
| { type: 'SET_TURN_TIMER'; timer: number }
|
||||
| { type: 'START_GAME'; cards: GameCard[] }
|
||||
| { type: 'START_GAME'; cards: GameCard[]; activePlayers: Player[] }
|
||||
| { type: 'FLIP_CARD'; cardId: string }
|
||||
| { type: 'MATCH_FOUND'; cardIds: [string, string] }
|
||||
| { type: 'MATCH_FAILED'; cardIds: [string, string] }
|
||||
@@ -99,6 +99,7 @@ export interface MemoryPairsContextValue {
|
||||
canFlipCard: (cardId: string) => boolean
|
||||
currentGameStatistics: GameStatistics
|
||||
gameMode: GameMode // Derived from global context
|
||||
activePlayers: Player[] // Active player IDs from arena
|
||||
|
||||
// Actions
|
||||
startGame: () => void
|
||||
|
||||
@@ -65,7 +65,7 @@ export interface Achievement {
|
||||
earned: boolean
|
||||
}
|
||||
|
||||
export function getAchievements(state: MemoryPairsState, gameMode: 'single' | 'two-player'): Achievement[] {
|
||||
export function getAchievements(state: MemoryPairsState, gameMode: 'single' | 'multiplayer'): Achievement[] {
|
||||
const { matchedPairs, totalPairs, moves, scores, gameStartTime, gameEndTime } = state
|
||||
const accuracy = moves > 0 ? (matchedPairs / moves) * 100 : 0
|
||||
const gameTime = gameStartTime && gameEndTime ? gameEndTime - gameStartTime : 0
|
||||
@@ -112,17 +112,17 @@ export function getAchievements(state: MemoryPairsState, gameMode: 'single' | 't
|
||||
name: 'Two-Player Triumph',
|
||||
description: 'Win a two-player game',
|
||||
icon: '👥',
|
||||
earned: gameMode === 'two-player' && matchedPairs === totalPairs &&
|
||||
(scores.player1 > scores.player2 || scores.player2 > scores.player1)
|
||||
earned: gameMode === 'multiplayer' && matchedPairs === totalPairs &&
|
||||
Object.keys(scores).length > 1 && Math.max(...Object.values(scores)) > 0
|
||||
},
|
||||
{
|
||||
id: 'shutout_victory',
|
||||
name: 'Shutout Victory',
|
||||
description: 'Win a two-player game without opponent scoring',
|
||||
icon: '🛡️',
|
||||
earned: gameMode === 'two-player' && matchedPairs === totalPairs &&
|
||||
((scores.player1 === totalPairs && scores.player2 === 0) ||
|
||||
(scores.player2 === totalPairs && scores.player1 === 0))
|
||||
earned: gameMode === 'multiplayer' && matchedPairs === totalPairs &&
|
||||
Object.values(scores).some(score => score === totalPairs) &&
|
||||
Object.values(scores).some(score => score === 0)
|
||||
},
|
||||
{
|
||||
id: 'comeback_kid',
|
||||
@@ -259,26 +259,49 @@ export function getTwoPlayerWinner(state: MemoryPairsState): {
|
||||
} {
|
||||
const { scores } = state
|
||||
|
||||
if (scores.player1 > scores.player2) {
|
||||
if (scores[1] > scores[2]) {
|
||||
return {
|
||||
winner: 1,
|
||||
winnerScore: scores.player1,
|
||||
loserScore: scores.player2,
|
||||
margin: scores.player1 - scores.player2
|
||||
winnerScore: scores[1],
|
||||
loserScore: scores[2],
|
||||
margin: scores[1] - scores[2]
|
||||
}
|
||||
} else if (scores.player2 > scores.player1) {
|
||||
} else if (scores[2] > scores[1]) {
|
||||
return {
|
||||
winner: 2,
|
||||
winnerScore: scores.player2,
|
||||
loserScore: scores.player1,
|
||||
margin: scores.player2 - scores.player1
|
||||
winnerScore: scores[2],
|
||||
loserScore: scores[1],
|
||||
margin: scores[2] - scores[1]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
winner: 'tie',
|
||||
winnerScore: scores.player1,
|
||||
loserScore: scores.player2,
|
||||
winnerScore: scores[1],
|
||||
loserScore: scores[2],
|
||||
margin: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get multiplayer game winner (supports N players)
|
||||
export function getMultiplayerWinner(state: MemoryPairsState, activePlayers: Player[]): {
|
||||
winners: Player[]
|
||||
winnerScore: number
|
||||
scores: { [playerId: number]: number }
|
||||
isTie: boolean
|
||||
} {
|
||||
const { scores } = state
|
||||
|
||||
// Find the highest score
|
||||
const maxScore = Math.max(...activePlayers.map(playerId => scores[playerId] || 0))
|
||||
|
||||
// Find all players with the highest score
|
||||
const winners = activePlayers.filter(playerId => (scores[playerId] || 0) === maxScore)
|
||||
|
||||
return {
|
||||
winners,
|
||||
winnerScore: maxScore,
|
||||
scores,
|
||||
isTie: winners.length > 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user