import 'dart:math'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); final int gridSize = 12; // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Bubble-Twist', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(title: 'Flutter Demo Home Page', gridSize: 12), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title, required this.gridSize}); // This widget is the home page of your application. It is stateful, meaning // that it has a State object (defined below) that contains fields that affect // how it looks. // This class is the configuration for the state. It holds the values (in this // case the title) provided by the parent (in this case the App widget) and // used by the build method of the State. Fields in a Widget subclass are // always marked "final". final String title; final int gridSize; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { late List> _grid; int _selectedRow = -1; int _selectedCol = -1; int _score = 0; @override void initState() { super.initState(); _initializeGrid(); } void _initializeGrid() { _grid = List.generate(widget.gridSize, (_) => List.generate(widget.gridSize, (_) => Random().nextInt(5))); _removeInitialMatches(); } void _removeInitialMatches() { bool hasMatches; do { hasMatches = _removeMatches(); _applyGravity(); } while (hasMatches); _score = 0; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Candy Crush'), ], ), ), body: Center( child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Text( 'Score: $_score', style: TextStyle(fontSize: 24), ), ), Expanded( child: GridView.builder( shrinkWrap: true, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: widget.gridSize, ), itemCount: widget.gridSize * widget.gridSize, itemBuilder: (BuildContext context, int index) { int row = index ~/ widget.gridSize; int col = index % widget.gridSize; return GestureDetector( onTap: () => _onTileTap(row, col), child: Container( margin: const EdgeInsets.all(2), decoration: BoxDecoration( color: _getColor(_grid[row][col]), borderRadius: BorderRadius.circular(8), ), ), ); }, ), ), ], ), ), ); } Color _getColor(int value) { switch (value) { case 0: return Colors.red; case 1: return Colors.blue; case 2: return Colors.green; case 3: return Colors.yellow; case 4: return Colors.orange; default: return Colors.white; } } void _onTileTap(int row, int col) { setState(() { if (_selectedRow == -1 && _selectedCol == -1) { _selectedRow = row; _selectedCol = col; } else { if (_isValidMove(_selectedRow, _selectedCol, row, col)) { _swapTiles(_selectedRow, _selectedCol, row, col); while (_removeMatches()) { _applyGravity(); } } _selectedRow = -1; _selectedCol = -1; } }); } bool _isValidMove(int row1, int col1, int row2, int col2) { if ((row1 == row2 && (col1 - col2).abs() == 1) || (col1 == col2 && (row1 - row2).abs() == 1)) { int temp = _grid[row1][col1]; _grid[row1][col1] = _grid[row2][col2]; _grid[row2][col2] = temp; bool isValid = _findMatches(row1, col1).isNotEmpty || _findMatches(row2, col2).isNotEmpty; _grid[row2][col2] = _grid[row1][col1]; _grid[row1][col1] = temp; return isValid; } return false; } List> _findMatches(int row, int col) { int color = _grid[row][col]; List> matches = []; // Check horizontally List horizontalMatch = []; for (int c = col; c >= 0 && _grid[row][c] == color; c--) { horizontalMatch.add(c); } for (int c = col + 1; c < widget.gridSize && _grid[row][c] == color; c++) { horizontalMatch.add(c); } if (horizontalMatch.length >= 3) { for (int c in horizontalMatch) { matches.add([row, c]); } } // Check vertically List verticalMatch = []; for (int r = row; r >= 0 && _grid[r][col] == color; r--) { verticalMatch.add(r); } for (int r = row + 1; r < widget.gridSize && _grid[r][col] == color; r++) { verticalMatch.add(r); } if (verticalMatch.length >= 3) { for (int r in verticalMatch) { matches.add([r, col]); } } return matches; } bool _removeMatches() { List> allMatches = []; int scoreIncrement = 0; for (int row = 0; row < widget.gridSize; row++) { for (int col = 0; col < widget.gridSize; col++) { List> matches = _findMatches(row, col); if (matches.isNotEmpty) { allMatches.addAll(matches); scoreIncrement++; // Increment score based on number of matches } } } for (var match in allMatches) { _grid[match[0]][match[1]] = -1; // Mark the tile as removed } setState(() { _score += scoreIncrement; }); return allMatches.isNotEmpty; } void _applyGravity() { for (int col = 0; col < widget.gridSize; col++) { int emptyRow = widget.gridSize - 1; for (int row = widget.gridSize - 1; row >= 0; row--) { if (_grid[row][col] != -1) { _grid[emptyRow][col] = _grid[row][col]; if (emptyRow != row) { _grid[row][col] = -1; } emptyRow--; } } for (int row = emptyRow; row >= 0; row--) { _grid[row][col] = Random().nextInt(5); } } } void _swapTiles(int row1, int col1, int row2, int col2) { int temp = _grid[row1][col1]; _grid[row1][col1] = _grid[row2][col2]; _grid[row2][col2] = temp; } }