summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile10
-rw-r--r--checks.c364
-rw-r--r--chess.h39
-rw-r--r--computer_player.c49
-rw-r--r--main.c200
-rw-r--r--ncurses.c342
-rw-r--r--valid.c254
8 files changed, 1259 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7b05f41
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
chess
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..aea03ac
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
1CC ?= cc
2LDFLAGS = -lncurses
3
4output:
5 ${CC} main.c ncurses.c valid.c checks.c computer_player.c $(LDFLAGS) -o chess
6
7clean:
8 rm -f chess
9
10install: output
diff --git a/checks.c b/checks.c
new file mode 100644
index 0000000..64418b2
--- /dev/null
+++ b/checks.c
@@ -0,0 +1,364 @@
1#include "chess.h"
2int isvalid_move(int side, int start_row, int start_col, int end_row, int end_col);
3int ischeck(int side, int row, int col);
4int ischeck_mate(int side, int row, int col);
5void find_kings();
6extern int board[ROW_SIZE][ROW_SIZE];
7extern int check, white_king_row, white_king_col, black_king_row, black_king_col;
8
9/* Returns 1 if king is in check, returns 0 otherwise */
10int ischeck(int side, int row, int col) {
11 /* Check horizontal */
12 /* Check left */
13 for (int i = row - 1; i >= 0; i--) {
14 int piece = board[i][col];
15 if (piece > 0) { /* If the square is not empty */
16 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
17 if (piece % 10 == 5 || piece % 10 == 2) { /* If the piece is a rook or queen then the king is in check*/
18 return 1;
19 }
20 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
21 break;
22 }
23 }
24 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
25 break;
26 }
27 }
28 }
29
30 /* Check right */
31 for (int i = row + 1; i < ROW_SIZE; i++) {
32 int piece = board[i][col];
33 if (piece > 0) { /* If the square is not empty */
34 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
35 if (piece % 10 == 5 || piece % 10 == 2) { /* If the piece is a rook or queen then the king is in check*/
36 return 1;
37 }
38 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
39 break;
40 }
41 }
42 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
43 break;
44 }
45 }
46 }
47
48 /* Check vertical */
49 /* Check down */
50 for (int i = col - 1; i >= 0; i--) {
51 int piece = board[row][i];
52 if (piece > 0) { /* If the square is not empty */
53 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
54 if (piece % 10 == 5 || piece % 10 == 2) { /* If the piece is a rook or queen then the king is in check*/
55 return 1;
56 }
57 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
58 break;
59 }
60 }
61 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
62 break;
63 }
64 }
65 }
66
67 /* Check up */
68 for (int i = col + 1; i < ROW_SIZE; i++) {
69 int piece = board[row][i];
70 if (piece > 0) { /* If the square is not empty */
71 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
72 if (piece % 10 == 5 || piece % 10 == 2) { /* If the piece is a rook or queen then the king is in check*/
73 return 1;
74 }
75 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
76 break;
77 }
78 }
79 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
80 break;
81 }
82 }
83 }
84
85 /* Check diagonal */
86 /* Check up and left */
87 for (int i = row + 1, j = col - 1; i < ROW_SIZE && j >= 0; i++, j--) {
88 int piece = board[i][j];
89 if (piece > 0) { /* If the square is not empty */
90 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
91 if (piece % 10 == 5 || piece % 10 == 4) { /* If the piece is a queen or bishop */
92 return 1;
93 }
94 else if (piece == BLACK_PAWN && side == WHITE) {
95 return 1;
96 }
97 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
98 break;
99 }
100 }
101 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
102 break;
103 }
104 }
105 }
106
107 /* Check up and right */
108 for (int i = row + 1, j = col + 1; i < ROW_SIZE && j < ROW_SIZE; i++, j++) {
109 int piece = board[i][j];
110 if (piece > 0) { /* If the square is not empty */
111 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
112 if (piece % 10 == 5 || piece % 10 == 4) { /* If the piece is a bishop */
113 return 1;
114 }
115 else if (piece == BLACK_PAWN && side == WHITE) {
116 return 1;
117 }
118 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
119 break;
120 }
121 }
122 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
123 break;
124 }
125 }
126 }
127
128 /* Check down and left */
129 for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
130 int piece = board[i][j];
131 if (piece > 0) { /* If the square is not empty */
132 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
133 if (piece % 10 == 5 || piece % 10 == 4) { /* If the piece is a bishop */
134 return 1;
135 }
136 else if (piece == WHITE_PAWN && side == BLACK) {
137 return 1;
138 }
139 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
140 break;
141 }
142 }
143 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
144 break;
145 }
146 }
147 }
148
149 /* Check down and right */
150 for (int i = row - 1, j = col + 1; i >=0 && j < ROW_SIZE; i--, j++) {
151 int piece = board[i][j];
152 if (piece > 0) { /* If the square is not empty */
153 if ((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) { /* If the piece belongs to the opponent */
154 if (piece % 10 == 5 || piece % 10 == 4) { /* If the piece is a bishop */
155 return 1;
156 }
157 else if (piece == WHITE_PAWN && side == BLACK) { /* If white pawn is below and to right if a king, that is check */
158 return 1;
159 }
160 else { /* If its another piece, stop looking left as the king is screened by the non rook or queen piece */
161 break;
162 }
163 }
164 else { /* If it is a friendly piece, the king is safe to the left so stop looking*/
165 break;
166 }
167 }
168 }
169
170 /* Check for knights */
171 if (board[row-2][col-1] > 0){
172 if (row-2 >= 0 && row-2 < ROW_SIZE && col-1 >=0 && col-1 < ROW_SIZE) { /* Only check if the resulting row and column are valid values on the board */
173 int piece = board[row-2][col-1];
174 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
175 return 1;
176 }
177 }
178 }
179
180 if (board[row-2][col+1] > 0) {
181 if (row-2 >= 0 && row-2 < ROW_SIZE && col+1 >=0 && col+1 < ROW_SIZE) {
182 int piece = board[row-2][col+1];
183 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
184 return 1;
185 }
186 }
187 }
188
189 if (board[row-1][col-2] > 0) {
190 if (row-1 >= 0 && row-1 < ROW_SIZE && col-2 >=0 && col-2 < ROW_SIZE) {
191 int piece = board[row-1][col-2];
192 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
193 return 1;
194 }
195 }
196 }
197
198 if (board[row-1][col+2] > 0){
199 if (row-1 >= 0 && row-1 < ROW_SIZE && col+2 >=0 && col+2 < ROW_SIZE) {
200 int piece = board[row-1][col+2];
201 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
202 return 1;
203 }
204 }
205 }
206
207 if (board[row+2][col-1] > 0) {
208 if (row+2 >= 0 && row+2 < ROW_SIZE && col-1 >=0 && col-1 < ROW_SIZE) {
209 int piece = board[row+2][col-1];
210 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
211 return 1;
212 }
213 }
214 else {
215 }
216 }
217
218 if (board[row+2][col+1] > 0) {
219 if (row+2 >= 0 && row+2 < ROW_SIZE && col+1 >=0 && col+1 < ROW_SIZE) {
220 int piece = board[row+2][col+1];
221 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
222 return 1;
223 }
224 }
225 }
226
227 if (board[row+1][col-2] > 0) {
228 if (row+1 >= 0 && row+1 < ROW_SIZE && col-2 >=0 && col-2 < ROW_SIZE) {
229 int piece = board[row+1][col-2];
230 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
231 return 1;
232 }
233 }
234 }
235 if (board[row+1][col+2] > 0) {
236 if (row+1 >= 0 && row+1 < ROW_SIZE && col+2 >=0 && col+2 < ROW_SIZE) {
237 int piece = board[row+1][col+2];
238 if (((side == WHITE && piece > 10) || (side == BLACK && piece < 10)) && piece % 10 == 3) { /* If it is an opponent's knight */
239 return 1;
240 }
241 }
242 }
243
244 return 0;
245}
246
247int can_king_move(int side, int row, int col);
248int can_piece_block(int side, int row, int col);
249
250/* Returns 1 if checkmate, 0 if not */
251int ischeck_mate(int side, int row, int col) {
252 if(!can_king_move(side, row, col)) {
253 if(!can_piece_block(side, row, col)) {
254 return 1;
255 }
256 }
257 return 0;
258}
259
260int can_piece_block(int side, int row, int col) {
261 /* Brute force check if any move causes the king not to be in check */
262 for (int i = 0; i < ROW_SIZE; i++) {
263 for (int j = 0; j < ROW_SIZE; j++) {
264 if ((board[i][j] < 10 && side == WHITE) || (board[i][j] > 10 && side == BLACK)) {
265 int piece = board[i][j];
266 for (int k = 0; k < ROW_SIZE; k++){
267 for(int l = 0; l < ROW_SIZE; l++) {
268 if (isvalid_move(side, i, j, k, l)) {
269 /* Make the move and run ischeck to see if the king is still in check afterwards */
270 int destination_piece = board[k][l];
271 board[k][l] = piece;
272 board[i][j] = 0;
273
274 find_kings(); /* Find the kings in case they have moved */
275
276 /* If the king is not in check after this move, then a valid move exists, so no checkmate*/
277 if (side == WHITE) {
278 if(!ischeck(WHITE, white_king_row, white_king_col)) {
279 /* Make sure to undo the test move */
280 board[i][j] = piece;
281 board[k][l] = destination_piece;
282 find_kings();
283 return 1;
284 }
285 }
286 else if (side == BLACK) {
287 if (!ischeck(BLACK, black_king_row, black_king_col)) {
288 /* Make sure to undo the test move */
289 board[i][j] = piece;
290 board[k][l] = destination_piece;
291 find_kings();
292 //printw("%d %d -> %d %d gets the black king out of check", i, j, k, l);
293 return 1;
294 }
295 }
296 /* Make sure to undo the test move */
297 board[i][j] = piece;
298 board[k][l] = destination_piece;
299 }
300 }
301 }
302 }
303 }
304 }
305 return 0;
306}
307
308/* Returns 0 if the King can safely move to a square to get out of check */
309int can_king_move(int side, int row, int col) {
310 if (!ischeck(side, row, col)) { /* If the king is not in check in the current position, checkmate is not possible */
311 return 1;
312 }
313 /* Check if the king can move safely move to any square around him*/
314 int temp_row, temp_col;
315 /* row+1, col */
316 temp_row = row + 1; temp_col = col;
317 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
318 return 1;
319 }
320
321 /* row+1, col+1 */
322 temp_row = row + 1; temp_col = col + 1;
323 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
324 return 1;
325 }
326
327 /* row, col+1 */
328 temp_row = row; temp_col = col + 1;
329 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
330 return 1;
331 }
332
333 /* row-1, col-1 */
334 temp_row = row - 1; temp_col = col - 1;
335 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
336 return 1;
337 }
338
339 /* row-1, col */
340 temp_row = row - 1; temp_col = col;
341 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
342 return 1;
343 }
344
345 /* row-1, col+1 */
346 temp_row = row - 1; temp_col = col + 1;
347 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
348 return 1;
349 }
350
351 /* row, col-1 */
352 temp_row = row; temp_col = col - 1;
353 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE) {
354 return 1;
355 }
356
357 /* row+1, col-1 */
358 temp_row = row + 1; temp_col = col - 1;
359 if (isvalid_move(side, row, col, temp_row, temp_col) && !ischeck(side, temp_row, temp_col) && temp_row >=0 && temp_row < ROW_SIZE && temp_col >=0 && temp_col < ROW_SIZE ){
360 return 1;
361 }
362 getch();
363 return 0;
364}
diff --git a/chess.h b/chess.h
new file mode 100644
index 0000000..123f2a7
--- /dev/null
+++ b/chess.h
@@ -0,0 +1,39 @@
1#include <stdio.h>
2#include <ctype.h>
3#include <stdlib.h>
4#include <ncurses.h>
5
6#define A 0
7#define B 1
8#define C 2
9#define D 3
10#define E 4
11#define F 5
12#define G 6
13#define H 7
14
15#define ROW_SIZE 8
16
17#define NO_CHECK 0
18#define IN_CHECK 1
19
20/* Pieces */
21#define WHITE 1
22#define BLACK 2
23/* For easy identification, pieces of the same type will be congruent mod 10
24 If the piece is less than 10, it is white, if it is greater than 10 it is black */
25
26#define WHITE_PAWN 1
27#define WHITE_ROOK 2
28#define WHITE_KNIGHT 3
29#define WHITE_BISHOP 4
30#define WHITE_QUEEN 5
31#define WHITE_KING 6
32
33#define BLACK_PAWN 11
34#define BLACK_ROOK 12
35#define BLACK_KNIGHT 13
36#define BLACK_BISHOP 14
37#define BLACK_QUEEN 15
38#define BLACK_KING 16
39
diff --git a/computer_player.c b/computer_player.c
new file mode 100644
index 0000000..06dc3fa
--- /dev/null
+++ b/computer_player.c
@@ -0,0 +1,49 @@
1#include "chess.h"
2#include <stdlib.h>
3
4extern int board[ROW_SIZE][ROW_SIZE];
5extern int white_king_row;
6extern int white_king_col;
7extern int black_king_row;
8extern int black_king_col;
9extern int check;
10
11int isvalid_move(int side, int old_row, int new_row, int old_col, int new_col);
12int ischeck(int side, int row, int col);
13void find_kings();
14
15int side = BLACK;
16
17void computer_move() {
18 int valid = 0;
19 while (!valid) {
20 int start_row = random() % 7;
21 int start_col = random() % 7;
22 int end_row = random() % 7;
23 int end_col = random() % 7;
24
25 if (isvalid_move(BLACK, start_row, start_col, end_row, end_col)) {
26 int piece = board[start_row][start_col];
27 int dest_piece = board[end_row][end_col];
28 board[start_row][start_col] = 0;
29 board[end_row][end_col] = piece;
30
31 find_kings();
32 /* If the move results in the side's king being in check, its invalid */
33 if (side == WHITE && ischeck(side, white_king_row, white_king_col)) {
34 /* undo the move and reprompt */
35 board[start_row][start_col] = piece;
36 board[end_row][end_col] = dest_piece;
37 }
38 else if (side == BLACK && ischeck(side, black_king_row, black_king_col)) {
39 board[start_row][start_col] = piece;
40 board[end_row][end_col] = dest_piece;
41 }
42 else {
43 check = NO_CHECK; /* If move is valid, then there is no check */
44 valid = 1;
45 //check_capture(side, command[2], command[3]);
46 }
47 }
48 }
49}
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..1a25217
--- /dev/null
+++ b/main.c
@@ -0,0 +1,200 @@
1#include "chess.h"
2#include <ncurses.h>
3
4/* 8x8, letters are columns, numbers are rows
5 queen goes on left of king */
6
7/* Terminal Chess */
8
9
10int board[ROW_SIZE][ROW_SIZE] = {
11 {WHITE_ROOK, WHITE_KNIGHT, WHITE_BISHOP, WHITE_QUEEN, WHITE_KING, WHITE_BISHOP, WHITE_KNIGHT, WHITE_ROOK},
12 {WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN, WHITE_PAWN},
13 {},
14 {},
15 {},
16 {},
17 {BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN, BLACK_PAWN},
18 {BLACK_ROOK, BLACK_KNIGHT, BLACK_BISHOP, BLACK_QUEEN, BLACK_KING, BLACK_BISHOP, BLACK_KNIGHT, BLACK_ROOK},
19};
20int white_captured[16]; /* Black pieces that white has captured */
21int num_white_cap = 0; /* Number of black pieces white has captured */
22int black_captured[16]; /* White pieces that black has captured */
23int num_black_cap = 0; /* Number of white pieces black has captured */
24
25int white_king_row = 0; /* Location of the white king */
26int white_king_col = 4;
27
28int black_king_row = 7; /* Location of the black king */
29int black_king_col = 4;
30
31int check = NO_CHECK;
32
33void print_board(void);
34void move_piece(int side);
35void find_kings();
36
37int isvalid_move(int side, int old_row, int new_row, int old_col, int new_col);
38int isblocked(int piece, int old_row, int new_row, int old_col, int new_col);
39int ischeck(int side, int row, int col);
40int ischeck_mate(int side, int row, int col);
41int get_color(int piece);
42void check_capture(int side, int row, int col);
43void castle(int side);
44
45int get_input();
46int screen_display();
47int screen_refresh();
48int screen_close();
49int get_move(int move[4], int side);
50void display_check(int side);
51void display_win(int side);
52WINDOW *inputwin;
53
54int computer_move();
55
56
57int main() {
58 screen_display();
59 inputwin = newwin(1, 50, 45, 0);
60 while (1) {
61 screen_refresh();
62 move_piece(WHITE);
63 find_kings();
64
65 if (ischeck(BLACK, black_king_row, black_king_col)) {
66 if (ischeck_mate(BLACK, black_king_row, black_king_col)) {
67 screen_refresh();
68 display_win(WHITE);
69 break;
70 }
71 else {
72 display_check(BLACK);
73 check = IN_CHECK;
74 }
75 }
76
77 screen_refresh();
78 // computer_move();
79 move_piece(BLACK);
80 find_kings();
81
82 if (ischeck(WHITE, white_king_row, white_king_col)) {
83 if (ischeck_mate(WHITE, white_king_row, white_king_col)) {
84 screen_refresh();
85 display_win(BLACK);
86 break;
87 }
88 else {
89 display_check(WHITE);
90 check = IN_CHECK;
91 }
92 }
93 }
94 getch();
95 screen_close();
96 return 0;
97}
98
99/* Finds and updates the locations on the board of each side's king */
100void find_kings() {
101 for (int row = 0; row < ROW_SIZE; row++) {
102 for (int col = 0; col < ROW_SIZE; col++) {
103 if (board[row][col] == 6) {
104 white_king_row = row;
105 white_king_col = col;
106 }
107 else if (board[row][col] == 16) {
108 black_king_row = row;
109 black_king_col = col;
110 }
111 }
112 }
113}
114
115/* Gets an input from the user as to what piece to move and where to move it to and makes the move once a valid one is selected */
116void move_piece(int side) {
117 /* Get piece and destination from user*/
118 int valid = 0;
119 while (!valid) {
120 int move[4];
121 get_move(move, side);
122 int start_row = move[0];
123 int start_col = move[1];
124 int end_row = move[2];
125 int end_col = move[3];
126
127 int v;
128 if ((v = isvalid_move(side, start_row, start_col, end_row, end_col))) {
129
130 if (v == 2) {
131 castle(side);
132 break;
133 }
134
135 int piece = board[start_row][start_col];
136 int dest_piece = board[end_row][end_col];
137 board[start_row][start_col] = 0;
138 board[end_row][end_col] = piece;
139
140 find_kings();
141 /* If the move results in the side's king being in check, its invalid */
142 if (side == WHITE && ischeck(side, white_king_row, white_king_col)) {
143 /* undo the move and reprompt */
144 board[start_row][start_col] = piece;
145 board[end_row][end_col] = dest_piece;
146 }
147 else if (side == BLACK && ischeck(side, black_king_row, black_king_col)) {
148 board[start_row][start_col] = piece;
149 board[end_row][end_col] = dest_piece;
150 }
151 else {
152 check = NO_CHECK; /* If move is valid, then there is no check */
153 valid = 1;
154 //check_capture(side, command[2], command[3]);
155 }
156 }
157
158 }
159}
160
161void castle(int side) {
162 switch (side) {
163 case WHITE:
164 board[0][4] = 0;
165 board[0][7] = 0;
166 board[0][6] = WHITE_KING;
167 board[0][5] = WHITE_ROOK;
168 break;
169 case BLACK:
170 board[7][4] = 0;
171 board[7][7] = 0;
172 board[7][6] = BLACK_KING;
173 board[7][5] = BLACK_ROOK;
174 break;
175 }
176}
177
178void check_capture(int side, int row, int col) {
179 /* If there is a piece on the given square, it is assured
180 to be an opponent piece as otherwise validity checking would have failed */
181 int piece;
182 if (board[row][col] > 0) {
183 piece = board[row][col];
184 switch (side) {
185 case WHITE:
186 white_captured[num_white_cap++] = piece;
187 break;
188 case BLACK:
189 black_captured[num_black_cap++] = piece;
190 break;
191 }
192 }
193}
194
195/* Returns which color the piece belongs to */
196int get_color(int piece) {
197 if (piece <= 0)
198 return -1;
199 return (piece < 10) ? WHITE : BLACK;
200}
diff --git a/ncurses.c b/ncurses.c
new file mode 100644
index 0000000..57047b9
--- /dev/null
+++ b/ncurses.c
@@ -0,0 +1,342 @@
1#include <ncurses.h>
2#include "chess.h"
3
4#define WHITE_SQUARE 1
5#define BLACK_SQUARE 2
6
7int current_square = BLACK_SQUARE;
8
9WINDOW *windows[ROW_SIZE][ROW_SIZE];
10WINDOW *currentwin;
11WINDOW *white_statuswin;
12WINDOW *black_statuswin;
13
14int current_y = 0;
15int current_x = 0;
16
17int ws = 0;
18
19extern int board[ROW_SIZE][ROW_SIZE];
20
21void get_piece(int piece, WINDOW *win) {
22 switch (piece) {
23 case 0:
24 mvwprintw(win, 1, 1, " ");
25 mvwprintw(win, 2, 1, " ");
26 mvwprintw(win, 3, 1, " ");
27 wmove(win, 2, 3);
28 break;
29 case 1:
30 mvwprintw(win, 1, 1, " ");
31 mvwprintw(win, 2, 1, " WP ");
32 mvwprintw(win, 3, 1, " ");
33 break;
34 case 2:
35 mvwprintw(win, 1, 1, " ");
36 mvwprintw(win, 2, 1, " WR ");
37 mvwprintw(win, 3, 1, " ");
38 break;
39 case 3:
40 mvwprintw(win, 1, 1, " ");
41 mvwprintw(win, 2, 1, " WN ");
42 mvwprintw(win, 3, 1, " ");
43 break;
44 case 4:
45 mvwprintw(win, 1, 1, " ");
46 mvwprintw(win, 2, 1, " WB ");
47 mvwprintw(win, 3, 1, " ");
48 break;
49 case 5:
50 mvwprintw(win, 1, 1, " ");
51 mvwprintw(win, 2, 1, " WQ ");
52 mvwprintw(win, 3, 1, " ");
53 break;
54 case 6:
55 mvwprintw(win, 1, 1, " ");
56 mvwprintw(win, 2, 1, " WK ");
57 mvwprintw(win, 3, 1, " ");
58 break;
59
60 case 11:
61 mvwprintw(win, 1, 1, " ");
62 mvwprintw(win, 2, 1, " BP ");
63 mvwprintw(win, 3, 1, " ");
64 break;
65 case 12:
66 mvwprintw(win, 1, 1, " ");
67 mvwprintw(win, 2, 1, " BR ");
68 mvwprintw(win, 3, 1, " ");
69 break;
70 case 13:
71 mvwprintw(win, 1, 1, " ");
72 mvwprintw(win, 2, 1, " BN ");
73 mvwprintw(win, 3, 1, " ");
74 break;
75 case 14:
76 mvwprintw(win, 1, 1, " ");
77 mvwprintw(win, 2, 1, " BB ");
78 mvwprintw(win, 3, 1, " ");
79 break;
80 case 15:
81 mvwprintw(win, 1, 1, " ");
82 mvwprintw(win, 2, 1, " BQ ");
83 mvwprintw(win, 3, 1, " ");
84 break;
85 case 16:
86 mvwprintw(win, 1, 1, " ");
87 mvwprintw(win, 2, 1, " BK ");
88 mvwprintw(win, 3, 1, " ");
89 break;
90 }
91}
92
93/* Print the board to standard output */
94void print_board(void) {
95 int row = 8;
96 for (int i = 0; i < ROW_SIZE; i++, row--) {
97 for (int j = 0; j < ROW_SIZE; j++) {
98 WINDOW *win = newwin(5, 8, i*5, j*8 + 4);
99 windows[row-1][j] = win;
100 refresh();
101 switch (i % 2) {
102 case 0:
103 if (ws % 2 == 0)
104 wattron(win, COLOR_PAIR(2));
105 else
106 wattron(win, COLOR_PAIR(1));
107 break;
108 case 1:
109 if (ws % 2 == 0)
110 wattron(win, COLOR_PAIR(1));
111 else
112 wattron(win, COLOR_PAIR(2));
113 break;
114 }
115 ws++;
116 box(win, 0, 0);
117 get_piece(board[row-1][j], win);
118 wrefresh(win);
119 }
120 }
121 white_statuswin = newwin(5, 50, 35, 70);
122 black_statuswin = newwin(5, 50, 0, 70);
123 refresh();
124
125 box(white_statuswin, 0, 0);
126 box(black_statuswin, 0, 0);
127
128 mvwprintw(white_statuswin, 2, 1, "White");
129 mvwprintw(black_statuswin, 2, 1, "Black");
130
131 wrefresh(white_statuswin);
132 wrefresh(black_statuswin);
133}
134
135void highlight_side(int side) {
136 switch (side) {
137 case WHITE:
138 wattron(white_statuswin, A_REVERSE);
139 mvwprintw(white_statuswin, 2, 1, "White");
140 wattroff(white_statuswin, A_REVERSE);
141 mvwprintw(black_statuswin, 2, 1, "Black");
142 wrefresh(white_statuswin);
143 wrefresh(black_statuswin);
144 break;
145 case BLACK:
146 wattron(black_statuswin, A_REVERSE);
147 mvwprintw(black_statuswin, 2, 1, "Black");
148 wattroff(black_statuswin, A_REVERSE);
149 mvwprintw(white_statuswin, 2, 1, "White");
150 wrefresh(white_statuswin);
151 wrefresh(black_statuswin);
152 break;
153 }
154}
155
156
157/* Gets a move from the player */
158void get_move(int move[4], int side) {
159
160 highlight_side(side);
161
162 WINDOW *hlightwin;
163 int c, start_row, start_col, end_row, end_col, select_start, select_dest, keep_hlight, hlight_y, hlight_x;
164 c = start_row = start_col = end_row = end_col = select_start = select_dest = keep_hlight = hlight_y = hlight_x = 0;
165
166 switch (side) {
167 case WHITE:
168 current_y = 0;
169 current_x = 4;
170 currentwin = windows[0][4];
171 move(0, 0);
172 refresh();
173 break;
174 case BLACK:
175 current_y = 7;
176 current_x = 4;
177 currentwin = windows[7][4];
178 break;
179 }
180
181 while ((c = getch()) != EOF) {
182 switch (c) {
183 case 'h':
184 current_x -= 1;
185 if (current_x < 0) {
186 current_x = 0;
187 }
188 break;
189 case 'j':
190 current_y -= 1;
191 if (current_y < 0) {
192 current_y = 0;
193 }
194 break;
195 case 'k':
196 current_y += 1;
197 if (current_y > 7) {
198 current_y = 7;
199 }
200 break;
201 case 'l':
202 current_x += 1;
203 if (current_x > 7) {
204 current_x = 7;
205 }
206 break;
207 case 'H': case '0':
208 current_x = 0;
209 break;
210 case 'J': case 'G':
211 current_y = 0;
212 break;
213 case 'K': case 'g':
214 current_y = 7;
215 break;
216 case 'L': case '$':
217 current_x = 7;
218 break;
219 case '\n': case ' ':
220 switch (select_start) {
221 case 0:
222 select_start = 1;
223 keep_hlight = 1;
224 start_row = current_y;
225 start_col = current_x;
226 break;
227 case 1:
228 select_dest = 1;
229 end_row = current_y;
230 end_col = current_x;
231 break;
232 }
233 break;
234 case 'u':
235 if (select_start) {
236 select_start = 0;
237 start_row = start_col = 0;
238 get_piece(board[hlight_y][hlight_x], hlightwin);
239 wrefresh(hlightwin);
240 wmove(currentwin, 2, 3);
241 wrefresh(currentwin);
242 break;
243 }
244 }
245
246 /* Refresh the window before updating currentwin to show the normal piece in the previous square */
247 wrefresh(currentwin);
248 /* Apply screen effects to new square */
249 currentwin = windows[current_y][current_x];
250 wattron(currentwin, A_STANDOUT);
251 get_piece(board[current_y][current_x], currentwin);
252 wattroff(currentwin, A_STANDOUT);
253 wrefresh(currentwin);
254 move(0, 0);
255
256 /* If the player has already selected a piece and returns to that square
257 enable keep_hlight so that the selected piece doesn't get 'unhighlighted'*/
258 if (select_start && hlight_y == current_y && hlight_x == current_x) {
259 keep_hlight = 1;
260 }
261 if (!keep_hlight) {
262 /* Print the current square again so it returns to normal in memory
263 but don't refresh the window so it stays hidden*/
264 get_piece(board[current_y][current_x], currentwin);
265 }
266 else {
267 keep_hlight = 0;
268 /* Save highlight window and board location to remove the highlight when finished */
269 hlightwin = currentwin;
270 hlight_y = current_y;
271 hlight_x = current_x;
272 }
273 if (select_dest) {
274 break;
275 }
276 }
277 /* Reprint the higlighted piece to clear the highlight */
278 get_piece(board[hlight_y][hlight_x], hlightwin);
279 wrefresh(hlightwin);
280 /* Move back to selected position (where you were before the above two lines) */
281 wmove(currentwin, 2, 3);
282 wrefresh(currentwin);
283 move[0] = start_row;
284 move[1] = start_col;
285 move[2] = end_row;
286 move[3] = end_col;
287}
288
289
290void display_check(int side) {
291 switch (side) {
292 case WHITE:
293 mvwprintw(white_statuswin, 2, 10, "Check");
294 wrefresh(white_statuswin);
295 break;
296 case BLACK:
297 mvwprintw(black_statuswin, 2, 10, "Check");
298 wrefresh(black_statuswin);
299 break;
300 }
301}
302
303void display_win(int side) {
304 switch (side) {
305 case WHITE:
306 mvwprintw(white_statuswin, 2, 10, "WIN!");
307 wrefresh(white_statuswin);
308 break;
309 case BLACK:
310 mvwprintw(black_statuswin, 2, 10, "WIN!");
311 wrefresh(black_statuswin);
312 break;
313 }
314}
315
316int screen_display() {
317 initscr();
318 noecho();
319 cbreak();
320 curs_set(0);
321 start_color();
322 use_default_colors();
323 //short int *deffg, *defbg;
324 //pair_content(0, deffg, defbg);
325 init_pair(1, COLOR_WHITE, COLOR_BLACK);
326 init_pair(2, COLOR_RED, COLOR_BLACK);
327 print_board();
328 currentwin = windows[0][0];
329 return 0;
330}
331
332int screen_refresh() {
333 int row = 8;
334 print_board();
335 refresh();
336 return 0;
337}
338
339int screen_close() {
340 endwin();
341 return 0;
342}
diff --git a/valid.c b/valid.c
new file mode 100644
index 0000000..3bfa98e
--- /dev/null
+++ b/valid.c
@@ -0,0 +1,254 @@
1#include "chess.h"
2int isvalid_move(int side, int old_row, int old_col, int new_row, int new_col);
3int isblocked(int piece, int old_row, int old_col, int new_row, int new_col);
4int ischeck(int side, int row, int col);
5int get_color(int piece);
6
7int white_king_moved = 0;
8int black_king_moved = 0;
9
10extern int board[ROW_SIZE][ROW_SIZE];
11
12/* Checks if the selected move is valid by the rules of chess */
13int isvalid_move(int side, int old_row, int old_col, int new_row, int new_col) {
14
15 /* If either the new row or new column is outside the dimensions of the board, invalid */
16 if (new_row < 0 || new_row > ROW_SIZE || new_col < 0 || new_col > ROW_SIZE) {
17 return 0;
18 }
19
20 int sp = board[old_row][old_col]; /* Piece chosen by player */
21 int dp = board[new_row][new_col]; /* Piece in destination square (may or may not be null) */
22 /* Invalid if the row or column is invalid, the chosen piece does not belong to the player,
23 the old square = dest square, or if there is a piece on the destination square that also belongs to the player*/
24 if (side != get_color(sp) || ((old_col == new_col) && (old_row == new_row)) || side == get_color(dp)){
25 return 0;
26 }
27 else if (isblocked(sp, old_row, old_col, new_row, new_col)) {
28 return 0;
29 }
30
31 switch (sp % 10) {
32 case 1: /* Pawn */
33 /* Valid if row = row + 1 for white, row = row -1 for black */
34 if (side == WHITE && new_row == old_row + 1 && new_col == old_col) {
35 break;
36 }
37 if (side == BLACK && new_row == old_row - 1 && new_col == old_col) {
38 break;
39 }
40 /*valid if abs(row-row) = 1 and abs(col-col) = 1 and piece on destination square is an opponent */
41 if (abs(old_row - new_row) == 1 && abs(old_col - new_col) == 1 && dp > 0) {
42 if ((side == WHITE && dp > 10 && new_row > old_row) || (side == BLACK && dp < 10 && new_row < old_row)) {
43 break;
44 }
45 }
46 /* Valid if abs(row-row) = 2 and col=col and destination square is empty */
47 if (abs(old_row - new_row) == 2 && old_col == new_col && dp == 0) {
48 if ((old_row == 1 && new_row == 3 && side == WHITE) || (old_row == 6 && new_row == 4 && side == BLACK )) {
49 break;
50 }
51 }
52 return 0;
53 case 2: /* Rook */
54 if (old_row != new_row && old_col != new_col)
55 return 0;
56 break;
57 case 3: /* Knight */
58 if (!((abs(old_row - new_row) == 2 && abs(old_col - new_col) == 1) || (abs(old_col - new_col) == 2 && abs(old_row - new_row) == 1)))
59 return 0;
60 break;
61 case 4: /* Bishop */
62 if (abs(old_row - new_row) != abs(old_col - new_col))
63 return 0;
64 break;
65 case 5: /* Queen */
66 if ((abs(old_row - new_row) != abs(old_col - new_col)) && ((old_row != new_row && old_col != new_col)))
67 return 0;
68 break;
69
70 case 6: /* King */
71 if (ischeck(side, new_row, new_col)) { /* Invalid if the move would put the king in check */
72 return 0;
73 }
74 else if (side == WHITE && sp == WHITE_KING && board[0][5] == 0 && board[0][6] == 0 && old_row == 0 && new_row == 0 && new_col == 6 && !white_king_moved) {
75 white_king_moved = 1;
76 return 2;
77 }
78 else if (side == BLACK && sp == BLACK_KING && board[7][5] == 0 && board[7][6] == 0 && old_row == 7 && new_row == 7 && new_col == 6 && !black_king_moved) {
79 black_king_moved = 1;
80 return 2;
81 }
82 else if (abs(new_col - old_col) > 1 || abs(new_row - old_row) > 1)
83 return 0;
84 switch (side) {
85 case WHITE:
86 white_king_moved = 1;
87 break;
88 case BLACK:
89 black_king_moved = 1;
90 break;
91 }
92 break;
93 }
94 return 1;
95}
96
97/* Returns whether or not the path to the destination is blocked by another piece, 1 for blocked, 0 for not-blocked */
98int isblocked(int piece, int start_row, int start_col, int end_row, int end_col) {
99 int diagonal = 0;
100 int horizontal = 0;
101 int vertical = 0;
102 /* Determine direction of travel */
103 if (start_row != end_row && start_col != end_col) {
104 diagonal = 1;
105 }
106 else if (start_row == end_row && start_col != end_col) {
107 horizontal = 1;
108 }
109 else if (start_row != end_row && start_col == end_col) {
110 vertical = 1;
111 }
112 /* Use direction to determine path based off of piece */
113 switch (piece % 10) {
114 case 1: /* Pawn */
115 /* If pawn isn't on starting row, no need to check because previous error checking
116 in isvalid_move() would have already determined if its path (the 1 square in-front) is occupied*/
117 if ((piece < 10 && start_row != 1) || (piece > 10 && start_row != 6)) {
118 break;
119 }
120 /* If the pawn is trying to move two spaces from its starting position, the only possible block
121 would be on the square directly in front of it */
122 else if (piece < 10 && board[start_row + 1][start_col] > 0) { /* If white, check row above */
123 return 1;
124 }
125 else if (piece > 10 && board[start_row - 1][start_col] > 0) { /* If black, check row below */
126 return 1;
127 }
128 break;
129 case 2: /* Rook */
130 if (horizontal && start_col < end_col) {
131 for (int i = start_col + 1; i < end_col; i++) {
132 if (board[start_row][i] > 0) {
133 return 1;
134 }
135 }
136 }
137 else if (horizontal && start_col > end_col) {
138 for (int i = start_col - 1; i > end_col; i--) {
139 if (board[start_row][i] > 0) {
140 return 1;
141 }
142 }
143 }
144 else if (vertical && start_row < end_row) {
145 for (int i = start_row + 1; i < end_row; i++) {
146 if (board[i][start_col] > 0) {
147 return 1;
148 }
149 }
150 }
151 else if (vertical && start_row > end_row) {
152 for (int i = start_row - 1; i > end_row; i--) {
153 if (board[i][start_col] > 0) {
154 return 1;
155 }
156 }
157 }
158 break;
159 case 3: /* Knight, a knight's path cannot be blocked */
160 break;
161 case 4: /* Bishop */
162 if (start_row > end_row && start_col > end_col) { /* If moving to the left and back */
163 for (int i = start_row - 1, j = start_col - 1; j > end_col; i--, j--) {
164 if (board[i][j] > 0) {
165 return 1;
166 }
167 }
168 }
169 else if (start_row < end_row && start_col > end_col) { /* If moving to the left and forward */
170 for (int i = start_row + 1, j = start_col - 1; j > end_col; i++, j--) {
171 if (board[i][j] > 0) {
172 return 1;
173 }
174 }
175 }
176 else if (start_row > end_row && start_col < end_col) { /* If moving to the right and back*/
177 for (int i = start_row - 1, j = start_col + 1; j < end_col; i--, j++) {
178 if (board[i][j] > 0) {
179 return 1;
180 }
181 }
182 }
183 else if (start_row < end_row && start_col < end_col) { /* If moving to the right and forward*/
184 for (int i = start_row + 1, j = start_col + 1; j < end_col; i++, j++) {
185 if (board[i][j] > 0) {
186 return 1;
187 }
188 }
189 }
190 break;
191 case 5: /* Queen */
192 /* Queen checks are just a mix of rook and bishop checks */
193 if (horizontal && start_col < end_col) {
194 for (int i = start_col + 1; i < end_col; i++) {
195 if (board[start_row][i] > 0) {
196 return 1;
197 }
198 }
199 }
200 else if (horizontal && start_col > end_col) {
201 for (int i = start_col - 1; i > end_col; i--) {
202 if (board[start_row][i] > 0) {
203 return 1;
204 }
205 }
206 }
207 else if (vertical && start_row < end_row) {
208 for (int i = start_row + 1; i < end_row; i++) {
209 if (board[i][start_col] > 0) {
210 return 1;
211 }
212 }
213 }
214 else if (vertical && start_row > end_row) {
215 for (int i = start_row - 1; i > end_row; i--) {
216 if (board[i][start_col] > 0) {
217 return 1;
218 }
219 }
220 }
221 else if (diagonal && start_row > end_row && start_col > end_col) { /* If moving to the left and back */
222 for (int i = start_row - 1, j = start_col - 1; j > end_col; i--, j--) {
223 if (board[i][j] > 0) {
224 return 1;
225 }
226 }
227 }
228 else if (diagonal && start_row < end_row && start_col > end_col) { /* If moving to the left and forward */
229 for (int i = start_row + 1, j = start_col - 1; j > end_col; i++, j--) {
230 if (board[i][j] > 0) {
231 return 1;
232 }
233 }
234 }
235 else if (diagonal && start_row > end_row && start_col < end_col) { /* If moving to the right and back*/
236 for (int i = start_row - 1, j = start_col + 1; j < end_col; i--, j++) {
237 if (board[i][j] > 0) {
238 return 1;
239 }
240 }
241 }
242 else if (diagonal && start_row < end_row && start_col < end_col) { /* If moving to the right and forward*/
243 for (int i = start_row + 1, j = start_col + 1; j < end_col; i++, j++) {
244 if (board[i][j] > 0) {
245 return 1;
246 }
247 }
248 }
249 case 6: /* King, king's path cannot be blocked as it can only move 1 square, so any blocks would be detected in isvalid_move()*/
250 break;
251 }
252 return 0;
253}
254