MoodCanvas/lib/models/puzzle_game.dart
fengshengxiong 91b7eebbf2 接入TopON
2026-01-22 16:34:55 +08:00

169 lines
4.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:aesthetica_wallpaper/models/puzzle_game_interface.dart';
/// 拼图块数据模型
class PuzzlePiece {
final int id; // 唯一标识
final int correctPosition; // 正确位置
int currentPosition; // 当前位置
final ImageProvider image; // 图片块
PuzzlePiece({
required this.id,
required this.correctPosition,
required this.currentPosition,
required this.image,
});
bool get isCorrect => currentPosition == correctPosition;
PuzzlePiece copyWith({
int? id,
int? correctPosition,
int? currentPosition,
ImageProvider? image,
}) {
return PuzzlePiece(
id: id ?? this.id,
correctPosition: correctPosition ?? this.correctPosition,
currentPosition: currentPosition ?? this.currentPosition,
image: image ?? this.image,
);
}
}
/// 游戏模式
enum GameMode {
classic, // 经典模式(滑动)
challenge, // 挑战模式(限时)
casual, // 休闲模式(无限制)
}
/// 游戏难度
enum GameDifficulty {
easy(3, '简单', '3x3'),
medium(4, '中等', '4x4'),
hard(5, '困难', '5x5'),
expert(6, '专家', '6x6');
final int gridSize;
final String label;
final String description;
const GameDifficulty(this.gridSize, this.label, this.description);
}
/// 拼图游戏状态
class PuzzleGame implements IPuzzleGame {
List<PuzzlePiece> pieces;
int moves;
Duration elapsedTime;
GameDifficulty difficulty;
GameMode mode;
bool isComplete;
int? emptyPosition; // 空格位置(仅滑动模式)
PuzzleGame({
required this.pieces,
this.moves = 0,
this.elapsedTime = Duration.zero,
required this.difficulty,
this.mode = GameMode.classic,
this.isComplete = false,
this.emptyPosition,
});
int get gridSize => difficulty.gridSize;
int get totalPieces => gridSize * gridSize;
@override
String get difficultyLabel => difficulty.label;
/// 检查游戏是否完成
bool checkComplete() {
return pieces.every((piece) => piece.isCorrect);
}
/// 获取星级评分1-3星
@override
int getStarRating() {
if (!isComplete) return 0;
final optimalMoves = totalPieces * 2; // 理想步数
final optimalTime = Duration(minutes: difficulty.gridSize); // 理想时间
int stars = 1;
if (moves <= optimalMoves && elapsedTime <= optimalTime) {
stars = 3;
} else if (moves <= optimalMoves * 1.5 ||
elapsedTime <= optimalTime * 1.5) {
stars = 2;
}
return stars;
}
PuzzleGame copyWith({
List<PuzzlePiece>? pieces,
int? moves,
Duration? elapsedTime,
GameDifficulty? difficulty,
GameMode? mode,
bool? isComplete,
int? emptyPosition,
}) {
return PuzzleGame(
pieces: pieces ?? this.pieces,
moves: moves ?? this.moves,
elapsedTime: elapsedTime ?? this.elapsedTime,
difficulty: difficulty ?? this.difficulty,
mode: mode ?? this.mode,
isComplete: isComplete ?? this.isComplete,
emptyPosition: emptyPosition ?? this.emptyPosition,
);
}
}
/// 游戏记录
class GameRecord {
final String imageId;
final GameDifficulty difficulty;
final Duration time;
final int moves;
final int stars;
final DateTime completedAt;
GameRecord({
required this.imageId,
required this.difficulty,
required this.time,
required this.moves,
required this.stars,
required this.completedAt,
});
Map<String, dynamic> toJson() {
return {
'imageId': imageId,
'difficulty': difficulty.name,
'time': time.inSeconds,
'moves': moves,
'stars': stars,
'completedAt': completedAt.toIso8601String(),
};
}
factory GameRecord.fromJson(Map<String, dynamic> json) {
return GameRecord(
imageId: json['imageId'],
difficulty: GameDifficulty.values.firstWhere(
(d) => d.name == json['difficulty'],
),
time: Duration(seconds: json['time']),
moves: json['moves'],
stars: json['stars'],
completedAt: DateTime.parse(json['completedAt']),
);
}
}