Posted By

ekampp on 03/09/11


Tagged

functions chess


Versions (?)

Who likes this?

1 person have marked this snippet as a favorite

Desoxena


Chess game


 / Published in: C++
 

Added a list of all the taken pieces.

  1. /*
  2.  * This is a small and simple chessgame to be played by two human players.
  3.  * Copyright 2011 Emil Kampp <[email protected]>
  4.  *
  5.  * TODO: Check for check- and mate situations.
  6.  *
  7.  */
  8.  
  9. #include "iostream"
  10. #include "fstream"
  11. #include "string"
  12. #include "vector"
  13. #include "math.h"
  14. #include "cstdlib"
  15. #include "sstream"
  16. using namespace std;
  17. using std::vector;
  18.  
  19. // Contains the current board
  20. int board[8][8];
  21.  
  22. // Contains a list of the pieces that has been taken out
  23. string taken_pieces = "";
  24.  
  25. // Reference ids for the pieces
  26. const int pawn = 1;
  27. const int rock = 2;
  28. const int knight = 3;
  29. const int bishop = 4;
  30. const int queen = 5;
  31. const int king = 6;
  32.  
  33. // Current state of the game
  34. int status = 0;
  35.  
  36. // Current state of the application
  37. int exit_game = 0;
  38.  
  39. // Current turn
  40. int current_player = 1;
  41.  
  42. // Number of played rounds in this game
  43. int turn_counter = 1;
  44.  
  45. /*
  46.  * Resets the board
  47.  *
  48.  * This takes no arguments and resets all the positions of the pieces to a
  49.  * prestine version of the game.
  50.  *
  51.  */
  52. void reset(){
  53. // Normal board setup
  54. board[0][0]=rock;
  55. board[0][1]=knight;
  56. board[0][2]=bishop;
  57. board[0][3]=queen;
  58. board[0][4]=king;
  59. board[0][5]=bishop;
  60. board[0][6]=knight;
  61. board[0][7]=rock;
  62. board[1][0]=pawn;
  63. board[1][1]=pawn;
  64. board[1][2]=pawn;
  65. board[1][3]=pawn;
  66. board[1][4]=pawn;
  67. board[1][5]=pawn;
  68. board[1][6]=pawn;
  69. board[1][7]=pawn;
  70. board[2][0]=0;
  71. board[2][1]=0;
  72. board[2][2]=0;
  73. board[2][3]=0;
  74. board[2][4]=0;
  75. board[2][5]=0;
  76. board[2][6]=0;
  77. board[2][7]=0;
  78. board[3][0]=0;
  79. board[3][1]=0;
  80. board[3][2]=0;
  81. board[3][3]=0;
  82. board[3][4]=0;
  83. board[3][5]=0;
  84. board[3][6]=0;
  85. board[3][7]=0;
  86. board[4][0]=0;
  87. board[4][1]=0;
  88. board[4][2]=0;
  89. board[4][3]=0;
  90. board[4][4]=0;
  91. board[4][5]=0;
  92. board[4][6]=0;
  93. board[4][7]=0;
  94. board[5][0]=0;
  95. board[5][1]=0;
  96. board[5][2]=0;
  97. board[5][3]=0;
  98. board[5][4]=0;
  99. board[5][5]=0;
  100. board[5][6]=0;
  101. board[5][7]=0;
  102. board[6][0]=-pawn;
  103. board[6][1]=-pawn;
  104. board[6][2]=-pawn;
  105. board[6][3]=-pawn;
  106. board[6][4]=-pawn;
  107. board[6][5]=-pawn;
  108. board[6][6]=-pawn;
  109. board[6][7]=-pawn;
  110. board[7][0]=-rock;
  111. board[7][1]=-knight;
  112. board[7][2]=-bishop;
  113. board[7][3]=-queen;
  114. board[7][4]=-king;
  115. board[7][5]=-bishop;
  116. board[7][6]=-knight;
  117. board[7][7]=-rock;
  118. current_player = 1;
  119. turn_counter = 1;
  120. status = 0;
  121. taken_pieces = "";
  122. }
  123.  
  124. /*
  125.  * Returns the +current_player+ integer for the opposite player
  126.  *
  127.  */
  128. int oppositePlayer(){
  129. if(current_player == 1) return 2;
  130. return 1;
  131. }
  132.  
  133. /*
  134.  * Returns the +current_player+ integer for the current player
  135.  *
  136.  */
  137. string currentPlayerColor(){
  138. if(current_player == 1) return "White";
  139. return "Black";
  140. }
  141.  
  142. /*
  143.  * Returns the color of the +current_player+
  144.  *
  145.  */
  146. string oppositePlayerColor(){
  147. if(current_player == 1) return "Black";
  148. return "White";
  149. }
  150.  
  151. /*
  152.  * Constructs a text-representation of the given +piece+.
  153.  *
  154.  * All whitespaces can be supressed with the +supress_blank+ option.
  155.  *
  156.  */
  157. string displayPiece(int piece=0, int supress_blank=0){
  158. string str = "";
  159. if(piece > 0){ // White piece
  160. if(supress_blank==1){
  161. switch(piece){
  162. case rock: str = "r"; break;
  163. case knight: str = "k"; break;
  164. case bishop: str = "b"; break;
  165. case queen: str = "Q"; break;
  166. case king: str = "K"; break;
  167. case pawn: str = "p"; break;
  168. }
  169. } else {
  170. switch(piece){
  171. case rock: str = " r "; break;
  172. case knight: str = " k "; break;
  173. case bishop: str = " b "; break;
  174. case queen: str = " Q "; break;
  175. case king: str = " K "; break;
  176. case pawn: str = " p "; break;
  177. }
  178. }
  179. } else {
  180. if(piece < 0) {
  181. switch(-piece){
  182. case rock: str = "(r)"; break;
  183. case knight: str = "(k)"; break;
  184. case bishop: str = "(b)"; break;
  185. case queen: str = "(Q)"; break;
  186. case king: str = "(K)"; break;
  187. case pawn: str = "(p)"; break;
  188. }
  189. } else {
  190. if(supress_blank == 1) return "";
  191. str = " ";
  192. }
  193. }
  194. return str;
  195. }
  196.  
  197. /*
  198.  * Generates a human readable list of all the pieces that has been taken
  199.  * during the game.
  200.  *
  201.  */
  202. string takenPiecesList(){
  203. string list = taken_pieces;
  204. if(list.length()==0) list = "N/A";
  205. return list;
  206. }
  207.  
  208. /*
  209.  * Ouputs a graphical represntation of the +board+ array to the CLI
  210.  *
  211.  */
  212. void displayBoard(){
  213. cout << "\n\n";
  214. cout << " a b c d e f g h\n";
  215. cout << " +-------------------------------+\n";
  216. for(size_t i = 0; i < 8; ++i){
  217. switch(i){
  218. case 0: cout << "1 "; break;
  219. case 1: cout << "2 "; break;
  220. case 2: cout << "3 "; break;
  221. case 3: cout << "4 "; break;
  222. case 4: cout << "5 "; break;
  223. case 5: cout << "6 "; break;
  224. case 6: cout << "7 "; break;
  225. case 7: cout << "8 "; break;
  226. }
  227. cout << "|";
  228. for(size_t j = 0; j < 8; ++j){
  229. cout << displayPiece(board[i][j]);
  230. cout << "|";
  231. if(j == 7) cout << "\n";
  232. }
  233. cout << " +-------------------------------+\n";
  234. }
  235. cout << "Taken pieces: " << takenPiecesList() << "\n";
  236. }
  237.  
  238. /*
  239.  * Checks if the given move is valid.
  240.  *
  241.  * The check is based on the originating coordinates and the targeted
  242.  * coordinates.
  243.  *
  244.  */
  245. int validMove(int ox, int oy, int dx, int dy){
  246. int source = board[oy][ox];
  247. int target = board[dy][dx];
  248. // cout << "Validating move for " << displayPiece(source) << "@" << ox << "," << oy
  249. // << " to " << target << "@" << dx << "," << dy << "\n";
  250. switch(abs(source)){
  251. //Pawn
  252. case 1: case -1:
  253. if(dx==ox && abs(dy-oy)==1 && target==0) return 1;
  254. if(abs(dx-ox)==1 && abs(dy-oy)==1 && target!= 0) return 1;
  255. if(current_player == 1 && oy==1 && abs(oy-dy)==2 && target == 0) return 1;
  256. if(current_player == 2 && oy==6 && abs(oy-dy)==2 && target == 0) return 1;
  257. // TODO: Check for en-passant
  258. break;
  259.  
  260. // Rock
  261. case 2:
  262. if(dx==ox){ // Moving vertically
  263. if(dy>oy){ // Downards
  264. for(size_t row = (unsigned)(oy+1); row < (unsigned)dy; ++row){
  265. if(board[row][dx] != 0) return 0;
  266. }
  267. } else { // Upwards
  268. for(size_t row = (unsigned)dy; row < (unsigned)(oy-1); ++row){
  269. if(board[row][dx] != 0) return 0;
  270. }
  271. }
  272. return 1;
  273. }
  274. if(dy==oy){ // Moving horizontally
  275. if(dx>ox){ // Rightwards
  276. for(size_t column = (unsigned)(ox+1); column < (unsigned)dy; ++column){
  277. if(board[dy][column] != 0) return 0;
  278. }
  279. }
  280. if(dx<ox){ // Leftwards
  281. for(size_t column = (unsigned)dx; column < (unsigned)(ox-1); ++column){
  282. if(board[dy][column] != 0) return 0;
  283. }
  284. }
  285. return 1;
  286. }
  287. return 0;
  288. break;
  289.  
  290. // Knight
  291. case 3:
  292. if((abs(dy-oy)==2 && abs(dx-ox)==1) || (abs(dx-ox)==2 && abs(dy-oy)==1)){
  293. return 1;
  294. }
  295. return 0;
  296. break;
  297.  
  298. // Bishop
  299. case 4:
  300. if(abs(dy-oy) == abs(dx-ox)){ // Moving diagonally
  301. if(dy>oy){ // South
  302. int column = min(dx, ox)+1;
  303. for(size_t row = oy+1; row < (unsigned)dy; ++row){
  304. if(board[row][column] != 0) return 0;
  305. column ++;
  306. }
  307. return 1;
  308. }
  309. if(dy<oy && dx>ox){ // North
  310. int column = min(dx, ox)+1;
  311. for(size_t row = oy+1; row < (unsigned)dy; ++row){
  312. if(board[row][column] != 0) return 0;
  313. column ++;
  314. }
  315. return 1;
  316. }
  317. }
  318. return 0;
  319. break;
  320.  
  321. // Queen
  322. case 5:
  323. if(abs(dy-oy) == abs(dx-ox)){ // Moving diagonally
  324. if(dy>oy){ // South
  325. int column = min(dx, ox)+1;
  326. for(size_t row = oy+1; row < (unsigned)dy; ++row){
  327. if(board[row][column] != 0) return 0;
  328. column ++;
  329. }
  330. return 1;
  331. }
  332. if(dy<oy && dx>ox){ // North
  333. int column = min(dx, ox)+1;
  334. for(size_t row = oy+1; row < (unsigned)dy; ++row){
  335. if(board[row][column] != 0) return 0;
  336. column ++;
  337. }
  338. return 1;
  339. }
  340. }
  341. if(dy==oy || dx==ox){ // Moving straight
  342. if(dx==ox){ // Moving vertically
  343. if(dy>oy){ // Downards
  344. for(size_t row = (unsigned)(oy+1); row < (unsigned)dy; ++row){
  345. if(board[row][dx] != 0) return 0;
  346. }
  347. } else { // Upwards
  348. for(size_t row = (unsigned)dy; row < (unsigned)(oy-1); ++row){
  349. if(board[row][dx] != 0) return 0;
  350. }
  351. }
  352. return 1;
  353. }
  354. if(dy==oy){ // Moving horizontally
  355. if(dx>ox){ // Rightwards
  356. for(size_t column = (unsigned)(ox+1); column < (unsigned)dy; ++column){
  357. if(board[dy][column] != 0) return 0;
  358. }
  359. }
  360. if(dx<ox){ // Leftwards
  361. for(size_t column = (unsigned)dx; column < (unsigned)(ox-1); ++column){
  362. if(board[dy][column] != 0) return 0;
  363. }
  364. }
  365. return 1;
  366. }
  367. }
  368. return 0;
  369. break;
  370.  
  371. // King
  372. case 6:
  373. if(abs(dy-oy)<=1 && abs(dx-ox)<=1) return 1;
  374. // TODO: Check for castling
  375. return 0;
  376. break;
  377. }
  378. return 0;
  379. }
  380.  
  381. /*
  382.  * Logs the given +piece+ into the +taken_pieces+ list.
  383.  *
  384.  */
  385. void logTakenPiece(int piece){
  386. string piece_str = displayPiece(piece, 1);
  387. if(piece_str.length()>0){
  388. if(taken_pieces.length()>0) taken_pieces=taken_pieces+",";
  389. taken_pieces=taken_pieces+displayPiece(piece);
  390. }
  391. }
  392.  
  393. /*
  394.  * Displays the help message
  395.  *
  396.  * TODO: Move the help message into the help.txt file.
  397.  *
  398.  */
  399. void displayHelp(){
  400. cout << "\n\n";
  401. cout << "When asked for a move, please enter a move in the following fasion: from>to. This means, that if you want to move from a1 to a2 then you should write a1>a2.\n";
  402. cout << "If you get the warning: Illegal move it means that you entered a move that's either impossible with the selected piece or you't trying to take one of your own pieces or you'r trying to move out of the board.\n";
  403. cout << "Typing reset will reset the game back to starting position. Typing display will redraw the board. Typing exit or quit will exit the game.\n";
  404. }
  405.  
  406. /*
  407.  * Gets a letter (a..h) from a number (1..8)
  408.  *
  409.  */
  410. string getLetter(int column){
  411. switch(column){
  412. case 0: return "a"; break;
  413. case 1: return "b"; break;
  414. case 2: return "c"; break;
  415. case 3: return "d"; break;
  416. case 4: return "e"; break;
  417. case 5: return "f"; break;
  418. case 6: return "g"; break;
  419. }
  420. return "n/a";
  421. }
  422.  
  423. /*
  424.  * Converts a given letter (a..h) into a corresponding number (1..8)
  425.  *
  426.  */
  427. int getNumber(string letter){
  428. if(letter == "a") return 0;
  429. if(letter == "b") return 1;
  430. if(letter == "c") return 2;
  431. if(letter == "d") return 3;
  432. if(letter == "e") return 4;
  433. if(letter == "f") return 5;
  434. if(letter == "g") return 6;
  435. if(letter == "h") return 7;
  436. return 0;
  437. }
  438.  
  439. /*
  440.  * Catches the users inputted move
  441.  *
  442.  * This also does some validation of the move..
  443.  * DISCUSS: Should all validation be moved somewhere else?
  444.  *
  445.  */
  446. int getMove(){
  447. cout << "Turn " << turn_counter << ". " << currentPlayerColor() <<", select a move:";
  448. string move = "";
  449. cin >> move;
  450.  
  451. // Checks if the move is a command
  452. if(move == "help"){ // Display help
  453. displayHelp();
  454. displayBoard();
  455. return 0;
  456. }
  457. if(move == "reset"){ // Reset the game
  458. reset(); displayBoard(); return 0;
  459. }
  460. if(move == "display"){ // Displays the board
  461. displayBoard(); return 0;
  462. }
  463. if(move == "exit" || move == "quit") exit(1);
  464.  
  465. // Splits the move into orgination and destrination and those
  466. // into x and y parts
  467. // TODO: Add validation of the y-coordinate of both the
  468. // destination and the origination.
  469. int ox = 0; int oy = 0; int dx = 0; int dy = 0;
  470. string ox_part = move.substr(0, move.find(">")).substr(0, 1);
  471. string oy_part = move.substr(0, move.find(">")).substr(1, 1);
  472. string dx_part = move.substr(move.find(">")+1, move.length()).substr(0, 1);
  473. string dy_part = move.substr(move.find(">")+1, move.length()).substr(1, 1);
  474. ox = getNumber(ox_part);
  475. oy = atoi(oy_part.c_str())-1;
  476. dx = getNumber(dx_part);
  477. dy = atoi(dy_part.c_str())-1;
  478.  
  479. // Gets the piece in question and moves it
  480. int source = board[oy][ox];
  481. int target = board[dy][dx];
  482. if((current_player == 1 && (source <= 0 || target > 0)) || (current_player == 2 && (source >= 0 || target < 0)) || !validMove(ox, oy, dx, dy)){
  483. cout << "Illegal move\n"; return 0;
  484. }
  485.  
  486. // Moves the piece
  487. board[oy][ox] = 0;
  488. board[dy][dx] = source;
  489. logTakenPiece(target);
  490.  
  491. // Checks for win condition
  492. // Changes the +status+ for the game to the +current_player+
  493. if(abs(target) == king){
  494. status = current_player;
  495. return 0;
  496. }
  497.  
  498. // Increments the +turn_counter+
  499. turn_counter ++;
  500.  
  501. // Changes the turn
  502. current_player = oppositePlayer();
  503.  
  504. // Redraws the board
  505. displayBoard();
  506.  
  507. return 0;
  508. }
  509.  
  510. /*
  511.  * Displays the about.txt file content
  512.  *
  513.  * TODO: Add the about.txt file
  514.  *
  515.  */
  516. void displayGameInformation(){
  517. cout << "This is a game os chess to be played between to humans. To get help with movements and such, type 'help'.\n";
  518. }
  519.  
  520. /*
  521.  * Initializes the program and contains the main loop that keeps the game
  522.  * alive.
  523.  *
  524.  */
  525. int main(){
  526. displayGameInformation();
  527. reset();
  528. displayBoard();
  529.  
  530. while(exit_game == 0){
  531. while(status == 0){
  532. getMove();
  533. }
  534.  
  535. // Displays win condition
  536. cout << currentPlayerColor() << " wins! Start a new game? [y/n]:";
  537. string new_game = "y";
  538. cin >> new_game;
  539. if(new_game == "y"){
  540. reset();
  541. displayBoard();
  542. } else {
  543. exit_game = 1;
  544. }
  545. }
  546.  
  547. cout << "Thank you for playing.\n";
  548. return 0;
  549. }

Report this snippet  

You need to login to post a comment.