Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • android/org.benoitharrault.suguru
1 result
Show changes
Commits on Source (6)
Showing
with 344 additions and 246 deletions
Fix display big vertical grids.
Improve/fix grid solver.
Improve grid display.
Correction sur l'affichage des grandes grilles verticales.
Amélioration/correction du résolveur de grille.
Amélioration de l'affichage de la grille.
......@@ -8,7 +8,9 @@ import 'package:suguru/data/game_data.dart';
import 'package:suguru/models/activity/board.dart';
import 'package:suguru/models/activity/cell.dart';
import 'package:suguru/models/activity/cell_location.dart';
import 'package:suguru/models/activity/move.dart';
import 'package:suguru/models/activity/types.dart';
import 'package:suguru/utils/suguru_solver.dart';
class Activity {
Activity({
......@@ -139,16 +141,12 @@ class Activity {
bool get canGiveTip => (buttonTipsCountdown == 0);
bool checkBoardIsSolved() {
for (CellLocation location in board.getCellLocations()) {
if (board.get(location).value == 0 ||
board.get(location).value != board.solvedCells[location.row][location.col].value) {
return false;
}
if (board.isSolved()) {
printlog('-> ok suguru solved!');
return true;
}
printlog('-> ok suguru solved!');
return true;
return false;
}
ConflictsCount computeConflictsInBoard() {
......@@ -227,7 +225,7 @@ class Activity {
tipGiven = helpSelectCell(activityCubit);
} else {
// currently selected cell -> set value
tipGiven = helpFillCell(activityCubit);
tipGiven = helpFillCell(activityCubit, selectedCell?.location);
}
if (tipGiven) {
......@@ -236,56 +234,66 @@ class Activity {
}
bool helpSelectCell(ActivityCubit activityCubit) {
CellLocation? cellLocationToFix;
// pick one of wrong value cells, if found
final List<List<int>> wrongValueCells = getCellsWithWrongValue();
final List<CellLocation> wrongValueCells = getCellsWithWrongValue();
if (wrongValueCells.isNotEmpty) {
printlog('pick from wrongValueCells');
return pickRandomFromList(activityCubit, wrongValueCells);
wrongValueCells.shuffle();
cellLocationToFix = wrongValueCells[0];
}
// pick one of conflicting cells, if found
final List<List<int>> conflictingCells = getCellsWithConflicts();
final List<CellLocation> conflictingCells = getCellsWithConflicts();
if (conflictingCells.isNotEmpty) {
printlog('pick from conflictingCells');
return pickRandomFromList(activityCubit, conflictingCells);
conflictingCells.shuffle();
cellLocationToFix = conflictingCells[0];
}
// pick one from "easy" cells (unique empty cell in block)
final List<List<int>> easyFillableCells = board.getLastEmptyCellsInBlocks();
if (easyFillableCells.isNotEmpty) {
printlog('pick from easyFillableCells');
return pickRandomFromList(activityCubit, easyFillableCells);
if (cellLocationToFix != null) {
printlog('picked cell with wrong or conflicting value...');
activityCubit.selectCell(cellLocationToFix);
return true;
}
// pick one from cells with unique non-conflicting candidate value
final List<List<int>> candidateCells = board.getEmptyCellsWithUniqueAvailableValue();
if (candidateCells.isNotEmpty) {
printlog('pick from candidateCells');
return pickRandomFromList(activityCubit, candidateCells);
final Move? nextMove = SuguruSolver.pickNextMove(board);
if (nextMove == null) {
printlog('no easy cell to select...');
return false;
}
// pick one from "only cell in this block for this value"
final List<List<int>> onlyCellsWithoutConflict = board.getOnlyCellInBlockWithoutConflict();
if (onlyCellsWithoutConflict.isNotEmpty) {
printlog('pick from onlyCellsWithoutConflict');
return pickRandomFromList(activityCubit, onlyCellsWithoutConflict);
activityCubit.selectCell(nextMove.location);
return true;
}
bool helpFillCell(ActivityCubit activityCubit, CellLocation? location) {
final Move? nextMove = SuguruSolver.pickNextMove(board, location);
if (nextMove == null) {
printlog('unable to compute cell value for $location');
activityCubit.unselectCell();
return false;
}
printlog('no easy cell to select...');
return false;
activityCubit.updateCellValue(nextMove.location, nextMove.value);
activityCubit.unselectCell();
return true;
}
List<List<int>> getCellsWithWrongValue() {
List<CellLocation> getCellsWithWrongValue() {
final BoardCells cells = board.cells;
final BoardCells cellsSolved = board.solvedCells;
List<List<int>> cellsWithWrongValue = [];
List<CellLocation> cellsWithWrongValue = [];
for (int row = 0; row < boardSizeVertical; row++) {
for (int col = 0; col < boardSizeHorizontal; col++) {
if (cells[row][col].value != 0 &&
cells[row][col].value != cellsSolved[row][col].value) {
cellsWithWrongValue.add([row, col]);
cellsWithWrongValue.add(CellLocation.go(row, col));
}
}
}
......@@ -293,13 +301,13 @@ class Activity {
return cellsWithWrongValue;
}
List<List<int>> getCellsWithConflicts() {
List<List<int>> cellsWithConflict = [];
List<CellLocation> getCellsWithConflicts() {
List<CellLocation> cellsWithConflict = [];
for (int row = 0; row < boardSizeVertical; row++) {
for (int col = 0; col < boardSizeHorizontal; col++) {
if (boardConflicts[row][col] != 0) {
cellsWithConflict.add([row, col]);
cellsWithConflict.add(CellLocation.go(row, col));
}
}
}
......@@ -307,73 +315,6 @@ class Activity {
return cellsWithConflict;
}
bool pickRandomFromList(ActivityCubit activityCubit, List<List<int>> cellsCoordinates) {
if (cellsCoordinates.isNotEmpty) {
cellsCoordinates.shuffle();
final List<int> cell = cellsCoordinates[0];
activityCubit.selectCell(CellLocation.go(cell[0], cell[1]));
return true;
}
return false;
}
bool helpFillCell(ActivityCubit activityCubit) {
// Will clean cell if no eligible value found
int eligibleValue = 0;
// Ensure there is only one eligible value for this cell
int allowedValuesCount = 0;
final int maxValueForThisCell = board.getMaxValueForBlock(selectedCell?.blockId);
for (int value = 1; value <= maxValueForThisCell; value++) {
if (board.isValueAllowed(selectedCell?.location, value)) {
allowedValuesCount++;
eligibleValue = value;
}
}
if (allowedValuesCount == 1) {
activityCubit.updateCellValue(selectedCell!.location, eligibleValue);
activityCubit.unselectCell();
return true;
}
activityCubit.unselectCell();
return false;
}
void checkAllTemplates() {
printlog('###############################');
printlog('## ##');
printlog('## CHECK TEMPLATES ##');
printlog('## ##');
printlog('###############################');
final List<String> allowedLevels = ApplicationConfig.config
.getFromCode(ApplicationConfig.parameterCodeDifficultyLevel)
.allowedValues;
final List<String> allowedSizes = ApplicationConfig.config
.getFromCode(ApplicationConfig.parameterCodeBoardSize)
.allowedValues;
for (String level in allowedLevels) {
printlog('* level: $level');
for (String size in allowedSizes) {
printlog('** size: $size');
final List<String> templates = GameData.templates[size]?[level] ?? [];
printlog('*** templates count: ${templates.length}');
for (String template in templates) {
printlog(' checking $template');
final Board testBoard = Board.createEmpty();
testBoard.createFromTemplate(template: template);
testBoard.dump();
}
}
}
}
void dump() {
printlog('');
printlog('## Current game dump:');
......
......@@ -4,7 +4,9 @@ import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:suguru/models/activity/cell.dart';
import 'package:suguru/models/activity/cell_location.dart';
import 'package:suguru/models/activity/move.dart';
import 'package:suguru/models/activity/types.dart';
import 'package:suguru/utils/suguru_solver.dart';
class Board {
Board({
......@@ -35,6 +37,9 @@ class Board {
void createFromTemplate({
required String template,
}) {
printlog('Creating board from template:');
printlog(template);
final List<String> templateParts = template.split(';');
if (templateParts.length != 3) {
printlog('Failed to get grid template (wrong format)...');
......@@ -69,49 +74,8 @@ class Board {
cells.add(row);
}
const List<String> allowedFlip = ['none', 'horizontal', 'vertical'];
List<String> allowedRotate = ['none', 'left', 'right', 'upsidedown'];
// Limit rotation if board is not symetric
if (boardSizeVertical != boardSizeHorizontal) {
allowedRotate = ['none', 'upsidedown'];
}
final Random rand = Random();
final String flip = allowedFlip[rand.nextInt(allowedFlip.length)];
final String rotate = allowedRotate[rand.nextInt(allowedRotate.length)];
switch (flip) {
case 'horizontal':
{
transformFlipHorizontal();
}
break;
case 'vertical':
{
transformFlipVertical();
}
break;
}
switch (rotate) {
case 'left':
{
transformRotateLeft();
}
break;
case 'right':
{
transformRotateRight();
}
break;
case 'upsidedown':
{
transformFlipHorizontal();
transformFlipVertical();
}
break;
}
// Do some transformations to board
transformBoard();
// Force cells fixed states (all cells with value != 0)
for (CellLocation location in getCellLocations()) {
......@@ -124,7 +88,12 @@ class Board {
);
}
resolve();
final Board solvedBoard = SuguruSolver.resolve(this);
solvedCells = solvedBoard.cells;
// FIXME: for debug only
// to start with a board (almost) automatically solved
// cells = solvedCells;
}
// Helper to create board from size, with "empty" cells
......@@ -166,6 +135,55 @@ class Board {
return locations;
}
void transformBoard() {
final int boardSizeVertical = cells.length;
final int boardSizeHorizontal = cells[0].length;
const List<String> allowedFlip = ['none', 'horizontal', 'vertical'];
List<String> allowedRotate = ['none', 'left', 'right', 'upsidedown'];
// Limit rotation if board is not symetric
if (boardSizeVertical != boardSizeHorizontal) {
allowedRotate = ['none', 'upsidedown'];
}
final Random rand = Random();
final String flip = allowedFlip[rand.nextInt(allowedFlip.length)];
final String rotate = allowedRotate[rand.nextInt(allowedRotate.length)];
switch (flip) {
case 'horizontal':
{
transformFlipHorizontal();
}
break;
case 'vertical':
{
transformFlipVertical();
}
break;
}
switch (rotate) {
case 'left':
{
transformRotateLeft();
}
break;
case 'right':
{
transformRotateRight();
}
break;
case 'upsidedown':
{
transformFlipHorizontal();
transformFlipVertical();
}
break;
}
}
void transformFlipHorizontal() {
final BoardCells transformedBoard = copyCells();
final int boardSizeVertical = cells.length;
......@@ -244,18 +262,25 @@ class Board {
cells = transformedBoard;
}
bool inBoard(CellLocation location) {
return (location.row >= 0 &&
location.row < cells.length &&
location.col >= 0 &&
location.col < cells[location.row].length);
}
Cell get(CellLocation location) {
if (location.row < cells.length) {
if (location.col < cells[location.row].length) {
return cells[location.row][location.col];
}
if (inBoard(location)) {
return cells[location.row][location.col];
}
return Cell.none;
}
void setCell(CellLocation location, Cell cell) {
cells[location.row][location.col] = cell;
if (inBoard(location)) {
cells[location.row][location.col] = cell;
}
}
void setValue(CellLocation location, int value) {
......@@ -271,6 +296,11 @@ class Board {
));
}
void applyMove(Move move) {
// printlog('put ${move.value} in ${move.location}');
setValue(move.location, move.value);
}
List<String> getBlockIds() {
List<String> blockIds = [];
for (CellLocation location in getCellLocations()) {
......@@ -314,48 +344,8 @@ class Board {
return copiedGrid;
}
resolve() {
final Board solvedBoard = Board(cells: copyCells(), solvedCells: []);
do {
// last cell in blocks
final List<List<int>> cellsLastEmptyInBlock = solvedBoard.getLastEmptyCellsInBlocks();
for (var cellData in cellsLastEmptyInBlock) {
solvedBoard.setValue(CellLocation.go(cellData[0], cellData[1]), cellData[2]);
}
// last cell in blocks
final List<List<int>> cellsSingleInBlockWithoutConflict =
solvedBoard.getOnlyCellInBlockWithoutConflict();
for (var cellData in cellsSingleInBlockWithoutConflict) {
solvedBoard.setValue(CellLocation.go(cellData[0], cellData[1]), cellData[2]);
}
// empty cells with unique available value
final List<List<int>> cellsWithUniqueAvailableValue =
solvedBoard.getEmptyCellsWithUniqueAvailableValue();
for (var cellData in cellsWithUniqueAvailableValue) {
solvedBoard.setValue(CellLocation.go(cellData[0], cellData[1]), cellData[2]);
}
// no more empty cell to fill
if (cellsLastEmptyInBlock.isEmpty && cellsWithUniqueAvailableValue.isEmpty) {
if (solvedBoard.isSolved()) {
printlog('ok compute solved board');
} else {
printlog('!!');
printlog('!! failed to resolve board');
printlog('!!');
}
break;
}
} while (true);
solvedCells = solvedBoard.cells;
}
bool isSolved() {
// check grid is fully completed
// first, check grid is fully completed
for (CellLocation location in getCellLocations()) {
if (get(location).value == 0) {
return false;
......@@ -387,6 +377,10 @@ class Board {
}
}
if (boardHasSiblingWithSameValue()) {
return false;
}
return true;
}
......@@ -415,8 +409,8 @@ class Board {
return missingValues;
}
List<List<int>> getLastEmptyCellsInBlocks() {
List<List<int>> candidateCells = [];
List<Move> getLastEmptyCellsInBlocks() {
List<Move> candidateCells = [];
for (CellLocation location in getCellLocations()) {
final Cell cell = get(location);
......@@ -433,7 +427,7 @@ class Board {
candidateValue = value;
}
}
candidateCells.add([location.row, location.col, candidateValue]);
candidateCells.add(Move(location: location, value: candidateValue));
}
}
}
......@@ -441,8 +435,8 @@ class Board {
return candidateCells;
}
List<List<int>> getOnlyCellInBlockWithoutConflict() {
List<List<int>> candidateCells = [];
List<Move> getOnlyCellInBlockWithoutConflict() {
List<Move> candidateCells = [];
for (String blockId in getBlockIds()) {
List<int> missingValuesInBlock = getMissingValuesInBlock(blockId);
......@@ -460,7 +454,7 @@ class Board {
if (allowedCellsForThisValue.length == 1) {
final CellLocation candidateLocation = allowedCellsForThisValue[0];
candidateCells.add([candidateLocation.row, candidateLocation.col, candidateValue]);
candidateCells.add(Move(location: candidateLocation, value: candidateValue));
}
}
}
......@@ -468,8 +462,8 @@ class Board {
return candidateCells;
}
List<List<int>> getEmptyCellsWithUniqueAvailableValue() {
List<List<int>> candidateCells = [];
List<Move> getEmptyCellsWithUniqueAvailableValue() {
List<Move> candidateCells = [];
for (CellLocation location in getCellLocations()) {
if (get(location).value == 0) {
......@@ -485,7 +479,7 @@ class Board {
}
if (allowedValuesCount == 1) {
candidateCells.add([location.row, location.col, candidateValue]);
candidateCells.add(Move(location: location, value: candidateValue));
}
}
}
......@@ -531,24 +525,15 @@ class Board {
return false;
}
final int boardSizeVertical = cells.length;
final int boardSizeHorizontal = cells[0].length;
final int value = candidateValue ?? get(cellLocation).value;
if (value != 0) {
for (int deltaRow in [-1, 0, 1]) {
for (int deltaCol in [-1, 0, 1]) {
if (cellLocation.row + deltaRow >= 0 &&
cellLocation.row + deltaRow < boardSizeHorizontal &&
cellLocation.col + deltaCol >= 0 &&
cellLocation.col + deltaCol < boardSizeVertical &&
!(deltaRow == 0 && deltaCol == 0)) {
final CellLocation candidateLocation =
CellLocation.go(cellLocation.row + deltaRow, cellLocation.col + deltaCol);
final int siblingValue = get(candidateLocation).value;
if (siblingValue == value) {
for (int deltaCol in [-1, 0, 1]) {
for (int deltaRow in [-1, 0, 1]) {
final CellLocation siblingLocation =
CellLocation.go(cellLocation.row + deltaRow, cellLocation.col + deltaCol);
if (inBoard(siblingLocation) && !(deltaRow == 0 && deltaCol == 0)) {
if (get(siblingLocation).value == value) {
return true;
}
}
......@@ -596,7 +581,12 @@ class Board {
if (solvedCells.isEmpty) {
rowSolved += '*';
} else {
rowSolved += stringValues[solvedCells[rowIndex][colIndex].value];
final int solvedValue = solvedCells[rowIndex][colIndex].value;
if (solvedValue == 0) {
rowSolved += ' ';
} else {
rowSolved += stringValues[solvedCells[rowIndex][colIndex].value];
}
}
}
printlog('$rowBlocks | $rowValues | $rowSolved');
......
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:suguru/models/activity/cell_location.dart';
class Move {
const Move({
required this.location,
required this.value,
});
final CellLocation location;
final int value;
void dump() {
printlog('$Move:');
printlog(' location: $location');
printlog(' value: $value');
printlog('');
}
@override
String toString() {
return '$Move(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'location': location.toJson(),
'value': value,
};
}
}
......@@ -29,11 +29,6 @@ class PageGame extends StatelessWidget {
const GameBoardWidget(),
const SizedBox(height: 8),
const GameBottomWidget(),
// StyledButton.text(
// onPressed: () => currentActivity.checkAllTemplates(),
// caption: '[debug] test all templates',
// color: Colors.red,
// ),
const Expanded(child: SizedBox.shrink()),
currentActivity.isFinished ? const GameEndWidget() : const SizedBox.shrink(),
],
......
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
......@@ -77,19 +75,35 @@ class CellWidget extends StatelessWidget {
return 'assets/ui/cell_empty.png';
}
Color getBaseColorFromBlockId(String blockId) {
const List<Color> paletteColors = [
Color.fromRGBO(0xbe, 0x7f, 0x51, 1),
Color.fromRGBO(0x50, 0x72, 0x8b, 1),
Color.fromRGBO(0xae, 0x70, 0x6f, 1),
Color.fromRGBO(0x91, 0x61, 0x87, 1),
Color.fromRGBO(0xe1, 0x8a, 0x2b, 1),
Color.fromRGBO(0x88, 0x77, 0x6d, 1),
Color.fromRGBO(0xd4, 0xbe, 0x1e, 1),
Color.fromRGBO(0xba, 0x96, 0x3a, 1),
Color.fromRGBO(0xa2, 0x9a, 0x5c, 1),
];
final int blockIdValue = blockId.codeUnits.first - 'A'.codeUnits.first;
return paletteColors[blockIdValue % paletteColors.length].lighten(20);
}
// Compute cell background color, from cell state
Color getBackgroundColor(Activity activity) {
final Color editableCellColor = Colors.grey.shade100;
final Color editableCellColorConflict = Colors.pink.shade100;
final Color fixedCellColor = Colors.grey.shade300;
final int fixedCellColorDarkAmount = 10;
final Color fixedCellColorConflict = Colors.pink.shade200;
final Color editableAnimated = Colors.green.shade200;
final Color fixedAnimated = Colors.green.shade300;
Color backgroundColor = editableCellColor;
Color backgroundColor = getBaseColorFromBlockId(cell.blockId);
if (cell.isFixed == true) {
backgroundColor = fixedCellColor;
backgroundColor = backgroundColor.darken(fixedCellColorDarkAmount);
}
final int conflictsCount = activity.boardConflicts[cell.location.row][cell.location.col];
......@@ -119,23 +133,14 @@ class CellWidget extends StatelessWidget {
// Compute cell borders, from board size and cell state
Border getCellBorders(Activity activity) {
final Color cellBorderDarkColor = Colors.grey.shade800;
final Color cellBorderLightColor = Colors.grey.shade400;
final Color baseColor = getBaseColorFromBlockId(cell.blockId);
final Color cellBorderDarkColor = baseColor.darken(50);
final Color cellBorderLightColor = baseColor.lighten(10);
const Color cellBorderSelectedColor = Colors.red;
Color cellBorderColor = cellBorderSelectedColor;
double cellBorderWidth = 4;
final int boardSizeReference =
max(activity.boardSizeHorizontal, activity.boardSizeVertical);
// Reduce cell border width on big boards
if (boardSizeReference > 8) {
cellBorderWidth = 2;
if (boardSizeReference > 10) {
cellBorderWidth = 1;
}
}
const double cellBorderWidth = 8;
if (!activity.isRunning) {
cellBorderColor = Colors.green.shade700;
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
......@@ -17,7 +18,11 @@ class GameBoardWidget extends StatelessWidget {
final Color borderColor = Theme.of(context).colorScheme.onSurface;
return Container(
final Size size = MediaQuery.of(context).size;
final double width = size.width;
final double height = size.height;
final Container board = Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
......@@ -81,6 +86,16 @@ class GameBoardWidget extends StatelessWidget {
],
),
);
return ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: width,
height: height * .6,
),
child: FittedBox(
child: board,
), //Text
);
},
);
}
......
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:suguru/config/application_config.dart';
import 'package:suguru/data/game_data.dart';
import 'package:suguru/models/activity/board.dart';
import 'package:suguru/models/activity/cell_location.dart';
import 'package:suguru/models/activity/move.dart';
import 'package:suguru/models/activity/types.dart';
class SuguruSolver {
static Board resolve(Board board) {
printlog('solving grid...');
final BoardCells cells = board.copyCells();
final Board solvedBoard = Board(cells: cells, solvedCells: cells);
solvedBoard.dump();
do {
if (solvedBoard.isSolved()) {
printlog('ok compute solved board');
break;
} else {
final Move? nextMove = pickNextMove(solvedBoard);
if (nextMove != null) {
// found empty cell to fill
solvedBoard.applyMove(nextMove);
// solvedBoard.dump();
} else {
// no more empty cell to fill
if (!solvedBoard.isSolved()) {
printlog('!!');
printlog('!! failed to resolve board');
printlog('!!');
}
break;
}
}
} while (true);
return solvedBoard;
}
static Move? pickNextMove(Board board, [CellLocation? candidateCell]) {
// pick one from "easy" cells (unique empty cell in block)
final List<Move> easyFillableMoves = board.getLastEmptyCellsInBlocks();
if (easyFillableMoves.isNotEmpty) {
printlog('picked next move from easyFillableMoves');
return pickRandomFromList(easyFillableMoves);
}
// pick one from cells with unique non-conflicting candidate value
final List<Move> candidateMoves = board.getEmptyCellsWithUniqueAvailableValue();
if (candidateMoves.isNotEmpty) {
printlog('picked next move from candidateMoves');
return pickRandomFromList(candidateMoves);
}
// pick one from "only cell in this block for this value"
final List<Move> onlyCellsWithoutConflict = board.getOnlyCellInBlockWithoutConflict();
if (onlyCellsWithoutConflict.isNotEmpty) {
printlog('picked next move from onlyCellsWithoutConflict');
return pickRandomFromList(onlyCellsWithoutConflict);
}
printlog('unable to find next move...');
return null;
}
static Board applyMove(Board board, Move move) {
board.setValue(move.location, move.value);
return board;
}
static Move? pickRandomFromList(List<Move> moves) {
if (moves.isNotEmpty) {
moves.shuffle();
return moves[0];
}
return null;
}
static void checkAllTemplates() {
printlog('###############################');
printlog('## ##');
printlog('## CHECK TEMPLATES ##');
printlog('## ##');
printlog('###############################');
final List<String> allowedLevels = ApplicationConfig.config
.getFromCode(ApplicationConfig.parameterCodeDifficultyLevel)
.allowedValues;
final List<String> allowedSizes = ApplicationConfig.config
.getFromCode(ApplicationConfig.parameterCodeBoardSize)
.allowedValues;
for (String level in allowedLevels) {
printlog('* level: $level');
for (String size in allowedSizes) {
printlog('** size: $size');
final List<String> templates = GameData.templates[size]?[level] ?? [];
printlog('*** templates count: ${templates.length}');
for (String template in templates) {
printlog(' checking $template');
final Board testBoard = Board.createEmpty();
testBoard.createFromTemplate(template: template);
testBoard.dump();
}
}
}
}
}
......@@ -3,7 +3,7 @@ description: A suguru game application.
publish_to: "none"
version: 0.0.1+1
version: 0.0.4+4
environment:
sdk: "^3.0.0"
......