import 'dart:async'; import 'dart:math' as math; import 'dart:ui' as ui; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:aesthetica_wallpaper/models/puzzle_game.dart'; class PuzzleProvider extends ChangeNotifier { PuzzleGame? _currentGame; Timer? _timer; List _records = []; PuzzleGame? get currentGame => _currentGame; List get records => _records; /// 创建新游戏 Future createGame({ required String imagePath, required GameDifficulty difficulty, GameMode mode = GameMode.classic, }) async { // 停止之前的计时器 _timer?.cancel(); // 加载并分割图片 final pieces = await _splitImage(imagePath, difficulty.gridSize); // 打乱拼图 _shufflePieces(pieces, difficulty.gridSize); // 创建游戏 _currentGame = PuzzleGame( pieces: pieces, difficulty: difficulty, mode: mode, emptyPosition: mode == GameMode.classic ? pieces.length - 1 : null, ); // 开始计时 _startTimer(); notifyListeners(); } /// 分割图片为拼图块 Future> _splitImage(String imagePath, int gridSize) async { final pieces = []; // 加载图片 final ByteData data = await rootBundle.load(imagePath); final codec = await ui.instantiateImageCodec(data.buffer.asUint8List()); final frame = await codec.getNextFrame(); final image = frame.image; final pieceWidth = image.width ~/ gridSize; final pieceHeight = image.height ~/ gridSize; // 分割图片 for (int row = 0; row < gridSize; row++) { for (int col = 0; col < gridSize; col++) { final position = row * gridSize + col; // 创建图片块 final recorder = ui.PictureRecorder(); final canvas = Canvas(recorder); canvas.drawImageRect( image, Rect.fromLTWH( col * pieceWidth.toDouble(), row * pieceHeight.toDouble(), pieceWidth.toDouble(), pieceHeight.toDouble(), ), Rect.fromLTWH(0, 0, pieceWidth.toDouble(), pieceHeight.toDouble()), Paint(), ); final picture = recorder.endRecording(); final pieceImage = await picture.toImage(pieceWidth, pieceHeight); pieces.add( PuzzlePiece( id: position, correctPosition: position, currentPosition: position, image: MemoryImage( (await pieceImage.toByteData( format: ui.ImageByteFormat.png, ))!.buffer.asUint8List(), ), ), ); } } return pieces; } /// 打乱拼图 void _shufflePieces(List pieces, int gridSize) { final random = math.Random(); // 执行多次随机交换 for (int i = 0; i < pieces.length * 10; i++) { final index1 = random.nextInt(pieces.length); final index2 = random.nextInt(pieces.length); final temp = pieces[index1].currentPosition; pieces[index1].currentPosition = pieces[index2].currentPosition; pieces[index2].currentPosition = temp; } // 确保拼图是可解的(对于滑动模式) // TODO: 实现可解性检查 } /// 移动拼图块 void movePiece(int pieceIndex) { if (_currentGame == null || _currentGame!.isComplete) return; final piece = _currentGame!.pieces[pieceIndex]; final gridSize = _currentGame!.gridSize; if (_currentGame!.mode == GameMode.classic) { // 滑动模式:只能移动到空格 if (!_canMoveToEmpty(piece.currentPosition, gridSize)) return; final emptyPos = _currentGame!.emptyPosition!; piece.currentPosition = emptyPos; _currentGame = _currentGame!.copyWith(emptyPosition: pieceIndex); } // 增加步数 _currentGame = _currentGame!.copyWith(moves: _currentGame!.moves + 1); // 检查是否完成 if (_currentGame!.checkComplete()) { _completeGame(); } notifyListeners(); } /// 交换两个拼图块(交换模式) void swapPieces(int index1, int index2) { if (_currentGame == null || _currentGame!.isComplete) return; if (_currentGame!.mode == GameMode.classic) return; final piece1 = _currentGame!.pieces[index1]; final piece2 = _currentGame!.pieces[index2]; final temp = piece1.currentPosition; piece1.currentPosition = piece2.currentPosition; piece2.currentPosition = temp; _currentGame = _currentGame!.copyWith(moves: _currentGame!.moves + 1); if (_currentGame!.checkComplete()) { _completeGame(); } notifyListeners(); } /// 检查是否可以移动到空格 bool _canMoveToEmpty(int position, int gridSize) { final emptyPos = _currentGame!.emptyPosition!; final row = position ~/ gridSize; final col = position % gridSize; final emptyRow = emptyPos ~/ gridSize; final emptyCol = emptyPos % gridSize; // 检查是否相邻 return (row == emptyRow && (col - emptyCol).abs() == 1) || (col == emptyCol && (row - emptyRow).abs() == 1); } /// 开始计时 void _startTimer() { _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_currentGame != null && !_currentGame!.isComplete) { _currentGame = _currentGame!.copyWith( elapsedTime: _currentGame!.elapsedTime + const Duration(seconds: 1), ); notifyListeners(); } }); } /// 完成游戏 void _completeGame() { _timer?.cancel(); _currentGame = _currentGame!.copyWith(isComplete: true); // 保存记录 final record = GameRecord( imageId: 'temp', // TODO: 使用实际图片ID difficulty: _currentGame!.difficulty, time: _currentGame!.elapsedTime, moves: _currentGame!.moves, stars: _currentGame!.getStarRating(), completedAt: DateTime.now(), ); _records.add(record); // TODO: 持久化保存记录 } /// 重新开始游戏 void restartGame() { if (_currentGame == null) return; _timer?.cancel(); _shufflePieces(_currentGame!.pieces, _currentGame!.gridSize); _currentGame = _currentGame!.copyWith( moves: 0, elapsedTime: Duration.zero, isComplete: false, ); _startTimer(); notifyListeners(); } /// 使用提示 void useHint() { if (_currentGame == null || _currentGame!.isComplete) return; // TODO: 实现提示逻辑 // 找到一个不在正确位置的块,并高亮显示其正确位置 } @override void dispose() { _timer?.cancel(); super.dispose(); } }