import 'dart:math'; import 'package:flame/components.dart'; import 'package:flame/game.dart'; import 'package:provider/provider.dart'; import 'tile.dart'; import 'swap_notifier.dart'; import 'package:flame/sprite.dart'; class Board extends FlameGame { final List sprites; static const int rows = 8; static const int cols = 8; late double tileSize; List> tiles = []; int? selectedRow; int? selectedCol; Board({required this.sprites}); @override Future onLoad() async { super.onLoad(); tileSize = size.x / cols; _initializeGrid(); _removeInitialMatches(); } void _initializeGrid() { for (int row = 0; row < rows; row++) { List rowTiles = []; for (int col = 0; col < cols; col++) { int spriteIndex = _randomElement(); var tile = Tile( sprite: sprites[spriteIndex], spriteIndex: spriteIndex, size: Vector2.all(tileSize), position: Vector2(col * tileSize, row * tileSize), row: row, col: col, onTileTap: handleTileTap, ); rowTiles.add(tile); add(tile); } tiles.add(rowTiles); } } int _randomElement() { return Random().nextInt(7); } void _removeInitialMatches() { bool hasMatches; do { hasMatches = false; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { if (_hasMatch(row, col)) { int spriteIndex = _randomElement(); tiles[row][col]!.sprite = sprites[spriteIndex]; tiles[row][col]!.spriteIndex = spriteIndex; hasMatches = true; } } } } while (hasMatches); } void handleTileTap(Tile tappedTile) { int row = tappedTile.row; int col = tappedTile.col; if (selectedRow == null || selectedCol == null) { selectedRow = row; selectedCol = col; } else { if (_isAdjacent(selectedRow!, selectedCol!, row, col)) { swapTiles(tiles[selectedRow!][selectedCol!]!, tiles[row][col]!); Future.delayed(const Duration(milliseconds: 300), () { if (!_checkMatches()) { swapTiles(tiles[row][col]!, tiles[selectedRow!][selectedCol!]!); } selectedRow = null; selectedCol = null; }); } else { selectedRow = row; selectedCol = col; } } } bool _isAdjacent(int row1, int col1, int row2, int col2) { return (row1 == row2 && (col1 - col2).abs() == 1) || (col1 == col2 && (row1 - row2).abs() == 1); } void swapTiles(Tile tile1, Tile tile2) { final tempPosition = tile1.position; final tempRow = tile1.row; final tempCol = tile1.col; tile1.position = tile2.position; tile1.row = tile2.row; tile1.col = tile2.col; tile2.position = tempPosition; tile2.row = tempRow; tile2.col = tempCol; tiles[tile1.row][tile1.col] = tile1; tiles[tile2.row][tile2.col] = tile2; tile1.animateMoveTo(tile1.position, () {}); tile2.animateMoveTo(tile2.position, () {}); _checkMatches(); } bool _checkMatches() { final matches = >[]; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { if (_hasMatch(row, col)) { matches.add([row, col]); } } } if (matches.isNotEmpty) { for (final match in matches) { _removeMatchedElements(match[0], match[1]); } _applyGravity(); Future.delayed(const Duration(milliseconds: 300), () { _fillEmptySpaces(); _checkMatches(); }); return true; } return false; } bool _hasMatch(int row, int col) { final value = tiles[row][col]!.spriteIndex; int count = 1; for (int i = col + 1; i < cols && tiles[row][i]!.spriteIndex == value; i++) count++; for (int i = col - 1; i >= 0 && tiles[row][i]!.spriteIndex == value; i--) count++; if (count >= 3) return true; count = 1; for (int i = row + 1; i < rows && tiles[i][col]!.spriteIndex == value; i++) count++; for (int i = row - 1; i >= 0 && tiles[i][col]!.spriteIndex == value; i--) count++; return count >= 3; } void _removeMatchedElements(int row, int col) { final value = tiles[row][col]!.spriteIndex; int left = col; while (left > 0 && tiles[row][left - 1]!.spriteIndex == value) left--; int right = col; while (right < cols - 1 && tiles[row][right + 1]!.spriteIndex == value) right++; if (right - left + 1 >= 3) { for (int i = left; i <= right; i++) { tiles[row][i] = null; } } int top = row; while (top > 0 && tiles[top - 1][col]!.spriteIndex == value) top--; int bottom = row; while (bottom < rows - 1 && tiles[bottom + 1][col]!.spriteIndex == value) bottom++; if (bottom - top + 1 >= 3) { for (int i = top; i <= bottom; i++) { tiles[i][col] = null; } } } void _applyGravity() { for (int col = 0; col < cols; col++) { int emptyRow = rows - 1; for (int row = rows - 1; row >= 0; row--) { if (tiles[row][col] != null) { if (row != emptyRow) { tiles[emptyRow][col] = tiles[row][col]; tiles[emptyRow][col]!.row = emptyRow; tiles[row][col] = null; } emptyRow--; } } } } void _fillEmptySpaces() { for (int col = 0; col < cols; col++) { for (int row = rows - 1; row >= 0; row--) { if (tiles[row][col] == null) { int spriteIndex = _randomElement(); var tile = Tile( sprite: sprites[spriteIndex], spriteIndex: spriteIndex, size: Vector2.all(tileSize), position: Vector2(col * tileSize, row * tileSize), row: row, col: col, onTileTap: handleTileTap, ); tiles[row][col] = tile; add(tile); } } } } }