Skip to content

Commit 24a437b

Browse files
committed
highlights squares of possible moves of selected piece, error messages, handling clicks outside the board
1 parent 6f47267 commit 24a437b

2 files changed

Lines changed: 133 additions & 43 deletions

File tree

app/src/main/java/com/example/chaiss/PlayActivity.java

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,48 @@
22

33
import android.graphics.drawable.PictureDrawable;
44
import android.os.Bundle;
5+
import android.util.Log;
56
import android.view.MotionEvent;
67
import android.view.View;
78
import android.widget.ImageView;
89
import android.widget.Toast;
910
import androidx.appcompat.app.AppCompatActivity;
1011

1112
import com.caverock.androidsvg.SVG;
13+
import com.caverock.androidsvg.PreserveAspectRatio;
14+
import com.caverock.androidsvg.SVGParseException;
15+
import com.chaquo.python.PyObject;
16+
import com.chaquo.python.Python;
17+
import com.chaquo.python.android.AndroidPlatform;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
1221

1322
public class PlayActivity extends AppCompatActivity {
1423

15-
private ChessEngine chessEngine;
24+
private Python py;
25+
private PyObject chessLogic;
1626
private String currentFEN;
1727
private ImageView chessBoardImage;
18-
19-
private String selectedSquare = null; // Track the square being touched
28+
private String selectedSquare = null;
29+
private List<String> legalMoves = null;
2030

2131
@Override
2232
protected void onCreate(Bundle savedInstanceState) {
2333
super.onCreate(savedInstanceState);
2434
setContentView(R.layout.activity_play);
2535

26-
chessEngine = new ChessEngine();
36+
if(!Python.isStarted()) {
37+
Python.start(new AndroidPlatform(this));
38+
}
39+
py = Python.getInstance();
40+
chessLogic = py.getModule("chess_logic");
41+
2742
chessBoardImage = findViewById(R.id.chess_board);
2843

29-
// Initialize board state
30-
currentFEN = chessEngine.createBoard();
44+
currentFEN = chessLogic.callAttr("create_board").toString();
3145
updateBoard();
3246

33-
// Set touch listener on the chessboard
3447
chessBoardImage.setOnTouchListener(new View.OnTouchListener() {
3548
@Override
3649
public boolean onTouch(View v, MotionEvent event) {
@@ -42,61 +55,116 @@ public boolean onTouch(View v, MotionEvent event) {
4255
}
4356
});
4457

45-
// Back arrow functionality
4658
ImageView backArrow = findViewById(R.id.back_arrow);
4759
backArrow.setOnClickListener(v -> finish());
4860
}
4961

5062
private void handleTouch(float x, float y) {
51-
// Map touch coordinates to a chess square
5263
String square = getSquareFromTouch(x, y);
53-
64+
if (square == null) {
65+
return;
66+
}
5467
if (selectedSquare == null) {
55-
// First touch: select the piece
5668
selectedSquare = square;
57-
Toast.makeText(this, "Selected: " + selectedSquare, Toast.LENGTH_SHORT).show();
69+
try {
70+
PyObject legalMovesPy = chessLogic.callAttr("get_legal_moves_from_square", currentFEN, selectedSquare);
71+
List<String> legalMoves = new ArrayList<>();
72+
for (PyObject move : legalMovesPy.asList()) {
73+
legalMoves.add(move.toString());
74+
}
75+
if (legalMoves.isEmpty()) {
76+
Toast.makeText(this, "No legal moves from " + selectedSquare, Toast.LENGTH_SHORT).show();
77+
selectedSquare = null;
78+
} else {
79+
this.legalMoves = legalMoves;
80+
updateBoard();
81+
}
82+
} catch (Exception e) {
83+
Toast.makeText(this, "Error finding legal moves: " + e.getMessage(), Toast.LENGTH_SHORT).show();
84+
selectedSquare = null;
85+
}
5886
} else {
59-
// Second touch: move the piece
60-
String move = selectedSquare + square; // e.g., "e2e4"
87+
String move = selectedSquare + square;
88+
Log.d("ChessApp", "Attempting move: " + move);
6189
try {
62-
currentFEN = chessEngine.makeMove(currentFEN, move); // Update the board state
63-
updateBoard(); // Redraw the board
64-
selectedSquare = null; // Reset selection
90+
PyObject result = chessLogic.callAttr("make_move", currentFEN, move);
91+
currentFEN = result.toString();
92+
selectedSquare = null;
93+
this.legalMoves = null;
94+
updateBoard();
6595
} catch (Exception e) {
66-
Toast.makeText(this, "Invalid move", Toast.LENGTH_SHORT).show();
67-
selectedSquare = null; // Reset selection
96+
Toast.makeText(this, "Invalid move: " + e.getMessage(), Toast.LENGTH_SHORT).show();
97+
selectedSquare = null;
98+
this.legalMoves = null;
99+
updateBoard();
68100
}
69101
}
70102
}
71103

72104
private String getSquareFromTouch(float x, float y) {
73-
// Calculate board square based on touch coordinates
74-
int boardSize = chessBoardImage.getWidth(); // Assuming square layout
105+
int boardSize = chessBoardImage.getWidth();
75106
int squareSize = boardSize / 8;
76107

77108
int col = (int) (x / squareSize);
78-
int row = 7 - (int) (y / squareSize); // Flip Y-axis for chess notation
109+
int row = 7 - (int) (y / squareSize);
110+
111+
if (col < 0 || col > 7 || row < 0 || row > 7) {
112+
return null;
113+
}
79114

80115
char file = (char) ('a' + col);
81116
int rank = row + 1;
82117

83-
return "" + file + rank; // Chess notation, e.g., "e2"
118+
return "" + file + rank;
84119
}
85120

86121
private void updateBoard() {
87-
try {
88-
// Fetch the SVG representation of the chessboard from the Python code
89-
String boardSvg = chessEngine.renderBoard(currentFEN);
90-
91-
// Use AndroidSVG to render the SVG
92-
SVG svg = SVG.getFromString(boardSvg);
93-
PictureDrawable drawable = new PictureDrawable(svg.renderToPicture());
94-
95-
// Display the drawable in the ImageView
96-
chessBoardImage.setLayerType(View.LAYER_TYPE_SOFTWARE, null); // Required for SVG rendering
97-
chessBoardImage.setImageDrawable(drawable);
98-
} catch (Exception e) {
99-
Toast.makeText(this, "Error rendering board: " + e.getMessage(), Toast.LENGTH_SHORT).show();
122+
new Thread(() -> {
123+
try {
124+
PyObject svgData;
125+
if (selectedSquare != null && legalMoves != null) {
126+
String[] legalMovesArray = legalMoves.toArray(new String[0]);
127+
svgData = chessLogic.callAttr("render_board", currentFEN, selectedSquare, (Object) legalMovesArray);
128+
} else {
129+
svgData = chessLogic.callAttr("render_board", currentFEN);
130+
}
131+
String boardSvg = svgData.toString();
132+
runOnUiThread(() -> {
133+
try {
134+
SVG svg = SVG.getFromString(boardSvg);
135+
svg.setDocumentWidth("100%");
136+
svg.setDocumentHeight("100%");
137+
svg.setDocumentPreserveAspectRatio(PreserveAspectRatio.LETTERBOX);
138+
chessBoardImage.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
139+
chessBoardImage.setImageDrawable(new PictureDrawable(svg.renderToPicture()));
140+
} catch (SVGParseException e) {
141+
Toast.makeText(this, "Error rendering board: " + e.getMessage(), Toast.LENGTH_SHORT).show();
142+
e.printStackTrace();
143+
}
144+
});
145+
} catch (Exception e) {
146+
runOnUiThread(() -> {
147+
Toast.makeText(this, "Error rendering board: " + e.getMessage(), Toast.LENGTH_LONG).show();
148+
});
149+
e.printStackTrace();
150+
}
151+
}).start();
152+
}
153+
@Override
154+
protected void onSaveInstanceState(Bundle outState) {
155+
super.onSaveInstanceState(outState);
156+
outState.putString("currentFEN", currentFEN);
157+
outState.putString("selectedSquare", selectedSquare);
158+
if (legalMoves != null) {
159+
outState.putStringArrayList("legalMoves", new ArrayList<>(legalMoves));
100160
}
101161
}
162+
@Override
163+
protected void onRestoreInstanceState(Bundle savedInstanceState) {
164+
super.onRestoreInstanceState(savedInstanceState);
165+
currentFEN = savedInstanceState.getString("currentFEN");
166+
selectedSquare = savedInstanceState.getString("selectedSquare");
167+
legalMoves = savedInstanceState.getStringArrayList("legalMoves");
168+
updateBoard();
169+
}
102170
}

app/src/main/python/chess_logic.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,39 @@ def create_board():
77

88
def get_legal_moves(fen):
99
board = chess.Board(fen)
10-
return [move.uci() for move in board.legal_moves]
10+
moves = [move.uci() for move in board.legal_moves]
11+
return moves
1112

12-
def make_move(fen, move):
13+
def make_move(fen, move_uci):
1314
board = chess.Board(fen)
14-
if move in [m.uci() for m in board.legal_moves]:
15-
board.push_uci(move)
15+
move = chess.Move.from_uci(move_uci)
16+
if move in board.legal_moves:
17+
board.push(move)
1618
return board.fen()
1719
else:
18-
raise ValueError("Invalid move")
20+
raise ValueError(f"Invalid move: {move_uci}")
1921

20-
def render_board(fen):
22+
def get_legal_moves_from_square(fen, square):
2123
board = chess.Board(fen)
22-
svg_data = chess.svg.board(board)
24+
legal_moves = []
25+
from_square = chess.parse_square(square)
26+
for move in board.legal_moves:
27+
if move.from_square == from_square:
28+
to_square = chess.square_name(move.to_square)
29+
legal_moves.append(to_square)
30+
return legal_moves
31+
32+
def render_board(fen, selected_square=None, legal_moves=None):
33+
board = chess.Board(fen)
34+
squares_to_highlight = {}
35+
if selected_square:
36+
selected_sq = chess.parse_square(selected_square)
37+
squares_to_highlight[selected_sq] = "#a9a9f5"
38+
39+
if legal_moves:
40+
for move_square in legal_moves:
41+
sq = chess.parse_square(move_square)
42+
squares_to_highlight[sq] = "#f5a9a9"
43+
44+
svg_data = chess.svg.board(board, squares=squares_to_highlight)
2345
return svg_data

0 commit comments

Comments
 (0)