11import 'dart:collection' ;
2+ import 'dart:math' ;
23import 'package:collection/collection.dart' ;
34import 'package:flutter/material.dart' ;
45import 'package:flutter_riverpod/flutter_riverpod.dart' ;
@@ -11,9 +12,10 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
1112 static const Duration scaleAppearDurationForWall = Duration (milliseconds: 700 );
1213 static const Duration clearDuration = Duration (microseconds: 10 );
1314 static const Duration drawFindingPathDuration = Duration (milliseconds: 2 );
14- static const Duration drawSearcherDuration = Duration (milliseconds: 2 );
15+ static const Duration drawSearcherDuration = Duration (milliseconds: 5 );
1516
1617 int tapDownIndex = - 1 ;
18+ GridStatus tapDownGridStatus = GridStatus .empty;
1719
1820 void updateGridLayout (Size size) {
1921 final screenWidth = size.width;
@@ -92,12 +94,14 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
9294 return gridStatus;
9395 }
9496
95- Future <void > _clearTheGrid ({required GridNotifierState addState}) async {
97+ Future <void > _clearTheGrid ({required GridNotifierState addState, bool keepWall = false }) async {
9698 final elements = addState.gridData;
9799
98100 for (int i = 0 ; i < elements.length; i++ ) {
99101 final grid = addState.gridData[i];
102+
100103 if (grid == GridStatus .targetPoint || grid == GridStatus .startPoint) continue ;
104+ if (grid == GridStatus .wall && keepWall) continue ;
101105
102106 addState.gridData[i] = GridStatus .empty;
103107 state = addState.copyWith (gridData: addState.gridData);
@@ -106,8 +110,8 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
106110 }
107111 }
108112
109- void clearTheGrid () {
110- _clearTheGrid (addState: state);
113+ void clearTheGrid ({ bool keepWall = false } ) {
114+ _clearTheGrid (addState: state, keepWall : keepWall );
111115
112116 state = state.copyWith (currentTappedIndex: - 1 );
113117 }
@@ -131,11 +135,13 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
131135 final currentGrid = updatedGridData[index];
132136
133137 if (updatedGridData[tapDownIndex] == GridStatus .startPoint) {
134- updatedGridData[tapDownIndex] = GridStatus .empty;
138+ updatedGridData[tapDownIndex] = tapDownGridStatus;
139+ tapDownGridStatus = updatedGridData[index];
135140 updatedGridData[index] = GridStatus .startPoint;
136141 tapDownIndex = index;
137142 } else if (updatedGridData[tapDownIndex] == GridStatus .targetPoint) {
138- updatedGridData[tapDownIndex] = GridStatus .empty;
143+ updatedGridData[tapDownIndex] = tapDownGridStatus;
144+ tapDownGridStatus = updatedGridData[index];
139145 updatedGridData[index] = GridStatus .targetPoint;
140146 tapDownIndex = index;
141147 } else if (currentGrid == GridStatus .empty) {
@@ -288,7 +294,7 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
288294 bool _isValidNeighbor (
289295 int currentIndex, int neighborIndex, int direction, int cross, List <GridStatus > gridData) {
290296 final isFirstLeftInRowIndex = neighborIndex % cross == 0 ;
291- final isEndRightInRowIndex = neighborIndex % (cross - 1 ) == 0 ;
297+ final isEndRightInRowIndex = ( neighborIndex + 1 ) % cross == 0 ;
292298
293299 if (direction == 1 && isFirstLeftInRowIndex) return false ; // avoid exiting the boundaries
294300 if (direction == - 1 && isEndRightInRowIndex) return false ; // avoid exiting the boundaries
@@ -311,4 +317,79 @@ class GridNotifierCubit extends StateNotifier<GridNotifierState> {
311317 traceIndex = previous[traceIndex];
312318 }
313319 }
320+
321+ void generateMaze () {
322+ final gridData = List <GridStatus >.from (state.gridData);
323+
324+ // Clear the maze but keep start and target points
325+ for (int i = 0 ; i < gridData.length; i++ ) {
326+ if (gridData[i] != GridStatus .startPoint && gridData[i] != GridStatus .targetPoint) {
327+ gridData[i] = GridStatus .empty;
328+ }
329+ }
330+
331+ // Start the division from the full grid
332+ _recursiveDivision (gridData, 0 , state.rowMainAxisCount, 0 , state.columnCrossAxisCount);
333+ }
334+
335+ Future <void > _recursiveDivision (
336+ List <GridStatus > gridData, int rowStart, int rowEnd, int colStart, int colEnd) async {
337+ if (rowEnd - rowStart < 2 || colEnd - colStart < 2 ) return ; // Avoid too small segments
338+
339+ bool divideVertically = Random ().nextBool ();
340+
341+ if (divideVertically) {
342+ return _recursiveVerticalDivision (gridData, rowStart, rowEnd, colStart, colEnd);
343+ } else {
344+ return _recursiveHorizontalDivision (gridData, rowStart, rowEnd, colStart, colEnd);
345+ }
346+ }
347+
348+ Future <void > _recursiveVerticalDivision (
349+ List <GridStatus > gridData, int rowStart, int rowEnd, int colStart, int colEnd) async {
350+ if (rowEnd - rowStart < 2 || colEnd - colStart < 2 ) return ;
351+
352+ int splitCol = Random ().nextInt (colEnd - colStart - 1 ) + colStart + 1 ;
353+ for (int row = rowStart; row < rowEnd; row++ ) {
354+ if (row == rowStart || row == rowEnd - 1 ) continue ; // Skip the boundary
355+ final index = row * state.columnCrossAxisCount + splitCol;
356+ final grid = gridData[index];
357+ if (grid == GridStatus .startPoint || grid == GridStatus .targetPoint) return ;
358+ gridData[index] = GridStatus .wall;
359+ state = state.copyWith (gridData: List <GridStatus >.from (gridData));
360+ await Future .delayed (const Duration (milliseconds: 10 ));
361+ }
362+
363+ // Open a passage
364+ int passageAt = Random ().nextInt (rowEnd - rowStart) + rowStart;
365+ gridData[passageAt * state.columnCrossAxisCount + splitCol] = GridStatus .empty;
366+
367+ await _recursiveDivision (gridData, rowStart, rowEnd, colStart, splitCol);
368+ await _recursiveDivision (gridData, rowStart, rowEnd, splitCol + 1 , colEnd);
369+ }
370+
371+ Future <void > _recursiveHorizontalDivision (
372+ List <GridStatus > gridData, int rowStart, int rowEnd, int colStart, int colEnd) async {
373+ if (rowEnd - rowStart < 2 || colEnd - colStart < 2 ) return ;
374+
375+ int splitRow = Random ().nextInt (rowEnd - rowStart - 1 ) + rowStart + 1 ;
376+ for (int col = colStart; col < colEnd; col++ ) {
377+ if (col == colStart || col == colEnd - 1 ) continue ; // Skip the boundary
378+
379+ final index = splitRow * state.columnCrossAxisCount + col;
380+ final grid = gridData[index];
381+ if (grid == GridStatus .startPoint || grid == GridStatus .targetPoint) return ;
382+ gridData[index] = GridStatus .wall;
383+
384+ state = state.copyWith (gridData: List <GridStatus >.from (gridData));
385+ await Future .delayed (const Duration (milliseconds: 10 ));
386+ }
387+
388+ // Open a passage
389+ int passageAt = Random ().nextInt (colEnd - colStart) + colStart;
390+ gridData[splitRow * state.columnCrossAxisCount + passageAt] = GridStatus .empty;
391+
392+ await _recursiveDivision (gridData, rowStart, splitRow, colStart, colEnd);
393+ await _recursiveDivision (gridData, splitRow + 1 , rowEnd, colStart, colEnd);
394+ }
314395}
0 commit comments