diff --git a/src/lib/counter-do.ts b/src/lib/counter-do.ts index 2708503..af1ce24 100644 --- a/src/lib/counter-do.ts +++ b/src/lib/counter-do.ts @@ -1,7 +1,11 @@ import type { DurableObjectNamespace, DurableObjectState } from '@cloudflare/workers-types'; -import type { Session, BettingInfo } from './types'; +import type { Session } from './types'; import { applyBetResults } from './game-results'; +// 게임 지속 시간 상수 (ms) +export const NO_MORE_BET_DURATION_MS = 15_000; // 15초 +export const BETTING_DURATION_MS = 45_000; // 45초 + export interface Env { COUNTER: DurableObjectNamespace; } @@ -141,18 +145,15 @@ export class CounterDurableObject { private startNoMoreBetPeriod() { this.noMoreBet = true; this.noMoreBetStartTime = Date.now(); - this.noMoreBetEndTime = this.noMoreBetStartTime + 15000; // 15초 + this.noMoreBetEndTime = this.noMoreBetStartTime + NO_MORE_BET_DURATION_MS; // 15초 // 3개의 주사위 랜덤 생성 (1-6) this.dice1 = Math.floor(Math.random() * 6) + 1; this.dice2 = Math.floor(Math.random() * 6) + 1; this.dice3 = Math.floor(Math.random() * 6) + 1; - // 주사위 합계 - const sum = this.dice1 + this.dice2 + this.dice3; - // 추출된 함수로 배팅 결과 계산 및 세션 갱신 - applyBetResults(this.sessions, sum); + applyBetResults(this.sessions, this.dice1, this.dice2, this.dice3); // 상태 저장 this.ctx.storage.put('noMoreBet', this.noMoreBet); @@ -166,14 +167,14 @@ export class CounterDurableObject { } this.gameTimer = setTimeout(() => { this.startBettingPeriod(); - }, 15000); + }, NO_MORE_BET_DURATION_MS); } // 2번 로직: noMoreBet = false, 45초간 유지 private startBettingPeriod() { this.noMoreBet = false; this.noMoreBetStartTime = Date.now(); - this.noMoreBetEndTime = this.noMoreBetStartTime + 45000; // 45초 + this.noMoreBetEndTime = this.noMoreBetStartTime + BETTING_DURATION_MS; // 45초 // 주사위 값 클리어 this.dice1 = null; @@ -205,7 +206,7 @@ export class CounterDurableObject { } this.gameTimer = setTimeout(() => { this.startNoMoreBetPeriod(); - }, 45000); + }, BETTING_DURATION_MS); } async webSocketClose(ws: WebSocket, code: number, _reason: string, _wasClean: boolean) { @@ -222,21 +223,6 @@ export class CounterDurableObject { // WebSocket Hibernation API를 사용할 때는 getWebSockets()로 실제 연결 수를 확인 const connectedWebSockets = this.ctx.getWebSockets(); - // 전체 사용자 배팅 내역 수집 - const allBettings: BettingInfo[] = []; - - this.sessions.forEach((session) => { - if (session.nickname && (session.oddBet > 0 || session.evenBet > 0 || session.bigBet > 0 || session.smallBet > 0)) { - allBettings.push({ - nickname: session.nickname, - oddBet: session.oddBet, - evenBet: session.evenBet, - bigBet: session.bigBet, - smallBet: session.smallBet - }); - } - }); - // 각 세션별로 메시지 전송 // @ts-ignore - Cloudflare Workers types 불일치 connectedWebSockets.forEach((ws: WebSocket) => { @@ -258,8 +244,7 @@ export class CounterDurableObject { bigResult: session?.bigResult, smallResult: session?.smallResult, lastWinAmount: session?.lastWinAmount, - // 전체 사용자 배팅 내역 - allBettings: allBettings + }); ws.send(message); diff --git a/src/lib/game-results.ts b/src/lib/game-results.ts index 03c1f04..256ad65 100644 --- a/src/lib/game-results.ts +++ b/src/lib/game-results.ts @@ -5,7 +5,9 @@ import type { Session } from './types'; * 승리 시 배팅금액 * 2 지급, 패배 시 이미 차감된 상태 유지. * lastWinAmount = (총 승리 수령액 - 총 배팅액) */ -export function applyBetResults(sessions: Map, sum: number) { +export function applyBetResults(sessions: Map, dice1: number, dice2: number, dice3: number) { + // 주사위 합계 + const sum = dice1 + dice2 + dice3; const isOdd = sum % 2 === 1; const isBig = sum >= 10; // 10~18: 대 diff --git a/src/lib/types.ts b/src/lib/types.ts index da547d5..98e37f5 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,82 +1,72 @@ export interface Session { - id: string; + token: string; webSocket: WebSocket; - nickname?: string; - capital?: number; - // 배팅 정보 - oddBet: number; - evenBet: number; - bigBet: number; - smallBet: number; - // 결과 - oddResult?: 'win' | 'lose' | null; - evenResult?: 'win' | 'lose' | null; - bigResult?: 'win' | 'lose' | null; - smallResult?: 'win' | 'lose' | null; - lastWinAmount?: number; + betInfo: BettingInfo[]; // 배팅 정보 + capital?: number; // 현재 자본금 } export interface BettingInfo { - nickname: string; - oddBet: number; - evenBet: number; - bigBet: number; - smallBet: number; + gameId: string; // 게임 고유 ID + betType: BetTypeKey; + betMoney: number; //배팅금액 + isWin?: boolean; //승리여부 + winMoney?: number; //승리금액 } export const BetType = { - BIG: { - category: 'A', - typeDescriptionEng: 'Big / Small Bet', - typeDescriptionKr: '대/소 배팅', - tripeLose: true, - key: 'big', - keyName: 'Big Bet', - rslt: 'big_rslt', - rsltName: 'Big Result', - winConditionDescription: '주사위 총합 10~18', - maxAmount: 300000, - payout: 2, - }, - SMALL: { - category: 'A', - typeDescriptionEng: 'Big / Small Bet', - typeDescriptionKr: '대/소 배팅', - tripeLose: true, - key: 'small', - keyName: 'Small Bet', - rslt: 'small_rslt', - rsltName: 'Small Result', - winConditionDescription: '주사위 총합 1~9', - maxAmount: 300000, - payout: 2, - }, - EVEN: { - category: 'B', - typeDescriptionEng: 'Even / Odd Bet', - typeDescriptionKr: '홀/짝 배팅', - tripeLose: true, - key: 'even', - keyName: 'Even Bet', - rslt: 'even_rslt', - rsltName: 'Even Result', - winConditionDescription: '주사위 총합 짝수', - maxAmount: 300000, - payout: 2, - }, - ODD: { - category: 'B', - typeDescriptionEng: 'Even / Odd Bet', - typeDescriptionKr: '홀/짝 배팅', - tripeLose: true, - key: 'odd', - keyName: 'Odd Bet', - rslt: 'odd_rslt', - rsltName: 'Odd Result', - winConditionDescription: '주사위 총합 홀수', - maxAmount: 300000, - payout: 2, - } + // 11~17 + Big: { maxBet: 300, payout: 1 }, + Small: { maxBet: 300, payout: 1 }, + Even: { maxBet: 300, payout: 1 }, + Odd: { maxBet: 300, payout: 1 }, + Pair1: { maxBet: 35, payout: 8 }, + Pair2: { maxBet: 35, payout: 8 }, + Pair3: { maxBet: 35, payout: 8 }, + Pair4: { maxBet: 35, payout: 8 }, + Pair5: { maxBet: 35, payout: 8 }, + Pair6: { maxBet: 35, payout: 8 }, + Triple1: { maxBet: 2, payout: 150 }, + Triple2: { maxBet: 2, payout: 150 }, + Triple3: { maxBet: 2, payout: 150 }, + Triple4: { maxBet: 2, payout: 150 }, + Triple5: { maxBet: 2, payout: 150 }, + Triple6: { maxBet: 2, payout: 150 }, + TripleAny: { maxBet: 10, payout: 24 }, + Total4: { maxBet: 5, payout: 50 }, + Total5: { maxBet: 10, payout: 30 }, + Total6: { maxBet: 15, payout: 18 }, + Total7: { maxBet: 25, payout: 12 }, + Total8: { maxBet: 35, payout: 8 }, + Total9: { maxBet: 50, payout: 6 }, + Total10: { maxBet: 50, payout: 6 }, + Total11: { maxBet: 50, payout: 6 }, + Total12: { maxBet: 50, payout: 6 }, + Total13: { maxBet: 35, payout: 8 }, + Total14: { maxBet: 25, payout: 12 }, + Total15: { maxBet: 15, payout: 18 }, + Total16: { maxBet: 10, payout: 30 }, + Total17: { maxBet: 5, payout: 50 }, + Domino12:{ maxBet: 60, payout: 5 }, + Domino13:{ maxBet: 60, payout: 5 }, + Domino14:{ maxBet: 60, payout: 5 }, + Domino15:{ maxBet: 60, payout: 5 }, + Domino16:{ maxBet: 60, payout: 5 }, + Domino23:{ maxBet: 60, payout: 5 }, + Domino24:{ maxBet: 60, payout: 5 }, + Domino25:{ maxBet: 60, payout: 5 }, + Domino26:{ maxBet: 60, payout: 5 }, + Domino34:{ maxBet: 60, payout: 5 }, + Domino35:{ maxBet: 60, payout: 5 }, + Domino36:{ maxBet: 60, payout: 5 }, + Domino45:{ maxBet: 60, payout: 5 }, + Domino46:{ maxBet: 60, payout: 5 }, + Domino56:{ maxBet: 60, payout: 5 }, + Single1_N1:{ maxBet: 100 }, + Single2_N1:{ maxBet: 100 }, + Single3_N1:{ maxBet: 100 }, + Single4_N1:{ maxBet: 100 }, + Single5_N1:{ maxBet: 100 }, + Single6_N1:{ maxBet: 100 }, } as const; export type BetTypeKey = keyof typeof BetType; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index ebf072d..bd55d1e 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -538,61 +538,6 @@ {/if} - - {#if isConnected && allBettings.length > 0} -
-

- 📊 전체 배팅 현황 -

-
- {#each allBettings as betting} -
-
{betting.nickname}
-
- {#if betting.oddBet > 0} -
-
-
{betting.oddBet.toLocaleString()}
-
- {/if} - {#if betting.evenBet > 0} -
-
-
{betting.evenBet.toLocaleString()}
-
- {/if} - {#if betting.bigBet > 0} -
-
-
{betting.bigBet.toLocaleString()}
-
- {/if} - {#if betting.smallBet > 0} -
-
-
{betting.smallBet.toLocaleString()}
-
- {/if} -
-
- {/each} -
-
- {/if} - - -
-

게임 규칙

-
    -
  • ✅ Cloudflare Durable Objects로 상태 관리
  • -
  • ✅ WebSocket으로 실시간 양방향 통신
  • -
  • 🎲 베팅 기간 (45초): 홀수 또는 짝수 선택 가능
  • -
  • 🚫 베팅 마감 (15초): 주사위 결과 확인 및 대기
  • -
  • 📊 Progress bar로 남은 시간 시각화
  • -
  • 🔄 게임은 자동으로 반복됩니다
  • -
  • 👥 모든 접속자에게 실시간 동기화
  • -
-