치지직 앱으로 연동하고, 연동 확인된 ID만 접속할 수 있도록 수정, 개발용으로는 채널ID를 수동으로 접속할 수 있도록 변경.
최초 추천 고정 배치 추가.
This commit is contained in:
@@ -5,15 +5,17 @@ export const MIN_PLANE_SIZE = 4;
|
||||
export const MAX_PLANE_SIZE = 16;
|
||||
|
||||
export const CELL_TYPE_PRESETS = [
|
||||
'한잔',
|
||||
'안주',
|
||||
'모두한잔',
|
||||
'두잔',
|
||||
'벌칙1',
|
||||
'벌칙2',
|
||||
'한잔마셔',
|
||||
'~~체 3분',
|
||||
'안주 한입',
|
||||
'노래 1절',
|
||||
'다같이한잔',
|
||||
'영어금지 3분',
|
||||
'두잔마셔',
|
||||
'애교/매도 100자',
|
||||
'무인도',
|
||||
'역방향',
|
||||
'비행기',
|
||||
'세계여행',
|
||||
] as const;
|
||||
|
||||
export type CellEventOption = {
|
||||
@@ -25,7 +27,7 @@ export const CELL_EVENT_OPTIONS: CellEventOption[] = [
|
||||
{ id: null, label: '없음' },
|
||||
{ id: 'island', label: '무인도' },
|
||||
{ id: 'reverse', label: '역방향' },
|
||||
{ id: 'airplane', label: '비행기 → 시작' },
|
||||
{ id: 'airplane', label: '세계여행 (원하는 칸)' },
|
||||
];
|
||||
|
||||
/** 저장용 칸 설정 (좌표는 지오메트리에서 합친다) */
|
||||
@@ -46,7 +48,46 @@ export type BoardConfig = {
|
||||
};
|
||||
|
||||
const BOARD_STORAGE_KEY = 'drinkmarble.board';
|
||||
const BOARD_VERSION = 2;
|
||||
/** v5: 추천 배치 아이콘(이모지) 제거 */
|
||||
const BOARD_VERSION = 5;
|
||||
|
||||
/** 기본 추천 배치 (시계방향, 시작 포함 28칸 = 9×7) */
|
||||
const DEFAULT_BOARD_LAYOUT: ReadonlyArray<{
|
||||
type: string;
|
||||
eventId?: string | null;
|
||||
}> = [
|
||||
{ type: '시작', eventId: null },
|
||||
{ type: '한잔마셔' },
|
||||
{ type: '~~체 3분' },
|
||||
{ type: '안주 한입' },
|
||||
{ type: '노래 1절' },
|
||||
{ type: '다같이한잔' },
|
||||
{ type: '영어금지 3분' },
|
||||
{ type: '애교/매도 100자' },
|
||||
{ type: '무인도', eventId: 'island' },
|
||||
{ type: '안주 한입' },
|
||||
{ type: '두잔마셔' },
|
||||
{ type: '~~체 3분' },
|
||||
{ type: '한잔마셔' },
|
||||
{ type: '애교/매도 100자' },
|
||||
{ type: '역방향', eventId: 'reverse' },
|
||||
{ type: '영어금지 3분' },
|
||||
{ type: '안주 한입' },
|
||||
{ type: '다같이한잔' },
|
||||
{ type: '노래 1절' },
|
||||
{ type: '한잔마셔' },
|
||||
{ type: '~~체 3분' },
|
||||
{ type: '두잔마셔' },
|
||||
{ type: '세계여행', eventId: 'airplane' },
|
||||
{ type: '애교/매도 100자' },
|
||||
{ type: '안주 한입' },
|
||||
{ type: '영어금지 3분' },
|
||||
{ type: '다같이한잔' },
|
||||
{ type: '한잔마셔' },
|
||||
];
|
||||
|
||||
const SPECIAL_TYPE_NAMES = new Set(['무인도', '역방향', '비행기', '세계여행']);
|
||||
|
||||
|
||||
export function clampPlaneSize(n: number) {
|
||||
return Math.min(MAX_PLANE_SIZE, Math.max(MIN_PLANE_SIZE, Math.round(n)));
|
||||
@@ -57,9 +98,7 @@ export function perimeterLength(width: number, height: number) {
|
||||
}
|
||||
|
||||
function randomPresetType() {
|
||||
const pool = CELL_TYPE_PRESETS.filter(
|
||||
(t) => t !== '무인도' && t !== '역방향' && t !== '비행기',
|
||||
);
|
||||
const pool = CELL_TYPE_PRESETS.filter((t) => !SPECIAL_TYPE_NAMES.has(t));
|
||||
return pool[Math.floor(Math.random() * pool.length)];
|
||||
}
|
||||
|
||||
@@ -80,10 +119,37 @@ function defaultSpecials(width: number, height: number): Record<number, BoardCel
|
||||
return {
|
||||
[topRight]: { type: '무인도', eventId: 'island' },
|
||||
[bottomRight]: { type: '역방향', eventId: 'reverse' },
|
||||
[bottomLeft]: { type: '비행기', eventId: 'airplane' },
|
||||
[bottomLeft]: { type: '세계여행', eventId: 'airplane' },
|
||||
};
|
||||
}
|
||||
|
||||
function cellFromLayout(
|
||||
entry: { type: string; eventId?: string | null },
|
||||
index: number,
|
||||
): BoardCellConfig {
|
||||
return {
|
||||
type: index === 0 ? '시작' : entry.type,
|
||||
eventId: index === 0 ? null : (entry.eventId ?? null),
|
||||
imageSrc: null,
|
||||
contentVisible: true,
|
||||
};
|
||||
}
|
||||
|
||||
/** 추천 기본 배치 (9×7) */
|
||||
export function createDefaultBoardConfig(): BoardConfig {
|
||||
const w = DEFAULT_PLANE_SIZE.width;
|
||||
const h = DEFAULT_PLANE_SIZE.height;
|
||||
const len = perimeterLength(w, h);
|
||||
if (DEFAULT_BOARD_LAYOUT.length !== len) {
|
||||
throw new Error(
|
||||
`DEFAULT_BOARD_LAYOUT length ${DEFAULT_BOARD_LAYOUT.length} != perimeter ${len}`,
|
||||
);
|
||||
}
|
||||
const cells = DEFAULT_BOARD_LAYOUT.map((entry, index) => cellFromLayout(entry, index));
|
||||
cells[0] = { type: '시작', eventId: null, imageSrc: null, contentVisible: true };
|
||||
return { version: BOARD_VERSION, width: w, height: h, cells };
|
||||
}
|
||||
|
||||
/** 시계방향 둘레 좌표만 만든다. */
|
||||
export function buildPerimeterGeometry(
|
||||
width: number,
|
||||
@@ -116,6 +182,10 @@ export function createRandomBoardConfig(
|
||||
): BoardConfig {
|
||||
const w = clampPlaneSize(width);
|
||||
const h = clampPlaneSize(height);
|
||||
if (w === DEFAULT_PLANE_SIZE.width && h === DEFAULT_PLANE_SIZE.height) {
|
||||
return createDefaultBoardConfig();
|
||||
}
|
||||
|
||||
const geo = buildPerimeterGeometry(w, h);
|
||||
const specials = defaultSpecials(w, h);
|
||||
const cells: BoardCellConfig[] = geo.map((_, index) => {
|
||||
@@ -180,7 +250,10 @@ export function readStoredBoard(): BoardConfig | null {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(BOARD_STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
return normalizeBoardConfig(JSON.parse(raw) as BoardConfig);
|
||||
const parsed = JSON.parse(raw) as BoardConfig;
|
||||
// 구버전(랜덤 기본)은 추천 배치로 교체
|
||||
if ((parsed.version ?? 0) < BOARD_VERSION) return null;
|
||||
return normalizeBoardConfig(parsed);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -195,7 +268,7 @@ export function writeStoredBoard(config: BoardConfig) {
|
||||
export function getOrCreateBoardConfig(): BoardConfig {
|
||||
const existing = readStoredBoard();
|
||||
if (existing) return existing;
|
||||
const created = createRandomBoardConfig();
|
||||
const created = createDefaultBoardConfig();
|
||||
writeStoredBoard(created);
|
||||
return created;
|
||||
}
|
||||
@@ -209,15 +282,24 @@ export function clearBoardConfig() {
|
||||
window.localStorage.removeItem(BOARD_STORAGE_KEY);
|
||||
}
|
||||
|
||||
/** 추천 기본 배치로 되돌린다 (크기 포함 9×7 고정). */
|
||||
export function resetToDefaultBoard(): BoardConfig {
|
||||
const created = createDefaultBoardConfig();
|
||||
writeStoredBoard(created);
|
||||
return created;
|
||||
}
|
||||
|
||||
export function randomizeAndSaveBoard(
|
||||
width?: number,
|
||||
height?: number,
|
||||
current = getOrCreateBoardConfig(),
|
||||
): BoardConfig {
|
||||
const created = createRandomBoardConfig(
|
||||
width ?? current.width,
|
||||
height ?? current.height,
|
||||
);
|
||||
const w = width ?? current.width;
|
||||
const h = height ?? current.height;
|
||||
if (w === DEFAULT_PLANE_SIZE.width && h === DEFAULT_PLANE_SIZE.height) {
|
||||
return resetToDefaultBoard();
|
||||
}
|
||||
const created = createRandomBoardConfig(w, h);
|
||||
writeStoredBoard(created);
|
||||
return created;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user