이것저것 수정중.. 지금상태로는 안돌아감

This commit is contained in:
pd0a6847 2025-11-19 17:28:38 +09:00
parent 992737ef33
commit 97a0533afd
4 changed files with 75 additions and 153 deletions

View File

@ -1,7 +1,11 @@
import type { DurableObjectNamespace, DurableObjectState } from '@cloudflare/workers-types'; import type { DurableObjectNamespace, DurableObjectState } from '@cloudflare/workers-types';
import type { Session, BettingInfo } from './types'; import type { Session } from './types';
import { applyBetResults } from './game-results'; 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 { export interface Env {
COUNTER: DurableObjectNamespace; COUNTER: DurableObjectNamespace;
} }
@ -141,18 +145,15 @@ export class CounterDurableObject {
private startNoMoreBetPeriod() { private startNoMoreBetPeriod() {
this.noMoreBet = true; this.noMoreBet = true;
this.noMoreBetStartTime = Date.now(); this.noMoreBetStartTime = Date.now();
this.noMoreBetEndTime = this.noMoreBetStartTime + 15000; // 15초 this.noMoreBetEndTime = this.noMoreBetStartTime + NO_MORE_BET_DURATION_MS; // 15초
// 3개의 주사위 랜덤 생성 (1-6) // 3개의 주사위 랜덤 생성 (1-6)
this.dice1 = Math.floor(Math.random() * 6) + 1; this.dice1 = Math.floor(Math.random() * 6) + 1;
this.dice2 = Math.floor(Math.random() * 6) + 1; this.dice2 = Math.floor(Math.random() * 6) + 1;
this.dice3 = 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); this.ctx.storage.put('noMoreBet', this.noMoreBet);
@ -166,14 +167,14 @@ export class CounterDurableObject {
} }
this.gameTimer = setTimeout(() => { this.gameTimer = setTimeout(() => {
this.startBettingPeriod(); this.startBettingPeriod();
}, 15000); }, NO_MORE_BET_DURATION_MS);
} }
// 2번 로직: noMoreBet = false, 45초간 유지 // 2번 로직: noMoreBet = false, 45초간 유지
private startBettingPeriod() { private startBettingPeriod() {
this.noMoreBet = false; this.noMoreBet = false;
this.noMoreBetStartTime = Date.now(); this.noMoreBetStartTime = Date.now();
this.noMoreBetEndTime = this.noMoreBetStartTime + 45000; // 45초 this.noMoreBetEndTime = this.noMoreBetStartTime + BETTING_DURATION_MS; // 45초
// 주사위 값 클리어 // 주사위 값 클리어
this.dice1 = null; this.dice1 = null;
@ -205,7 +206,7 @@ export class CounterDurableObject {
} }
this.gameTimer = setTimeout(() => { this.gameTimer = setTimeout(() => {
this.startNoMoreBetPeriod(); this.startNoMoreBetPeriod();
}, 45000); }, BETTING_DURATION_MS);
} }
async webSocketClose(ws: WebSocket, code: number, _reason: string, _wasClean: boolean) { async webSocketClose(ws: WebSocket, code: number, _reason: string, _wasClean: boolean) {
@ -222,21 +223,6 @@ export class CounterDurableObject {
// WebSocket Hibernation API를 사용할 때는 getWebSockets()로 실제 연결 수를 확인 // WebSocket Hibernation API를 사용할 때는 getWebSockets()로 실제 연결 수를 확인
const connectedWebSockets = this.ctx.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 불일치 // @ts-ignore - Cloudflare Workers types 불일치
connectedWebSockets.forEach((ws: WebSocket) => { connectedWebSockets.forEach((ws: WebSocket) => {
@ -258,8 +244,7 @@ export class CounterDurableObject {
bigResult: session?.bigResult, bigResult: session?.bigResult,
smallResult: session?.smallResult, smallResult: session?.smallResult,
lastWinAmount: session?.lastWinAmount, lastWinAmount: session?.lastWinAmount,
// 전체 사용자 배팅 내역
allBettings: allBettings
}); });
ws.send(message); ws.send(message);

View File

@ -5,7 +5,9 @@ import type { Session } from './types';
* * 2 , . * * 2 , .
* lastWinAmount = ( - ) * lastWinAmount = ( - )
*/ */
export function applyBetResults(sessions: Map<WebSocket, Session>, sum: number) { export function applyBetResults(sessions: Map<WebSocket, Session>, dice1: number, dice2: number, dice3: number) {
// 주사위 합계
const sum = dice1 + dice2 + dice3;
const isOdd = sum % 2 === 1; const isOdd = sum % 2 === 1;
const isBig = sum >= 10; // 10~18: 대 const isBig = sum >= 10; // 10~18: 대

View File

@ -1,82 +1,72 @@
export interface Session { export interface Session {
id: string; token: string;
webSocket: WebSocket; webSocket: WebSocket;
nickname?: string; betInfo: BettingInfo[]; // 배팅 정보
capital?: number; 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;
} }
export interface BettingInfo { export interface BettingInfo {
nickname: string; gameId: string; // 게임 고유 ID
oddBet: number; betType: BetTypeKey;
evenBet: number; betMoney: number; //배팅금액
bigBet: number; isWin?: boolean; //승리여부
smallBet: number; winMoney?: number; //승리금액
} }
export const BetType = { export const BetType = {
BIG: { // 11~17
category: 'A', Big: { maxBet: 300, payout: 1 },
typeDescriptionEng: 'Big / Small Bet', Small: { maxBet: 300, payout: 1 },
typeDescriptionKr: '대/소 배팅', Even: { maxBet: 300, payout: 1 },
tripeLose: true, Odd: { maxBet: 300, payout: 1 },
key: 'big', Pair1: { maxBet: 35, payout: 8 },
keyName: 'Big Bet', Pair2: { maxBet: 35, payout: 8 },
rslt: 'big_rslt', Pair3: { maxBet: 35, payout: 8 },
rsltName: 'Big Result', Pair4: { maxBet: 35, payout: 8 },
winConditionDescription: '주사위 총합 10~18', Pair5: { maxBet: 35, payout: 8 },
maxAmount: 300000, Pair6: { maxBet: 35, payout: 8 },
payout: 2, Triple1: { maxBet: 2, payout: 150 },
}, Triple2: { maxBet: 2, payout: 150 },
SMALL: { Triple3: { maxBet: 2, payout: 150 },
category: 'A', Triple4: { maxBet: 2, payout: 150 },
typeDescriptionEng: 'Big / Small Bet', Triple5: { maxBet: 2, payout: 150 },
typeDescriptionKr: '대/소 배팅', Triple6: { maxBet: 2, payout: 150 },
tripeLose: true, TripleAny: { maxBet: 10, payout: 24 },
key: 'small', Total4: { maxBet: 5, payout: 50 },
keyName: 'Small Bet', Total5: { maxBet: 10, payout: 30 },
rslt: 'small_rslt', Total6: { maxBet: 15, payout: 18 },
rsltName: 'Small Result', Total7: { maxBet: 25, payout: 12 },
winConditionDescription: '주사위 총합 1~9', Total8: { maxBet: 35, payout: 8 },
maxAmount: 300000, Total9: { maxBet: 50, payout: 6 },
payout: 2, Total10: { maxBet: 50, payout: 6 },
}, Total11: { maxBet: 50, payout: 6 },
EVEN: { Total12: { maxBet: 50, payout: 6 },
category: 'B', Total13: { maxBet: 35, payout: 8 },
typeDescriptionEng: 'Even / Odd Bet', Total14: { maxBet: 25, payout: 12 },
typeDescriptionKr: '홀/짝 배팅', Total15: { maxBet: 15, payout: 18 },
tripeLose: true, Total16: { maxBet: 10, payout: 30 },
key: 'even', Total17: { maxBet: 5, payout: 50 },
keyName: 'Even Bet', Domino12:{ maxBet: 60, payout: 5 },
rslt: 'even_rslt', Domino13:{ maxBet: 60, payout: 5 },
rsltName: 'Even Result', Domino14:{ maxBet: 60, payout: 5 },
winConditionDescription: '주사위 총합 짝수', Domino15:{ maxBet: 60, payout: 5 },
maxAmount: 300000, Domino16:{ maxBet: 60, payout: 5 },
payout: 2, Domino23:{ maxBet: 60, payout: 5 },
}, Domino24:{ maxBet: 60, payout: 5 },
ODD: { Domino25:{ maxBet: 60, payout: 5 },
category: 'B', Domino26:{ maxBet: 60, payout: 5 },
typeDescriptionEng: 'Even / Odd Bet', Domino34:{ maxBet: 60, payout: 5 },
typeDescriptionKr: '홀/짝 배팅', Domino35:{ maxBet: 60, payout: 5 },
tripeLose: true, Domino36:{ maxBet: 60, payout: 5 },
key: 'odd', Domino45:{ maxBet: 60, payout: 5 },
keyName: 'Odd Bet', Domino46:{ maxBet: 60, payout: 5 },
rslt: 'odd_rslt', Domino56:{ maxBet: 60, payout: 5 },
rsltName: 'Odd Result', Single1_N1:{ maxBet: 100 },
winConditionDescription: '주사위 총합 홀수', Single2_N1:{ maxBet: 100 },
maxAmount: 300000, Single3_N1:{ maxBet: 100 },
payout: 2, Single4_N1:{ maxBet: 100 },
} Single5_N1:{ maxBet: 100 },
Single6_N1:{ maxBet: 100 },
} as const; } as const;
export type BetTypeKey = keyof typeof BetType; export type BetTypeKey = keyof typeof BetType;

View File

@ -538,61 +538,6 @@
{/if} {/if}
</div> </div>
<!-- 전체 사용자 배팅 내역 -->
{#if isConnected && allBettings.length > 0}
<div class="mb-8 p-6 bg-gradient-to-br from-slate-50 to-gray-50 rounded-xl border-2 border-slate-200">
<h2 class="text-xl font-bold text-center mb-4 text-gray-800">
📊 전체 배팅 현황
</h2>
<div class="space-y-3 max-h-60 overflow-y-auto">
{#each allBettings as betting}
<div class="p-3 bg-white rounded-lg border border-gray-200">
<div class="font-semibold text-gray-800 mb-2">{betting.nickname}</div>
<div class="grid grid-cols-4 gap-2 text-sm">
{#if betting.oddBet > 0}
<div class="bg-blue-50 p-2 rounded text-center">
<div class="text-xs text-gray-600"></div>
<div class="font-semibold text-blue-600">{betting.oddBet.toLocaleString()}</div>
</div>
{/if}
{#if betting.evenBet > 0}
<div class="bg-pink-50 p-2 rounded text-center">
<div class="text-xs text-gray-600"></div>
<div class="font-semibold text-pink-600">{betting.evenBet.toLocaleString()}</div>
</div>
{/if}
{#if betting.bigBet > 0}
<div class="bg-orange-50 p-2 rounded text-center">
<div class="text-xs text-gray-600"></div>
<div class="font-semibold text-orange-600">{betting.bigBet.toLocaleString()}</div>
</div>
{/if}
{#if betting.smallBet > 0}
<div class="bg-purple-50 p-2 rounded text-center">
<div class="text-xs text-gray-600"></div>
<div class="font-semibold text-purple-600">{betting.smallBet.toLocaleString()}</div>
</div>
{/if}
</div>
</div>
{/each}
</div>
</div>
{/if}
<!-- 설명 -->
<div class="mt-8 p-4 bg-gray-50 rounded-lg border border-gray-200">
<h2 class="font-semibold text-gray-800 mb-2">게임 규칙</h2>
<ul class="text-sm text-gray-600 space-y-1">
<li>✅ Cloudflare Durable Objects로 상태 관리</li>
<li>✅ WebSocket으로 실시간 양방향 통신</li>
<li>🎲 <strong>베팅 기간 (45초)</strong>: 홀수 또는 짝수 선택 가능</li>
<li>🚫 <strong>베팅 마감 (15초)</strong>: 주사위 결과 확인 및 대기</li>
<li>📊 Progress bar로 남은 시간 시각화</li>
<li>🔄 게임은 자동으로 반복됩니다</li>
<li>👥 모든 접속자에게 실시간 동기화</li>
</ul>
</div>
</div> </div>
</div> </div>