...
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// packages/feature_game_spider/lib/models/spider_card.dart
|
||||
|
||||
/// 카드의 4가지 무늬
|
||||
enum SpiderSuit {
|
||||
spade, // ♠️
|
||||
heart, // ♥️
|
||||
club, // ♣️
|
||||
diamond // ♦️
|
||||
}
|
||||
|
||||
/// 스파이더 카드 1장의 데이터 모델
|
||||
class SpiderCard {
|
||||
/// 카드의 고유 ID (Draggable 위젯의 Key로 사용)
|
||||
final int id;
|
||||
|
||||
/// 무늬 (spade, heart 등)
|
||||
final SpiderSuit suit;
|
||||
|
||||
/// 숫자 (1 = A, 11 = J, 12 = Q, 13 = K)
|
||||
final int rank;
|
||||
|
||||
/// 현재 앞면이 보이는지 여부
|
||||
bool isFaceUp;
|
||||
|
||||
/// [UI용] 카드가 현재 드래그 중인지 여부
|
||||
bool isBeingDragged;
|
||||
|
||||
SpiderCard({
|
||||
required this.id,
|
||||
required this.suit,
|
||||
required this.rank,
|
||||
this.isFaceUp = false,
|
||||
this.isBeingDragged = false,
|
||||
});
|
||||
|
||||
/// 카드가 빨간색(하트, 다이아)인지 확인
|
||||
bool get isRed => suit == SpiderSuit.heart || suit == SpiderSuit.diamond;
|
||||
|
||||
/// 랭크를 텍스트(A, K, Q, J, 10...)로 변환
|
||||
String get rankText {
|
||||
switch (rank) {
|
||||
case 1: return 'A';
|
||||
case 11: return 'J';
|
||||
case 12: return 'Q';
|
||||
case 13: return 'K';
|
||||
default: return rank.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// 무늬를 심볼(♠️, ♥️...)로 변환
|
||||
String get suitSymbol {
|
||||
switch (suit) {
|
||||
case SpiderSuit.spade: return '♠️';
|
||||
case SpiderSuit.heart: return '♥️';
|
||||
case SpiderSuit.club: return '♣️';
|
||||
case SpiderSuit.diamond: return '♦️';
|
||||
}
|
||||
}
|
||||
|
||||
// 객체 비교를 위한 == 및 hashCode 오버라이드
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is SpiderCard &&
|
||||
runtimeType == other.runtimeType &&
|
||||
id == other.id; // 고유 ID로만 비교
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
|
||||
/// 디버깅용
|
||||
@override
|
||||
String toString() {
|
||||
return '$rankText-$suitSymbol ($id)';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// packages/feature_game_spider/lib/models/spider_difficulty.dart
|
||||
|
||||
import 'package:service_api/service_api.dart'; // 👈 공통 GameDifficulty 모델
|
||||
|
||||
/// 스파이더 게임의 난이도 정의
|
||||
class SpiderDifficulty extends GameDifficulty {
|
||||
/// 레벨 순서 (1-9)
|
||||
final int levelIndex;
|
||||
|
||||
/// 무늬 수 (1, 2, 4)
|
||||
final int numSuits;
|
||||
|
||||
/// 카드 분배 문자열 (예: "4,3")
|
||||
final String numCardsDistribution;
|
||||
|
||||
const SpiderDifficulty({
|
||||
required this.levelIndex,
|
||||
required super.name,
|
||||
required super.contextId,
|
||||
required this.numSuits,
|
||||
required this.numCardsDistribution,
|
||||
});
|
||||
}
|
||||
|
||||
/// 앱 전역에서 사용할 스파이더 난이도 목록 (총 9개)
|
||||
/// (스도쿠의 AppLevels와 동일한 구조)
|
||||
class SpiderDifficulties {
|
||||
static final List<SpiderDifficulty> allDifficulties = [
|
||||
// --- 1 Suit (Easy) ---
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 1,
|
||||
name: '입문 (1 Suit)',
|
||||
contextId: 'SPIDER_L1_1SUIT_4-3',
|
||||
numSuits: 1,
|
||||
numCardsDistribution: '4,3',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 2,
|
||||
name: '초급 (1 Suit)',
|
||||
contextId: 'SPIDER_L2_1SUIT_5-4',
|
||||
numSuits: 1,
|
||||
numCardsDistribution: '5,4',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 3,
|
||||
name: '중급 (1 Suit)',
|
||||
contextId: 'SPIDER_L3_1SUIT_6-5',
|
||||
numSuits: 1,
|
||||
numCardsDistribution: '6,5',
|
||||
),
|
||||
|
||||
// --- 2 Suits (Medium) ---
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 4,
|
||||
name: '상급 (2 Suits)',
|
||||
contextId: 'SPIDER_L4_2SUITS_5-4',
|
||||
numSuits: 2,
|
||||
numCardsDistribution: '5,4',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 5,
|
||||
name: '전문가 (2 Suits)',
|
||||
contextId: 'SPIDER_L5_2SUITS_6-5',
|
||||
numSuits: 2,
|
||||
numCardsDistribution: '6,5',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 6,
|
||||
name: '마스터 (2 Suits)',
|
||||
contextId: 'SPIDER_L6_2SUITS_7-6',
|
||||
numSuits: 2,
|
||||
numCardsDistribution: '7,6',
|
||||
),
|
||||
|
||||
// --- 4 Suits (Hard) ---
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 7,
|
||||
name: '최상급 (4 Suits)',
|
||||
contextId: 'SPIDER_L7_4SUITS_6-5',
|
||||
numSuits: 4,
|
||||
numCardsDistribution: '6,5',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 8,
|
||||
name: '지옥 (4 Suits)',
|
||||
contextId: 'SPIDER_L8_4SUITS_7-6',
|
||||
numSuits: 4,
|
||||
numCardsDistribution: '7,6',
|
||||
),
|
||||
const SpiderDifficulty(
|
||||
levelIndex: 9,
|
||||
name: '챔피언 (4 Suits)',
|
||||
contextId: 'SPIDER_L9_4SUITS_8-7',
|
||||
numSuits: 4,
|
||||
numCardsDistribution: '8,7',
|
||||
),
|
||||
];
|
||||
|
||||
/// 레벨 인덱스(1-9)로 레벨 정보 찾기
|
||||
static SpiderDifficulty getLevel(int levelIndex) {
|
||||
if (levelIndex < 1) levelIndex = 1;
|
||||
if (levelIndex > allDifficulties.length) levelIndex = allDifficulties.length;
|
||||
return allDifficulties.firstWhere((level) => level.levelIndex == levelIndex,
|
||||
orElse: () => allDifficulties[0]
|
||||
);
|
||||
}
|
||||
|
||||
/// 랭킹 화면용 맵 (ContextId -> 이름)
|
||||
static Map<String, String> get contextIdToNameMap {
|
||||
return { for (var level in allDifficulties) level.contextId : level.name };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// packages/feature_game_spider/lib/models/spider_game_state.dart
|
||||
import 'spider_card.dart';
|
||||
|
||||
/// 게임 보드 전체의 상태를 저장하는 클래스
|
||||
class SpiderGameState {
|
||||
final List<List<SpiderCard>> tableau;
|
||||
final List<SpiderCard> stock;
|
||||
final List<List<SpiderCard>> foundation;
|
||||
final int moves;
|
||||
// ❌ undoCount가 여기서 제거됨
|
||||
|
||||
SpiderGameState({
|
||||
required this.tableau,
|
||||
required this.stock,
|
||||
required this.foundation,
|
||||
required this.moves,
|
||||
});
|
||||
|
||||
/// `spider.html`의 `undoHistory`에 해당하는
|
||||
/// 되돌리기용 복사본을 생성하는 팩토리 생성자
|
||||
factory SpiderGameState.fromHistory(SpiderGameHistory history) {
|
||||
return SpiderGameState(
|
||||
tableau: history.tableau.map((pile) => List.of(pile)).toList(),
|
||||
stock: List.of(history.stock),
|
||||
foundation: history.foundation.map((pile) => List.of(pile)).toList(),
|
||||
moves: history.moves,
|
||||
// ❌ undoCount가 여기서 제거됨
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 되돌리기(Undo)를 위해 저장되는 게임 상태의 스냅샷
|
||||
class SpiderGameHistory {
|
||||
final List<List<SpiderCard>> tableau;
|
||||
final List<SpiderCard> stock;
|
||||
final List<List<SpiderCard>> foundation;
|
||||
final int moves;
|
||||
// ❌ undoCount가 여기서 제거됨
|
||||
|
||||
SpiderGameHistory({
|
||||
required this.tableau,
|
||||
required this.stock,
|
||||
required this.foundation,
|
||||
required this.moves,
|
||||
});
|
||||
|
||||
/// 현재 게임 상태(GameState)로부터 스냅샷 생성
|
||||
factory SpiderGameHistory.fromState(SpiderGameState state) {
|
||||
return SpiderGameHistory(
|
||||
tableau: state.tableau.map((pile) => List.of(pile)).toList(),
|
||||
stock: List.of(state.stock),
|
||||
foundation: state.foundation.map((pile) => List.of(pile)).toList(),
|
||||
moves: state.moves,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user