import { motion } from 'framer-motion' import { Card as Card_Type, Rank, get_rank_symbol, get_suit_symbol, is_red_suit, Suit_Joker, Rank_Red_Joker } from '../game/types' import { Hand } from './Hand' import { Table } from './Table' import { Card_Back } from './Card' interface Play_Log_Entry { seat: number cards: Card_Type[] combo_type: string is_pass: boolean } interface Game_Props { hand: Card_Type[] level: Rank selected_ids: Set on_card_click: (id: number) => void on_play: () => void on_pass: () => void table_cards: Card_Type[] combo_type: string current_turn: number my_seat: number can_pass: boolean player_card_counts: number[] team_levels: [number, number] play_log: Play_Log_Entry[] players_map: Record last_play_seat: number | null } export function Game({ hand, level, selected_ids, on_card_click, on_play, on_pass, table_cards, combo_type, current_turn, my_seat, can_pass, player_card_counts, team_levels, play_log, players_map, last_play_seat, }: Game_Props) { const is_my_turn = current_turn === my_seat const relative_positions = get_relative_positions(my_seat) return (
Level: {get_rank_symbol(level)}
Team 1: {get_rank_symbol(team_levels[0] as Rank)} Team 2: {get_rank_symbol(team_levels[1] as Rank)}
0 && hand.length > 0 ? '#28a745' : '#444', }} > Play 0 ? '#dc3545' : '#444', }} > Pass
{is_my_turn && hand.length > 0 && ( Your turn! )} {hand.length === 0 && ( You finished! )}
Play Log
{play_log.map((entry, i) => ( {players_map[entry.seat] || `Seat ${entry.seat + 1}`}: {' '} {entry.is_pass ? ( Pass ) : ( {entry.cards.map((c, j) => ( {get_rank_symbol(c.Rank)}{get_suit_symbol(c.Suit)}{j < entry.cards.length - 1 ? ' ' : ''} ))} {entry.combo_type && ({entry.combo_type})} )} ))}
) } interface Opponent_Hand_Props { count: number is_turn: boolean just_played?: boolean seat: number vertical?: boolean name?: string } function Opponent_Hand({ count, is_turn, just_played, seat, vertical, name }: Opponent_Hand_Props) { const display_count = Math.min(count, 10) const overlap = vertical ? 15 : 20 const get_highlight_style = () => { if (just_played) return { backgroundColor: 'rgba(76, 175, 80, 0.3)', border: '2px solid #4caf50' } if (is_turn) return { backgroundColor: 'rgba(255,193,7,0.2)', border: '2px solid #ffc107' } return { backgroundColor: 'transparent', border: '2px solid transparent' } } return (
{Array.from({ length: display_count }).map((_, i) => (
))}
{name || `Seat ${seat + 1}`}: {count}
) } function get_relative_positions(my_seat: number) { return { top: (my_seat + 2) % 4, left: (my_seat + 1) % 4, right: (my_seat + 3) % 4, } } const styles: Record = { container: { display: 'flex', flexDirection: 'column', height: '100vh', backgroundColor: '#0f3460', }, info_bar: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 24px', backgroundColor: '#16213e', }, level_badge: { padding: '8px 16px', backgroundColor: '#ffc107', color: '#000', borderRadius: 8, fontWeight: 'bold', }, team_scores: { color: '#fff', fontSize: 14, }, game_area: { flex: 1, display: 'flex', flexDirection: 'column', padding: 20, }, opponent_top: { display: 'flex', justifyContent: 'center', marginBottom: 20, }, middle_row: { flex: 1, display: 'flex', alignItems: 'center', }, opponent_side: { width: 120, display: 'flex', justifyContent: 'center', }, table_area: { flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.2)', borderRadius: 16, margin: '0 20px', }, my_area: { display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: 20, borderTop: '2px solid #333', }, actions: { display: 'flex', gap: 16, marginTop: 16, }, action_button: { padding: '12px 32px', fontSize: 16, border: 'none', borderRadius: 8, color: '#fff', cursor: 'pointer', }, turn_indicator: { marginTop: 12, padding: '8px 16px', backgroundColor: '#ffc107', color: '#000', borderRadius: 8, fontWeight: 'bold', }, main_layout: { display: 'flex', flex: 1, overflow: 'hidden', }, play_log: { width: 220, backgroundColor: '#16213e', padding: 12, overflowY: 'auto', borderLeft: '2px solid #333', }, play_log_title: { color: '#fff', fontSize: 14, fontWeight: 'bold', marginBottom: 12, paddingBottom: 8, borderBottom: '1px solid #333', }, play_log_entry: { fontSize: 12, color: '#fff', padding: '6px 0', borderBottom: '1px solid rgba(255,255,255,0.1)', }, }