Cursussen/Courses Codesnippets     Top 
B4A-chess - Show moving hints


1. Initialize the list
First the global hints list is cleared. Don't forget to declare and initialize this variable (hintslst)!
Then the local hints list is initialized and the piece letter is checked in a select statement.
For each chess piece the call to the correct subroutine is made.
The hints list for the queen or the king is a combination of the moves from a rook and a bishop. The king can only go one square in all directions.
The prowcol variable holds the position from the piece on the board. The pcolor variable holds the color of the piece and the pletter variable holds the piece letter.
Private Sub get_hints(prowcol As String, pcolor As String, pletter As String) As List
	hintslst.Clear
	Private hilst As List
	hilst.Initialize
	Select pletter
		Case "P"
			hilst = pawn_hints(prowcol,pcolor,hilst)
		Case "R"
			Private is_king As Boolean = False
			hilst = rook_hints(prowcol,pcolor,hilst,is_king)
		Case "N"
			hilst = knight_hints(prowcol,pcolor,hilst)
		Case "B"
			Private is_king As Boolean = False
			hilst = bishop_hints(prowcol,pcolor,hilst,is_king)
		Case "Q"
			hilst = queen_hints(prowcol,pcolor,hilst)
		Case "K"
			hilst = king_hints(prowcol,pcolor,hilst)
	End Select
	Return hilst
End Sub


2. Pawn moves
A white pawn can move from its starting position one or two squares up. After that it can only move one square up.
A black pawn moves down from its starting position one or two squares. After that it only moves one square at a time.
A pawn can't move forward (up or down) if there is another piece in its path.
A pawn can take a piece from the opposite color if that piece is on the diagonal one square forward (up for white and down for black).
The first digit from the phrowcol variable is the row integer and the second digit is the column integer.
A row or column integer must be greater than or equal to 0 and less than or equal to 7.
private Sub pawn_hints(phrowcol As String, phcolor As String, hlst As List) As List
	Private phrow As Int = phrowcol.SubString2(0,1)
	Private phcol As Int = phrowcol.SubString(1)
	If phcolor = "W" Then
		If (phrow-1) >= 0 And board((phrow-1),phcol) = "EEE" Then 
			hlst.Add((phrow-1)&phcol)
		End If
		If phrow = 6 And (phrow-2) >= 0 And board((phrow-2),phcol) = "EEE" And hlst.IndexOf((phrow-1)&phcol) <> -1 Then
			hlst.Add((phrow-2)&phcol)
		End If
		' take possible
		If (phrow-1) >= 0 And (phcol-1) >= 0 And board((phrow-1),(phcol-1)).StartsWith("B") Then
			hlst.Add((phrow-1)&(phcol-1))
		End If
		If (phrow-1) >= 0 And (phcol+1) <= 7 And board((phrow-1),(phcol+1)).StartsWith("B") Then
			hlst.Add((phrow-1)&(phcol+1))
		End If
		' in passing
		If phrow = 3 And (phcol-1) >= 0 And board(phrow,(phcol-1)).StartsWith("BP") Then
			hlst.Add((phrow-1)&(phcol-1))
		End If
		If phrow = 3 And (phcol+1) <= 7 And board(phrow,(phcol+1)).StartsWith("BP") Then
			hlst.Add((phrow-1)&(phcol+1))
		End If
	End If
	If phcolor = "B" Then
		If (phrow+1) <= 7 And board((phrow+1),phcol) = "EEE" Then
			hlst.Add((phrow+1)&phcol)
		End If
		If phrow = 1 And (phrow+2) <= 7 And board((phrow+2),phcol) = "EEE" And hlst.IndexOf((phrow+1)&phcol) <> -1 Then
			hlst.Add((phrow+2)&phcol)
		End If
		' take possible
		If (phrow+1) <= 7 And (phcol-1) >= 0 And board((phrow+1),(phcol-1)).StartsWith("W") Then
			hlst.Add((phrow+1)&(phcol-1))
		End If
		If (phrow+1) <= 7 And (phcol+1) <= 7 And board((phrow+1),(phcol+1)).StartsWith("W") Then
			hlst.Add((phrow+1)&(phcol+1))
		End If
		' in passing
		If phrow = 4 And (phcol-1) >= 0 And board(phrow,(phcol-1)).StartsWith("WP") Then
			hlst.Add((phrow+1)&(phcol-1))
		End If
		If phrow = 4 And (phcol+1) <= 7 And board(phrow,(phcol+1)).StartsWith("WP") Then
			hlst.Add((phrow+1)&(phcol+1))
		End If
	End If
	Return hlst
End Sub


3. Rook moves
A rook can move up, down, left and right in the same row or column it is in.
If there is a piece on its path and that piece is from the opposite color than the rook can take that piece and can't go further.
If a piece from the same color blocks the rook's path then the rook can't go further.
The tests use an offset value to verify if the next square is empty or the piece can be taken.
Private Sub rook_hints(rrowcol As String,rcolor As String,hlst As List,iking As Boolean) As List
	Private offset As Int
	Private rrow As Int = rrowcol.SubString2(0,1)
	Private rcol As Int = rrowcol.SubString(1)
	' up
	offset = 1
	Do While (rrow-offset) >= 0
		If board((rrow-offset),rcol) = "EEE" Then
			hlst.Add((rrow-offset)&rcol)
		Else
			If board((rrow-offset),rcol).SubString2(0,1) <> rcolor Then
				hlst.Add((rrow-offset)&rcol)
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' down
	offset = 1
	Do While (rrow+offset) <= 7
		If board((rrow+offset),rcol) = "EEE" Then
			hlst.Add((rrow+offset)&rcol)
		Else
			If board((rrow+offset),rcol).SubString2(0,1) <> rcolor Then
				hlst.Add((rrow+offset)&rcol)
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' left
	offset = 1
	Do While (rcol-offset) >= 0
		If board(rrow,(rcol-offset)) = "EEE" Then
			hlst.Add(rrow&(rcol-offset))
		Else
			If board(rrow,(rcol-offset)).SubString2(0,1) <> rcolor Then
				hlst.Add(rrow&(rcol-offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' right
	offset = 1
	Do While (rcol+offset) <= 7
		If board(rrow,(rcol+offset)) = "EEE" Then
			hlst.Add(rrow&(rcol+offset))
		Else
			If board(rrow,(rcol+offset)).SubString2(0,1) <> rcolor Then
				hlst.Add(rrow&(rcol+offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' castling
	Return hlst
End Sub


4. Knight moves
Aha, the famous knight moves!
A knight (in other languages it could be called a horse) can move in strange ways and jump over existing pieces.
The knight can go two squares up or down and then one square left or right.
The knight piece can also go one square up or down and two squares left or right.
If the destination square contains a piece from the opposite color then the knight can take that piece (except if it's the king because then that king is in a check position).
Private Sub knight_hints(nrowcol As String,ncolor As String,hlst As List) As List
	Private nrow As Int = nrowcol.SubString2(0,1)
	Private ncol As Int = nrowcol.SubString(1)
	' 8 places 2-1 or 1-2
	' lower half
	If (nrow+2) <= 7 And (ncol-1) >= 0 Then
		If board((nrow+2),(ncol-1)) = "EEE" Then
			hlst.Add((nrow+2)&(ncol-1))
		Else
			If board((nrow+2),(ncol-1)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow+2)&(ncol-1))
			End If
		End If
	End If
	If (nrow+2) <= 7 And (ncol+1) <= 7 Then
		If board((nrow+2),(ncol+1)) = "EEE" Then
			hlst.Add((nrow+2)&(ncol+1))
		Else
			If board((nrow+2),(ncol+1)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow+2)&(ncol+1))
			End If
		End If
	End If
	If (nrow+1) <= 7 And (ncol-2) >= 0 Then
		If board((nrow+1),(ncol-2)) = "EEE" Then
			hlst.Add((nrow+1)&(ncol-2))
		Else
			If board((nrow+1),(ncol-2)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow+1)&(ncol-2))
			End If
		End If
	End If
	If (nrow+1) <= 7 And (ncol+2) <= 7 Then
		If board((nrow+1),(ncol+2)) = "EEE" Then
			hlst.Add((nrow+1)&(ncol+2))
		Else
			If board((nrow+1),(ncol+2)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow+1)&(ncol+2))
			End If
		End If
	End If
	' upper half
	If (nrow-2) >= 0 And (ncol-1) >= 0 Then
		If board((nrow-2),(ncol-1)) = "EEE" Then
			hlst.Add((nrow-2)&(ncol-1))
		Else
			If board((nrow-2),(ncol-1)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow-2)&(ncol-1))
			End If
		End If
	End If
	If (nrow-2) >= 0 And (ncol+1) <= 7 Then
		If board((nrow-2),(ncol+1)) = "EEE" Then
			hlst.Add((nrow-2)&(ncol+1))
		Else
			If board((nrow-2),(ncol+1)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow-2)&(ncol+1))
			End If
		End If
	End If
	If (nrow-1) >= 0 And (ncol-2) >= 0 Then
		If board((nrow-1),(ncol-2)) = "EEE" Then
			hlst.Add((nrow-1)&(ncol-2))
		Else
			If board((nrow-1),(ncol-2)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow-1)&(ncol-2))
			End If
		End If
	End If
	If (nrow-1) >= 0 And (ncol+2) <= 7 Then
		If board((nrow-1),(ncol+2)) = "EEE" Then
			hlst.Add((nrow-1)&(ncol+2))
		Else
			If board((nrow-1),(ncol+2)).SubString2(0,1) <> ncolor Then
				hlst.Add((nrow-1)&(ncol+2))
			End If
		End If
	End If
	Return hlst
End Sub


5. Bishop moves
The bishop can move in all diagonal directions.
If there is a piece of the opposite color in the bishop's path it can take that piece and it can't go further.
If a piece from the same color blocks the path from the bishop then the bishop can't go further.
Private Sub bishop_hints(browcol As String,bcolor As String,hlst As List,iking As Boolean) As List
	Private offset As Int
	Private brow As Int = browcol.SubString2(0,1)
	Private bcol As Int = browcol.SubString(1)
	' left up
	offset = 1
	Do While (brow-offset) >= 0 And (bcol-offset) >= 0
		If board((brow-offset),(bcol-offset)) = "EEE" Then
			hlst.Add((brow-offset)&(bcol-offset))
		Else
			If board((brow-offset),(bcol-offset)).SubString2(0,1) <> bcolor Then
				hlst.Add((brow-offset)&(bcol-offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' left down
	offset = 1
	Do While (brow+offset) <= 7 And (bcol-offset) >= 0
		If board((brow+offset),(bcol-offset)) = "EEE" Then
			hlst.Add((brow+offset)&(bcol-offset))
		Else
			If board((brow+offset),(bcol-offset)).SubString2(0,1) <> bcolor Then
				hlst.Add((brow+offset)&(bcol-offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' right up
	offset = 1
	Do While (brow-offset) >= 0 And (bcol+offset) <= 7
		If board((brow-offset),(bcol+offset)) = "EEE" Then
			hlst.Add((brow-offset)&(bcol+offset))
		Else
			If board((brow-offset),(bcol+offset)).SubString2(0,1) <> bcolor Then
				hlst.Add((brow-offset)&(bcol+offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	' right down
	offset = 1
	Do While (brow+offset) <= 7 And (bcol+offset) <= 7
		If board((brow+offset),(bcol+offset)) = "EEE" Then
			hlst.Add((brow+offset)&(bcol+offset))
		Else
			If board((brow+offset),(bcol+offset)).SubString2(0,1) <> bcolor Then
				hlst.Add((brow+offset)&(bcol+offset))
			End If
			Exit
		End If
		If iking = True Then Exit
		offset = offset + 1
	Loop
	Return hlst
End Sub


6. Queen moves
The moves from a queen piece are a combination of the rook moves and the bishop moves.
The queen piece can go in all directions until there is a piece of the opposite color in its path that it can take.
A piece of the same color also blocks the path of the queen piece.
Private Sub queen_hints(qrowcol As String,qcolor As String,hlst As List) As List
	Private is_king As Boolean = False
	' rook hints
	hlst = rook_hints(qrowcol,qcolor,hlst,is_king)
	' bishop hints
	Private hlst1 As List
	hlst1.Initialize
	hlst1 = bishop_hints(qrowcol,qcolor,hlst1,is_king)
	hlst.AddAll(hlst1)
	Return hlst
End Sub


7. King moves
The king piece can move in all directions but only one square at a time.
A king piece can take a piece of the opposite color if that piece is one square away from the king piece.
If a king piece is in a check position it has to move to a non-check position.
The player can put a piece in between the king piece and the piece giving the check.
If the king can't go anywhere without being in a check position then the king is checkmate and the game is over.
Private Sub king_hints(krowcol As String,kcolor As String,hlst As List) As List
	Private is_king As Boolean = True
	' rook hints 1 cell
	hlst = rook_hints(krowcol,kcolor,hlst,is_king)
	' bishop hints 1 cell
	Private hlst1 As List
	hlst1.Initialize
	hlst1 = bishop_hints(krowcol,kcolor,hlst1,is_king)
	hlst.AddAll(hlst1)
	Return hlst
End Sub


8. Show the list
To show the hints we use the show_hints subroutine.
The hints list contains all the possible positions (rowcol) the piece can go to.
The cells or squares are shown with a green border.
Private Sub show_hints(hlst As List)
	For i = 0 To hlst.Size -1
		Dim hrowcol As String = hlst.Get(i)
		Dim pnl1 As Panel = get_board_panel(hrowcol,pnlmain)
		cnvscell.Initialize(pnl1)
		show_cell_border(Colors.Green,10dip,cnvscell)
	Next
End Sub
The get_board_panel subroutine is used to get the panel from the list.
The board panel contains 64 panels and each panel contains 1 label with the piece info.
The routine picks the panel at rowcol position and tests for the panel tag to be the same as the given rowcol.
Public Sub get_board_panel(pnlrowcol As String,pnlboard As Panel) As Panel
	For Each v As B4XView In pnlboard.GetAllViewsRecursive
		If v Is Panel Then
			If v.Tag = pnlrowcol Then
				Return v
			End If
		End If
	Next
	Return Null
End Sub
The subroutine get_hints is called in the pnl_Click subroutine and after that the show_hints routine is called.
This is the code for getting the hints (in pnl_Click above the line srcrowcol = rowcol):
		Private pcscolor As String = srctext.SubString2(0,1)
		Private pcsletter As String = srctext.SubString2(1,2)
		hintslst = get_hints(rowcol,pcscolor,pcsletter)
		Log("hintslst: " & hintslst)
		show_hints(hintslst)
So now you are ready to test the app, but first we have to fix the problem with the vanishing pieces.
In the pnl_Click subroutine you can add the following test below the else line:
		If hintslst.IndexOf(rowcol) = -1 Then
			refresh_board
			clickcnt = 0
			Return
		End If
Now if you tap on the same panel or on a panel that is not in the hints list then the board is refreshed, the click count is reset to 0 and with the return statement we leave the subroutine.