Skip to content
Snippets Groups Projects
Commit a70f7a3a authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Merge branch '2-create-minimal-playable-game' into 'master'

Resolve "Create minimal playable game"

Closes #2

See merge request !2
parents 0b3017a4 744cef3d
No related branches found
No related tags found
1 merge request!2Resolve "Create minimal playable game"
Pipeline #2713 passed
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.0.1 app.versionName=0.0.2
app.versionCode=1 app.versionCode=2
assets/skins/default_0.png

251 B

assets/skins/images_0.png

251 B

...@@ -33,6 +33,7 @@ AVAILABLE_SKINS=" ...@@ -33,6 +33,7 @@ AVAILABLE_SKINS="
# Images per skin # Images per skin
SKIN_IMAGES=" SKIN_IMAGES="
0
1 1
2 2
3 3
......
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="none"/><rect width="100" height="100" fill="#fff" stroke="#505050" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"/></svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="none"/><rect width="100" height="100" fill="#fff" stroke="#505050" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"/></svg>
import 'package:flutter/material.dart';
import '../provider/data.dart';
import '../utils/board_utils.dart';
class Cell {
int value;
Cell(
@required this.value,
);
Container widget(Data myProvider, int row, int col) {
String imageAsset = this.getImageAssetName(myProvider);
return Container(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 100),
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(child: child, scale: animation);
},
child: Image(
image: AssetImage(imageAsset),
fit: BoxFit.fill,
key: ValueKey<int>(imageAsset.hashCode),
),
),
);
}
Container widgetFillBoardWithColor(Data myProvider) {
String imageAsset = this.getImageAssetName(myProvider);
return Container(
margin: EdgeInsets.all(2),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 4,
),
),
child: GestureDetector(
child: Image(
image: AssetImage(imageAsset),
fit: BoxFit.fill
),
onTap: () {
BoardUtils.fillBoardFromFirstCell(myProvider, this.value);
if (BoardUtils.checkBoardIsSolved(myProvider)) {
myProvider.updateGameWon(true);
}
},
)
);
}
String getImageAssetName(Data myProvider) {
int cellValue = this.value;
return 'assets/skins/' + myProvider.skin + '_' + cellValue.toString() + '.png';
}
}
import 'package:flutter/material.dart';
import '../provider/data.dart';
class Board {
static Container buildGameBoard(Data myProvider) {
return Container(
margin: EdgeInsets.all(4),
padding: EdgeInsets.all(4),
child: Column(
children: [
buildGameTileset(myProvider),
],
),
);
}
static Table buildGameTileset(Data myProvider) {
int boardSize = myProvider.boardSize;
List cells = myProvider.cells;
return Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
for (var row = 0; row < boardSize; row++)
TableRow(children: [
for (var col = 0; col < boardSize; col++)
Column(children: [
cells[row][col].widget(
myProvider,
row,
col
)
]),
]),
]
);
}
}
...@@ -2,6 +2,8 @@ import 'dart:math'; ...@@ -2,6 +2,8 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../entities/cell.dart';
import '../layout/board.dart';
import '../provider/data.dart'; import '../provider/data.dart';
import '../utils/game_utils.dart'; import '../utils/game_utils.dart';
...@@ -16,21 +18,50 @@ class Game { ...@@ -16,21 +18,50 @@ class Game {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded( Expanded(
child: Text('❇️'), child: Board.buildGameBoard(myProvider),
), ),
SizedBox(height: 2), SizedBox(height: 2),
Container( Container(
height: 150,
width: double.maxFinite,
child: gameIsFinished child: gameIsFinished
? Game.buildEndGameMessage(myProvider) ? Game.buildEndGameMessage(myProvider)
: Text('❇️'), : Game.buildSelectColorBar(myProvider),
), ),
], ],
), ),
); );
} }
static Container buildSelectColorBar(Data myProvider) {
List cells = myProvider.cells;
int maxValue = myProvider.colorsCount;
return Container(
margin: EdgeInsets.all(2),
padding: EdgeInsets.all(2),
child: Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow(
children: [
for (
int value = 1;
value <= maxValue;
value++
)
Column(
children: [
Cell(value).widgetFillBoardWithColor(myProvider)
]
),
]
),
]
),
);
}
static FlatButton buildRestartGameButton(Data myProvider) { static FlatButton buildRestartGameButton(Data myProvider) {
return FlatButton( return FlatButton(
child: Container( child: Container(
......
...@@ -29,7 +29,8 @@ class MyApp extends StatelessWidget { ...@@ -29,7 +29,8 @@ class MyApp extends StatelessWidget {
routes: { routes: {
Home.id: (context) => Home(), Home.id: (context) => Home(),
}, },
)); ),
);
}), }),
); );
} }
......
...@@ -19,10 +19,17 @@ class Data extends ChangeNotifier { ...@@ -19,10 +19,17 @@ class Data extends ChangeNotifier {
// Game data // Game data
bool _gameIsRunning = false; bool _gameIsRunning = false;
bool _gameWon = false; bool _gameWon = false;
int _boardSize = 0;
int _colorsCount = 0;
List _cells = [];
String get level => _level; String get level => _level;
void updateLevel(String level) { void updateLevel(String level) {
_level = level; _level = level;
updateBoardSize(getBoardSizeFromLevel(level));
updateColorsCount(getColorsCountFromLevel(level));
notifyListeners(); notifyListeners();
} }
...@@ -39,6 +46,7 @@ class Data extends ChangeNotifier { ...@@ -39,6 +46,7 @@ class Data extends ChangeNotifier {
case 'skin': { return _skin; } case 'skin': { return _skin; }
break; break;
} }
return '';
} }
List getParameterAvailableValues(String parameterCode) { List getParameterAvailableValues(String parameterCode) {
...@@ -68,6 +76,55 @@ class Data extends ChangeNotifier { ...@@ -68,6 +76,55 @@ class Data extends ChangeNotifier {
setParameterValue('skin', prefs.getString('skin') ?? _skinDefault); setParameterValue('skin', prefs.getString('skin') ?? _skinDefault);
} }
int get boardSize => _boardSize;
void updateBoardSize(int boardSize) {
_boardSize = boardSize;
}
int get colorsCount => _colorsCount;
void updateColorsCount(int colorsCount) {
_colorsCount = colorsCount;
}
int getBoardSizeFromLevel(String level) {
switch(level) {
case 'easy': { return 6; }
break;
case 'normal': { return 10; }
break;
case 'hard': { return 14; }
break;
case 'nightmare': { return 20; }
break;
}
return 8;
}
int getColorsCountFromLevel(String level) {
switch(level) {
case 'easy': { return 4; }
break;
case 'normal': { return 5; }
break;
case 'hard': { return 6; }
break;
case 'nightmare': { return 7; }
break;
}
return 4;
}
List get cells => _cells;
void updateCells(List cells) {
_cells = cells;
notifyListeners();
}
updateCellValue(int col, int row, int value) {
_cells[row][col].value = value;
notifyListeners();
}
bool get gameIsRunning => _gameIsRunning; bool get gameIsRunning => _gameIsRunning;
void updateGameIsRunning(bool gameIsRunning) { void updateGameIsRunning(bool gameIsRunning) {
_gameIsRunning = gameIsRunning; _gameIsRunning = gameIsRunning;
...@@ -75,10 +132,14 @@ class Data extends ChangeNotifier { ...@@ -75,10 +132,14 @@ class Data extends ChangeNotifier {
} }
bool isGameFinished() { bool isGameFinished() {
return false; return _gameWon;
} }
bool get gameWon => _gameWon; bool get gameWon => _gameWon;
void updateGameWon(bool gameWon) {
_gameWon = gameWon;
notifyListeners();
}
void resetGame() { void resetGame() {
_gameIsRunning = false; _gameIsRunning = false;
......
import 'dart:math';
import '../entities/cell.dart';
import '../provider/data.dart';
class BoardUtils {
static printGrid(List cells) {
String stringValues = '01234567';
print('');
print('-------');
for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) {
String row = '';
for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
row += stringValues[cells[rowIndex][colIndex].value];
}
print(row);
}
print('-------');
print('');
}
static createNewBoard(Data myProvider) {
int boardSize = myProvider.boardSize;
int maxValue = myProvider.colorsCount;
var rand = new Random();
List grid = [];
for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
List row = [];
for (var colIndex = 0; colIndex < boardSize; colIndex++) {
int value = 1 + rand.nextInt(maxValue);
row.add(Cell(value));
}
grid.add(row);
}
printGrid(grid);
myProvider.resetGame();
myProvider.updateCells(grid);
}
static fillBoardFromFirstCell(Data myProvider, int value) {
List cellsToFill = BoardUtils.getSiblingFillableCells(myProvider, 0, 0, [[0, 0]]);
for (var cellIndex = 0; cellIndex < cellsToFill.length; cellIndex++) {
myProvider.updateCellValue(cellsToFill[cellIndex][1], cellsToFill[cellIndex][0], value);
}
}
static List getSiblingFillableCells(Data myProvider, row, col, siblingCells) {
List cells = myProvider.cells;
int boardSize = myProvider.boardSize;
int referenceValue = cells[row][col].value;
for (var deltaRow = -1; deltaRow <= 1; deltaRow++) {
for (var deltaCol = -1; deltaCol <= 1; deltaCol++) {
if (deltaCol == 0 || deltaRow == 0) {
int candidateRow = row + deltaRow;
int candidateCol = col + deltaCol;
if (
(candidateRow >= 0 && candidateRow < boardSize)
&&
(candidateCol >= 0 && candidateCol < boardSize)
) {
if (cells[candidateRow][candidateCol].value == referenceValue) {
bool alreadyFound = false;
for (var index = 0; index < siblingCells.length; index++) {
if (
(siblingCells[index][0] == candidateRow)
&&
(siblingCells[index][1] == candidateCol)
) {
alreadyFound = true;
}
}
if (!alreadyFound) {
siblingCells.add([candidateRow, candidateCol]);
siblingCells = getSiblingFillableCells(myProvider, candidateRow, candidateCol, siblingCells);
}
}
}
}
}
}
return siblingCells;
}
static bool checkBoardIsSolved(Data myProvider) {
List cells = myProvider.cells;
int boardSize = myProvider.boardSize;
// check grid is fully completed and does not contain conflict
int previousValue = cells[0][0].value;
for (var row = 0; row < boardSize; row++) {
for (var col = 0; col < boardSize; col++) {
if (cells[row][col].value == 0 || cells[row][col].value != previousValue) {
return false;
}
previousValue = cells[row][col].value;
}
}
print('-> ok grid solved!');
return true;
}
}
import '../provider/data.dart'; import '../provider/data.dart';
import '../utils/board_utils.dart';
class GameUtils { class GameUtils {
...@@ -9,8 +10,10 @@ class GameUtils { ...@@ -9,8 +10,10 @@ class GameUtils {
static Future<void> startGame(Data myProvider) async { static Future<void> startGame(Data myProvider) async {
print('Starting game'); print('Starting game');
print('- level: ' + myProvider.level); print('- level: ' + myProvider.level);
print('- size: ' + myProvider.boardSize.toString());
print('- colors: ' + myProvider.colorsCount.toString());
myProvider.resetGame(); BoardUtils.createNewBoard(myProvider);
myProvider.updateGameIsRunning(true); myProvider.updateGameIsRunning(true);
} }
......
...@@ -21,3 +21,4 @@ flutter: ...@@ -21,3 +21,4 @@ flutter:
uses-material-design: true uses-material-design: true
assets: assets:
- assets/icons/ - assets/icons/
- assets/skins/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment