diff --git a/lib/dash_sweeper.dart b/lib/dash_sweeper.dart index 8cbce5e..fb73d08 100644 --- a/lib/dash_sweeper.dart +++ b/lib/dash_sweeper.dart @@ -29,16 +29,10 @@ class _DashSweeperState extends State { final dashAmount = amount ~/ 10; // TODO customize percentage final emptyAmount = amount - dashAmount; - // create tiles - final dashTiles = List.generate( - dashAmount, - (_) => DashTile(TileState.idle), - ); - final emptyTiles = List.generate( - emptyAmount, - (_) => EmptyTile(TileState.idle), - ); - tiles = [...dashTiles, ...emptyTiles]..shuffle(); + tiles = [ + for (var _ in dashAmount.thisLengthList) DashTile(TileState.idle), + for (var _ in emptyAmount.thisLengthList) EmptyTile(TileState.idle), + ]..shuffle(); } bool inBounds(int row, int column) { @@ -48,79 +42,27 @@ class _DashSweeperState extends State { column < widget.columns; } - int? getIndex(int row, int column) { + int? getIndex(NamedPoint point) { + var (:row, :column) = point; if (!inBounds(row, column)) return null; return (row * widget.columns) + column; } - (int row, int column) getPointForIndex(int index) { + NamedPoint getPointForIndex(int index) { final row = (index / widget.columns).floor(); final column = index % widget.columns; - return (row, column); - } - - int? topLeftIndex(int row, int column) { - final targetRow = row - 1; - final targetColumn = column - 1; - return getIndex(targetRow, targetColumn); - } - - int? topCenterIndex(int row, int column) { - final targetRow = row - 1; - return getIndex(targetRow, column); - } - - int? topRightIndex(int row, int column) { - final targetRow = row - 1; - final targetColumn = column + 1; - return getIndex(targetRow, targetColumn); + return (row: row, column: column); } - int? leftIndex(int row, int column) { - final targetColumn = column - 1; - return getIndex(row, targetColumn); - } - - int? rightIndex(int row, int column) { - final targetColumn = column + 1; - return getIndex(row, targetColumn); - } - - int? bottomLeftIndex(int row, int column) { - final targetRow = row + 1; - final targetColumn = column - 1; - return getIndex(targetRow, targetColumn); - } - - int? bottomCenterIndex(int row, int column) { - final targetRow = row + 1; - return getIndex(targetRow, column); - } - - int? bottomRightIndex(int row, int column) { - final targetRow = row + 1; - final targetColumn = column + 1; - return getIndex(targetRow, targetColumn); - } - - List getNeighbouringDashes(int index) { - return getNeighbouringIndeces( - index, - ).where((tileIndex) => tiles[tileIndex] is DashTile).toList(); + int countNeighbouringDashes(int index) { + return getNeighbouringIndeces(index) // formatting hack + .where((tileIndex) => tiles[tileIndex] is DashTile) + .length; } Iterable getNeighbouringIndeces(int index) { - final (row, column) = getPointForIndex(index); - return [ - topLeftIndex(row, column), - topCenterIndex(row, column), - topRightIndex(row, column), - leftIndex(row, column), - rightIndex(row, column), - bottomLeftIndex(row, column), - bottomCenterIndex(row, column), - bottomRightIndex(row, column), - ].nonNulls; + final point = getPointForIndex(index); + return point.adjacents.map(getIndex).nonNulls; } void handleOnLongPress(int index) { @@ -139,7 +81,7 @@ class _DashSweeperState extends State { void handleOnTap(int index) { final tile = tiles[index]; - if (tile.state != TileState.idle) return; + if (!tile.state.isIdle) return; if (tile is DashTile) { _gameOver(); @@ -236,8 +178,8 @@ class _DashSweeperState extends State { toReveal.add(index); checked.add(index); - final dashes = getNeighbouringDashes(index); - if (dashes.isNotEmpty) return toReveal; + final dashes = countNeighbouringDashes(index); + if (dashes > 0) return toReveal; final neighbours = getNeighbouringIndeces(index); if (checked.containsAll(neighbours)) return toReveal; @@ -265,7 +207,7 @@ class _DashSweeperState extends State { onLongPress: () => handleOnLongPress(index), ), EmptyTile(:final state) => EmptyTileItem( - amount: getNeighbouringDashes(index).length, + amount: countNeighbouringDashes(index), state: state, onTap: () => handleOnTap(index), onLongPress: () => handleOnLongPress(index), @@ -277,7 +219,15 @@ class _DashSweeperState extends State { } } -enum TileState { idle, revealed, flagged } +enum TileState { + idle, + revealed, + flagged; + + bool get isIdle => this == TileState.idle; + bool get isRevealed => this == TileState.revealed; + bool get isFlagged => this == TileState.flagged; +} sealed class Tile { final TileState state; @@ -375,18 +325,18 @@ class TileItem extends StatelessWidget { @override Widget build(BuildContext context) { return Card( - elevation: state != TileState.idle ? 0 : 4, + elevation: state.isIdle ? 4 : 0, clipBehavior: Clip.antiAliasWithSaveLayer, child: InkWell( - onTap: onTap, - onLongPress: onLongPress, + onTap: state.isIdle ? onTap : null, + onLongPress: state.isIdle ? onLongPress : null, child: Center( child: AnimatedSwitcher( duration: Duration(milliseconds: 300), child: switch (state) { - TileState.idle => SizedBox(), + TileState.idle => const SizedBox.shrink(), TileState.revealed => child, - TileState.flagged => Icon( + TileState.flagged => const Icon( Icons.flag, color: Colors.red, ), @@ -397,3 +347,20 @@ class TileItem extends StatelessWidget { ); } } + +typedef NamedPoint = ({int row, int column}); + +extension on int { + List get adjacents => [this - 1, this, this + 1]; + + List get thisLengthList => [for (var i = 0; i < this; i++) i]; +} + +extension on NamedPoint { + List get adjacents { + return [ + for (var row in row.adjacents) + for (var column in column.adjacents) (row: row, column: column), + ]; + } +}