@@ -56,58 +56,48 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5656		case  "ctrl+c" , "q" :
5757			return  m , tea .Quit 
5858		case  "left" , "h" :
59+ 			beforeMerge  :=  m .grid 
5960			m .MergeTilesLeft ()
60- 			/* NOTE: There is an edge case here. This code requires 
61- 			 * that every move the user makes must free up a tile. 
62- 			 * This means that even if the board looks like this: 
63- 			 * 2 | 4 | 8 | 16 
64- 			 * 2 | 4 | 8 | 16 
65- 			 * 2 | 4 | 8 | 16 
66- 			 * 2 | 4 | 8 | 16 
67- 			 * and there is still technically a possible move, if 
68- 			 * the player does not open up new space, the game is 
69- 			 * over. 
70- 			 */ 
71- 			// TODO: Fix above. 
72- 			if  ! m .AddTile () {
73- 				return  m , tea .Quit 
74- 			}
61+ 			m .ValidateTile (beforeMerge )
7562		case  "down" , "j" :
7663			/* Instead of creating a separate method to merge down, 
7764			 * we rotate the grid. This is because the 
7865			 * m.MergeTilesLeft() method is *much* more complex 
7966			 * than m.Rotate90(), so it's simpler to rotate, merge, 
8067			 * then rotate back than to create a separate function. 
8168			 */ 
69+ 			beforeMerge  :=  m .grid 
8270			m .Rotate90 (false )
8371			m .MergeTilesLeft ()
8472			m .Rotate90 (true )
85- 			if  ! m .AddTile () {
86- 				return  m , tea .Quit 
87- 			}
73+ 
74+ 			m .ValidateTile (beforeMerge )
8875		case  "up" , "k" :
76+ 			beforeMerge  :=  m .grid 
8977			m .Rotate90 (true )
9078			m .MergeTilesLeft ()
9179			m .Rotate90 (false )
92- 			if  ! m .AddTile () {
93- 				return  m , tea .Quit 
94- 			}
80+ 			m .ValidateTile (beforeMerge )
9581		case  "right" , "l" :
82+ 			beforeMerge  :=  m .grid 
9683			m .Rotate90 (false )
9784			m .Rotate90 (false )
9885			m .MergeTilesLeft ()
9986			m .Rotate90 (true )
10087			m .Rotate90 (true )
101- 			if  ! m .AddTile () {
102- 				return  m , tea .Quit 
103- 			}
88+ 			m .ValidateTile (beforeMerge )
10489		}
10590	}
10691
10792	if  m .CheckForWin () {
10893		return  m , tea .Quit 
10994	}
11095
96+ 	// The game is over when there are no possible merges. 
97+ 	if  ! m .CanMove () {
98+ 		return  m , tea .Quit 
99+ 	}
100+ 
111101	return  m , nil 
112102}
113103
@@ -116,7 +106,7 @@ func (m model) View() string {
116106
117107	for  y  :=  0 ; y  <  4 ; y ++  {
118108		for  x  :=  0 ; x  <  4 ; x ++  {
119- 			/* The tiles don't look like this: |  256 |, they llok  
109+ 			/* The tiles don't look like this: |  256 |, they look  
120110			 * like this: -------- 
121111			 *            |      | 
122112			 *            |  256 | 
@@ -236,6 +226,50 @@ func (m model) CheckForWin() bool {
236226	return  false 
237227}
238228
229+ func  (m  * model ) ValidateTile (beforeMerge  [4 ][4 ]int ) (tea.Model , tea.Cmd ) {
230+ 	// Check if the grid has changed after handling the merge logic. 
231+ 	if  m .grid  !=  beforeMerge  {
232+ 		// If unable to add a tile, quit. 
233+ 		if  ! m .AddTile () {
234+ 			return  m , tea .Quit 
235+ 		}
236+ 	}
237+ 
238+ 	return  m , nil 
239+ }
240+ 
241+ // Validates that movement is possible. Returns true only if there is at least one empty tile or any adjacent equal pairs present. 
242+ func  (m  model ) CanMove () bool  {
243+ 	// Checks for empty tiles. 
244+ 	for  y  :=  0 ; y  <  4 ; y ++  {
245+ 		for  x  :=  0 ; x  <  4 ; x ++  {
246+ 			if  m.grid [y ][x ] ==  0  {
247+ 				return  true 
248+ 			}
249+ 		}
250+ 	}
251+ 
252+ 	// Checks if there are any horizontal merges within the grid. 
253+ 	for  y  :=  0 ; y  <  4 ; y ++  {
254+ 		for  x  :=  0 ; x  <  3 ; x ++  {
255+ 			if  m.grid [y ][x ] ==  m .grid [y ][x + 1 ] {
256+ 				return  true 
257+ 			}
258+ 		}
259+ 	}
260+ 
261+ 	// Checks if there are any vertical merges within the grid. 
262+ 	for  x  :=  0 ; x  <  4 ; x ++  {
263+ 		for  y  :=  0 ; y  <  3 ; y ++  {
264+ 			if  m.grid [y ][x ] ==  m .grid [y + 1 ][x ] {
265+ 				return  true 
266+ 			}
267+ 		}
268+ 	}
269+ 
270+ 	return  false 
271+ }
272+ 
239273func  Run () {
240274	p  :=  tea .NewProgram (initialModel ())
241275
0 commit comments