Added more stuff for proper Object orientation, abstraction and so on
--- UI still not working gotta fix thatmain
parent
3b8eb7c0e6
commit
480dbdacc6
|
@ -1,5 +1,5 @@
|
||||||
/// Enum for the stone colors.
|
/// Enum for the stone colors.
|
||||||
enum Color {
|
enum StoneColors {
|
||||||
red,
|
red,
|
||||||
green,
|
green,
|
||||||
blue,
|
blue,
|
||||||
|
@ -7,4 +7,3 @@ enum Color {
|
||||||
pink,
|
pink,
|
||||||
special, // not a "real" color; indicates that a stone is special (Not retarded, in a nice way, like mama always used to tell me i am her special child)
|
special, // not a "real" color; indicates that a stone is special (Not retarded, in a nice way, like mama always used to tell me i am her special child)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:bubbletwist/game/stone/SpecialStone.dart';
|
||||||
|
|
||||||
|
import '../enums/StoneColor.dart';
|
||||||
|
import 'Game.dart';
|
||||||
|
import 'stone/PentaSpecialStone.dart';
|
||||||
|
import 'stone/Stone.dart';
|
||||||
|
import 'stone/StoneLocation.dart';
|
||||||
|
|
||||||
|
class Board {
|
||||||
|
static const int boardSize = 8;
|
||||||
|
final Game game;
|
||||||
|
late final List<List<Stone?>> stones =
|
||||||
|
List.filled(boardSize, List.filled(boardSize, Stone()));
|
||||||
|
|
||||||
|
Board(this.game) {
|
||||||
|
for (var row in stones) {
|
||||||
|
for (var stone in row) {
|
||||||
|
stone = Stone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The map generates with pairs of 3+ stones already in place.
|
||||||
|
// To fix that we just let the game remove all 3+ stone pairs until none are left
|
||||||
|
//while (checkBoard());
|
||||||
|
}
|
||||||
|
void updateBoard() {
|
||||||
|
game.updateBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool swapStones(StoneLocation sl1, StoneLocation sl2) {
|
||||||
|
// Check if the two stones that have been clicked are next to each other
|
||||||
|
if (!(sl1.row >= sl2.row - 1 && sl1.row <= sl2.row + 1) ||
|
||||||
|
!(sl1.column >= sl2.column - 1 && sl1.column <= sl2.column + 1)) {
|
||||||
|
return false; // If they are not next to each other just abort
|
||||||
|
}
|
||||||
|
|
||||||
|
final s1 = game.getStone(sl1);
|
||||||
|
final ss1 = s1 is PentaSpecialStone ? s1 : null;
|
||||||
|
if (ss1 != null) {
|
||||||
|
ss1.stoneColor = getStone(sl2)!.stoneColor;
|
||||||
|
performSpecialStone(ss1, sl1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final s2 = game.getStone(sl2);
|
||||||
|
final ss2 = s2 is PentaSpecialStone ? s2 : null;
|
||||||
|
if (ss2 != null) {
|
||||||
|
ss2.stoneColor = getStone(sl1)!.stoneColor;
|
||||||
|
performSpecialStone(ss2, sl2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap stones
|
||||||
|
swap(sl1, sl2);
|
||||||
|
if (checkBoard()) {
|
||||||
|
// Check if swapping was a valid move
|
||||||
|
// If Swap is valid, Stones have been removed and others have to fall down
|
||||||
|
applyGravity();
|
||||||
|
while (checkBoard()) {
|
||||||
|
// Then we have to keep checking until no more 3+ stones are created by falling stones
|
||||||
|
applyGravity();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// If Swap is invalid, the stones get swapped back
|
||||||
|
swap(sl1, sl2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkBoard() {
|
||||||
|
bool stuffDeleted = false;
|
||||||
|
|
||||||
|
// FOR HORIZONTALS
|
||||||
|
for (int row = 0; row < boardSize; ++row) {
|
||||||
|
// First go through each row
|
||||||
|
int startPosition = 0;
|
||||||
|
int counter = 1;
|
||||||
|
for (int column = 1; column < boardSize; ++column) {
|
||||||
|
// And then through each column
|
||||||
|
if (stones[row][column] == null || stones[row][column - 1] == null) {
|
||||||
|
// Ignore deleted stones
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final colorsAreSame = stones[row][column]!.stoneColor ==
|
||||||
|
stones[row][column - 1]!.stoneColor;
|
||||||
|
|
||||||
|
// If both stones have the same color increase counter
|
||||||
|
if (colorsAreSame) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
// If they are not the same color or we reach the end of the Board,
|
||||||
|
// check the counter to see if the last 3+ stones had the same color
|
||||||
|
if (!colorsAreSame || column == boardSize - 1) {
|
||||||
|
if (counter >= 3) {
|
||||||
|
// And if we had 3+ stones, remove them
|
||||||
|
if (game.isRunning()) {
|
||||||
|
game.addPoints(counter);
|
||||||
|
game.addTime(3);
|
||||||
|
}
|
||||||
|
for (int k = 0; k < counter; ++k) {
|
||||||
|
final st = StoneLocation(row: row, column: startPosition + k);
|
||||||
|
removeStone(st);
|
||||||
|
stuffDeleted = true;
|
||||||
|
}
|
||||||
|
if (counter == 3 && game.isRunning()) {
|
||||||
|
//stones[row][startPosition] = TripleSpecialStone(this);
|
||||||
|
}
|
||||||
|
if (counter == 4 && game.isRunning()) {
|
||||||
|
//stones[row][startPosition] = QuadSpecialStone(this, false);
|
||||||
|
}
|
||||||
|
if (counter == 5 && game.isRunning()) {
|
||||||
|
stones[row][startPosition] = PentaSpecialStone(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reset counter and start position after each color change
|
||||||
|
counter = 1;
|
||||||
|
startPosition = column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FOR VERTICALS
|
||||||
|
for (int column = 0; column < boardSize; ++column) {
|
||||||
|
// First go through each column
|
||||||
|
int startPosition = 0;
|
||||||
|
int counter = 1;
|
||||||
|
for (int row = 1; row < boardSize; ++row) {
|
||||||
|
// And then through each row
|
||||||
|
if (stones[row][column] == null || stones[row - 1][column] == null) {
|
||||||
|
// Ignore deleted stones
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both stones have the same color increase counter
|
||||||
|
final colorsAreSame = stones[row][column]!.stoneColor ==
|
||||||
|
stones[row - 1][column]!.stoneColor;
|
||||||
|
if (colorsAreSame) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
// If they are not the same color or we reach the end of the Board,
|
||||||
|
// check the counter to see if the last 3+ stones had the same color
|
||||||
|
if (!colorsAreSame || row == boardSize - 1) {
|
||||||
|
if (counter >= 3) {
|
||||||
|
//And if we had 3+ stones, remove them
|
||||||
|
if (game.isRunning()) {
|
||||||
|
game.addPoints(counter);
|
||||||
|
game.addTime(3);
|
||||||
|
}
|
||||||
|
for (int k = 0; k < counter; ++k) {
|
||||||
|
final st = StoneLocation(row: startPosition + k, column: column);
|
||||||
|
removeStone(st);
|
||||||
|
stuffDeleted = true;
|
||||||
|
}
|
||||||
|
if (counter == 3 && game.isRunning()) {
|
||||||
|
//stones[startPosition][column] = TripleSpecialStone(this);
|
||||||
|
}
|
||||||
|
if (counter == 4 && game.isRunning()) {
|
||||||
|
//stones[startPosition][column] = QuadSpecialStone(this, true);
|
||||||
|
}
|
||||||
|
if (counter == 5 && game.isRunning()) {
|
||||||
|
stones[startPosition][column] = PentaSpecialStone(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Reset counter and start position after each color change
|
||||||
|
counter = 1;
|
||||||
|
startPosition = row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stuffDeleted) {
|
||||||
|
// If stuff has been deleted we have to update the Gui
|
||||||
|
game.updateBoard();
|
||||||
|
}
|
||||||
|
return stuffDeleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeStone(StoneLocation sl) {
|
||||||
|
if (sl.row < 0 ||
|
||||||
|
sl.row >= boardSize ||
|
||||||
|
sl.column < 0 ||
|
||||||
|
sl.column >= boardSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!game.isRunning()) {
|
||||||
|
// If game is not running, just give the stones a new color
|
||||||
|
stones[sl.row][sl.column]!.stoneColor =
|
||||||
|
StoneColors.values[Random().nextInt(StoneColors.values.length)];
|
||||||
|
} else {
|
||||||
|
// Otherwise mark stones as deleted
|
||||||
|
stones[sl.row][sl.column] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyGravity() {
|
||||||
|
bool stonesHaveFallenDown;
|
||||||
|
// Move Stones down 1 row if the stone below them is marked as deleted
|
||||||
|
do {
|
||||||
|
stonesHaveFallenDown = false;
|
||||||
|
for (int column = 0; column < boardSize; ++column) {
|
||||||
|
for (int row = boardSize - 1; row > 0; --row) {
|
||||||
|
if (stones[row][column] == null) {
|
||||||
|
if (stones[row - 1][column] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stones[row][column] = stones[row - 1][column];
|
||||||
|
stones[row - 1][column] = null;
|
||||||
|
stonesHaveFallenDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (
|
||||||
|
stonesHaveFallenDown); // Continue doing so until all deleted Stones are at the top most position
|
||||||
|
|
||||||
|
// Then generate new stones that rain from the sky)
|
||||||
|
for (var row in stones) {
|
||||||
|
for (var stone in row) {
|
||||||
|
if (stone == null) {
|
||||||
|
stone = Stone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
game.updateBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void performSpecialStone(SpecialStone ss, StoneLocation sl) {
|
||||||
|
//Delete Stones
|
||||||
|
ss.performSpecialStoneAction();
|
||||||
|
removeStone(sl);
|
||||||
|
//show Deleted Stones
|
||||||
|
updateBoard();
|
||||||
|
//Make Stones fall down into new "holes"
|
||||||
|
applyGravity();
|
||||||
|
updateBoard(); //Show the Gravity Effect
|
||||||
|
while (checkBoard()) {
|
||||||
|
// Then we have to keep checking until no more 3+ stones are created by falling stones
|
||||||
|
applyGravity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(StoneLocation sl1, StoneLocation sl2) {
|
||||||
|
final tmp = stones[sl1.row][sl1.column];
|
||||||
|
stones[sl1.row][sl1.column] = stones[sl2.row][sl2.column];
|
||||||
|
stones[sl2.row][sl2.column] = tmp;
|
||||||
|
game.updateBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stone? getStone(StoneLocation sl) {
|
||||||
|
return stones[sl.row][sl.column];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import '../enums/StoneColor.dart';
|
||||||
|
import 'Board.dart';
|
||||||
|
import 'IGameConsumer.dart';
|
||||||
|
import 'stone/Stone.dart';
|
||||||
|
import 'stone/StoneLocation.dart';
|
||||||
|
|
||||||
|
class Game {
|
||||||
|
IGameConsumer gameConsumer;
|
||||||
|
late int timeInSeconds;
|
||||||
|
int startTime = 60; // hardcoded
|
||||||
|
int points = 0;
|
||||||
|
bool running = false;
|
||||||
|
late Board board;
|
||||||
|
late Timer counterTimer;
|
||||||
|
StoneLocation stoneToSwap = StoneLocation(row: -1, column: -1);
|
||||||
|
|
||||||
|
Game(this.gameConsumer) {
|
||||||
|
timeInSeconds = startTime;
|
||||||
|
board = Board(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPoints() => points;
|
||||||
|
|
||||||
|
int getTimeInSeconds() => timeInSeconds;
|
||||||
|
|
||||||
|
void addPoints(int pointsToAdd) {
|
||||||
|
if (timeInSeconds != 0 && running) {
|
||||||
|
points += pointsToAdd;
|
||||||
|
gameConsumer.updatePoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTime(int timeToAdd) {
|
||||||
|
if (timeInSeconds != 0 && running) {
|
||||||
|
timeInSeconds += timeToAdd;
|
||||||
|
gameConsumer.updateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void endGame() {
|
||||||
|
running = false;
|
||||||
|
counterTimer?.cancel();
|
||||||
|
gameConsumer.gameStopped();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> countDown() async {
|
||||||
|
do {
|
||||||
|
timeInSeconds--;
|
||||||
|
gameConsumer.updateTime();
|
||||||
|
if (timeInSeconds > 0) {
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
}
|
||||||
|
} while (timeInSeconds > 0);
|
||||||
|
if (running) {
|
||||||
|
endGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StoneColors? getStoneColor(StoneLocation location) {
|
||||||
|
return board.getStone(location)?.getStoneColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Stone? getStone(StoneLocation location) {
|
||||||
|
return board.getStone(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
if (!running) {
|
||||||
|
timeInSeconds = startTime;
|
||||||
|
points = 0;
|
||||||
|
board = Board(this);
|
||||||
|
gameConsumer.updateStones();
|
||||||
|
counterTimer = Timer.periodic(Duration(seconds: 1), (_) => countDown());
|
||||||
|
gameConsumer.updatePoints();
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() {
|
||||||
|
if (running) {
|
||||||
|
running = false;
|
||||||
|
timeInSeconds = 0;
|
||||||
|
counterTimer.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool swapStones(StoneLocation sl1, StoneLocation sl2) {
|
||||||
|
return board.swapStones(sl1, sl2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBoard() {
|
||||||
|
if (running) {
|
||||||
|
gameConsumer.updateStones();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRunning() => running;
|
||||||
|
|
||||||
|
bool swap(StoneLocation sl) {
|
||||||
|
if (stoneToSwap.row == -1) {
|
||||||
|
stoneToSwap = sl;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
swapStones(stoneToSwap, sl);
|
||||||
|
stoneToSwap = StoneLocation(row: -1, column: -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool performSpecialStone(StoneLocation sl) {
|
||||||
|
Stone? s = getStone(sl);
|
||||||
|
/*if (s is TriggerableSpecialStone) {
|
||||||
|
s.setActivationLocation(sl);
|
||||||
|
board.performSpecialStone(s, sl);
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import '../Board.dart';
|
||||||
|
import 'SpecialStone.dart';
|
||||||
|
import 'StoneLocation.dart';
|
||||||
|
|
||||||
|
class PentaSpecialStone extends SpecialStone {
|
||||||
|
PentaSpecialStone(Board board) : super(board);
|
||||||
|
|
||||||
|
int getSpecialStoneNumber() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void performSpecialStoneAction() {
|
||||||
|
StoneLocation sl = StoneLocation(row: -1, column: -1);
|
||||||
|
for (int i = 0; i < Board.boardSize; ++i) {
|
||||||
|
for (int j = 0; j < Board.boardSize; ++j) {
|
||||||
|
sl.row = i;
|
||||||
|
sl.column = j;
|
||||||
|
if (this == board.getStone(sl)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (board.getStone(sl)?.getStoneColor() == this.getStoneColor()) {
|
||||||
|
board.removeStone(sl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
import '../Board.dart';
|
||||||
|
import 'Stone.dart';
|
||||||
|
|
||||||
|
abstract class SpecialStone extends Stone {
|
||||||
|
final Board board;
|
||||||
|
|
||||||
|
SpecialStone(this.board);
|
||||||
|
|
||||||
|
/// Returns the associated number of the special stone
|
||||||
|
int getSpecialStoneNumber();
|
||||||
|
|
||||||
|
/// Performs the action of the special stone
|
||||||
|
void performSpecialStoneAction();
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import '../../enums/Color.dart';
|
|
||||||
|
import '../../enums/StoneColor.dart';
|
||||||
|
|
||||||
/// Class to represent a stone on the board.
|
/// Class to represent a stone on the board.
|
||||||
class Stone {
|
class Stone {
|
||||||
/// Color of the stone
|
/// Color of the stone
|
||||||
late Color color;
|
late StoneColors stoneColor;
|
||||||
|
|
||||||
Stone() {
|
Stone() {
|
||||||
setRandomColor();
|
setRandomColor();
|
||||||
|
@ -12,16 +13,17 @@ class Stone {
|
||||||
|
|
||||||
/// Getter for the color.
|
/// Getter for the color.
|
||||||
/// \return color
|
/// \return color
|
||||||
Color getColor() => color;
|
StoneColors getStoneColor() => stoneColor;
|
||||||
|
|
||||||
/// Setter for the color
|
/// Setter for the color
|
||||||
/// \param color
|
/// \param color
|
||||||
void setColor(Color color) {
|
void setColor(StoneColors stoneColor) {
|
||||||
this.color = color;
|
this.stoneColor = stoneColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// method that sets a random color
|
/// method that sets a random color
|
||||||
void setRandomColor() {
|
void setRandomColor() {
|
||||||
color = Color.values[Random().nextInt(Color.values.length)];
|
stoneColor =
|
||||||
|
StoneColors.values[Random().nextInt(StoneColors.values.length)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
/// Simple structure that stores two ints to locate a stone on the board.
|
||||||
|
class StoneLocation {
|
||||||
|
int row;
|
||||||
|
int column;
|
||||||
|
|
||||||
|
StoneLocation({
|
||||||
|
required this.row,
|
||||||
|
required this.column,
|
||||||
|
});
|
||||||
|
}
|
208
lib/main.dart
208
lib/main.dart
|
@ -1,7 +1,11 @@
|
||||||
import 'dart:math';
|
import 'package:bubbletwist/enums/StoneColor.dart';
|
||||||
|
import 'package:bubbletwist/game/Game.dart';
|
||||||
|
import 'package:bubbletwist/game/IGameConsumer.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'game/stone/Stone.dart';
|
||||||
|
import 'game/stone/StoneLocation.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
@ -9,7 +13,7 @@ void main() {
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
final int gridSize = 12;
|
final int gridSize = 8;
|
||||||
|
|
||||||
// This widget is the root of your application.
|
// This widget is the root of your application.
|
||||||
@override
|
@override
|
||||||
|
@ -20,7 +24,7 @@ class MyApp extends StatelessWidget {
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: const MyHomePage(title: 'Flutter Demo Home Page', gridSize: 12),
|
home: const MyHomePage(title: 'Flutter Demo Home Page', gridSize: 8),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,44 +48,25 @@ class MyHomePage extends StatefulWidget {
|
||||||
State<MyHomePage> createState() => _MyHomePageState();
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> implements IGameConsumer {
|
||||||
late List<List<int>> _grid;
|
late List<List<Stone?>> _grid;
|
||||||
int _selectedRow = -1;
|
late Game game;
|
||||||
int _selectedCol = -1;
|
final int _score = 0;
|
||||||
int _score = 0;
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_initializeGrid();
|
game = Game(this);
|
||||||
}
|
|
||||||
|
|
||||||
void _initializeGrid() {
|
|
||||||
_grid = List.generate(widget.gridSize,
|
_grid = List.generate(widget.gridSize,
|
||||||
(_) => List.generate(widget.gridSize, (_) => Random().nextInt(5)));
|
(index) => List.generate(widget.gridSize, (index) => Stone()));
|
||||||
_removeInitialMatches();
|
game.start();
|
||||||
}
|
|
||||||
|
|
||||||
void _removeInitialMatches() {
|
|
||||||
bool hasMatches;
|
|
||||||
do {
|
|
||||||
hasMatches = _removeMatches();
|
|
||||||
_applyGravity();
|
|
||||||
} while (hasMatches);
|
|
||||||
_score = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Column(
|
title: Text(widget.title),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
const Text('Candy Crush'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -90,12 +75,11 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Score: $_score',
|
'Score: $_score',
|
||||||
style: TextStyle(fontSize: 24),
|
style: const TextStyle(fontSize: 24),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
shrinkWrap: true,
|
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: widget.gridSize,
|
crossAxisCount: widget.gridSize,
|
||||||
),
|
),
|
||||||
|
@ -103,13 +87,18 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
int row = index ~/ widget.gridSize;
|
int row = index ~/ widget.gridSize;
|
||||||
int col = index % widget.gridSize;
|
int col = index % widget.gridSize;
|
||||||
|
StoneLocation location = StoneLocation(row: row, column: col);
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => _onTileTap(row, col),
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
//game.handleTap(row, col);
|
||||||
|
});
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.all(2),
|
margin: const EdgeInsets.all(2),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _getColor(_grid[row][col]),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
color: _getColorForStone(game.getStone(location)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -122,143 +111,50 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color _getColorForStone(Stone? stone) {
|
||||||
Color _getColor(int value) {
|
// Beispielhafte Farben basierend auf dem Stein.
|
||||||
switch (value) {
|
switch (stone?.getStoneColor()) {
|
||||||
case 0:
|
case StoneColors.red:
|
||||||
return Colors.red;
|
return Colors.red;
|
||||||
case 1:
|
case StoneColors.green:
|
||||||
return Colors.blue;
|
|
||||||
case 2:
|
|
||||||
return Colors.green;
|
return Colors.green;
|
||||||
case 3:
|
case StoneColors.blue:
|
||||||
|
return Colors.blue;
|
||||||
|
case StoneColors.yellow:
|
||||||
return Colors.yellow;
|
return Colors.yellow;
|
||||||
case 4:
|
|
||||||
return Colors.orange;
|
|
||||||
default:
|
default:
|
||||||
return Colors.white;
|
return Colors.grey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onTileTap(int row, int col) {
|
@override
|
||||||
|
void gameStopped() {
|
||||||
|
// TODO: implement gameStopped
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updatePoints() {
|
||||||
|
int _score = game.getPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateStones() {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (_selectedRow == -1 && _selectedCol == -1) {
|
// _grid aktualisieren
|
||||||
_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<List<int>> _findMatches(int row, int col) {
|
|
||||||
int color = _grid[row][col];
|
|
||||||
List<List<int>> matches = [];
|
|
||||||
|
|
||||||
// Check horizontally
|
|
||||||
List<int> 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<int> 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<List<int>> allMatches = [];
|
|
||||||
int scoreIncrement = 0;
|
|
||||||
|
|
||||||
for (int row = 0; row < widget.gridSize; row++) {
|
for (int row = 0; row < widget.gridSize; row++) {
|
||||||
for (int col = 0; col < widget.gridSize; col++) {
|
for (int col = 0; col < widget.gridSize; col++) {
|
||||||
List<List<int>> matches = _findMatches(row, col);
|
_grid[row][col] = game.getStone(StoneLocation(row: row, column: 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
void _applyGravity() {
|
void updateTime() {
|
||||||
for (int col = 0; col < widget.gridSize; col++) {
|
// TODO: implement updateTime
|
||||||
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--) {
|
Game getGame() {
|
||||||
_grid[row][col] = Random().nextInt(5);
|
return game;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue