(* chess board *) newgraph (* files *) xaxis min 0.5 max 8.5 no_draw_axis no_grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 1 : A hash_label at 2 : B hash_label at 3 : C hash_label at 4 : D hash_label at 5 : E hash_label at 6 : F hash_label at 7 : G hash_label at 8 : H (* ranks *) yaxis min 0.5 max 8.5 no_draw_axis no_grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 1 : 1 hash_label at 2 : 2 hash_label at 3 : 3 hash_label at 4 : 4 hash_label at 5 : 5 hash_label at 6 : 6 hash_label at 7 : 7 hash_label at 8 : 8 (* dark squares *) shell : echo "" | awk '{\ for (rank = 1; rank <= 8; rank++) { \ if (rank % 2 == 0) file = 2; \ else file = 1; \ for (; file <= 8; file += 2) { \ printf("newline poly gray 1 ppattern estripe 45 pfill .7 pts "); \ printf("%f %f %f %f %f %f %f %f\n", \ file - .5, rank - .5, \ file + .5, rank - .5, \ file + .5, rank + .5, \ file - .5, rank + .5); \ } \ } \ }' (* border *) newline pts 0.5 0.5 0.5 8.5 8.5 8.5 8.5 0.5 0.5 0.5 |
Notice how I automatically generated the dark squares instead of laboriously brute forcing each square. Because jgraph allows you to execute a sh command using the ``shell'' keyword, we can create all of our squares via another language and embed this in our jgraph code for readability. I chose to create the dark squares using awk (see Dr. Plank's Awk Lecture). I like awk because it reads like C, but you can use whatever language you want to get the job done. I use this same technique to generate chess pieces (see section Creating Chess Pieces).
Also, to make things simpler, I chose to have each square be a 1 x 1 square with the xaxis and yaxis going from 0.5 to 8.5. This will allow us later to specify piece placement by putting them on their exact row and column. This makes writing a program to generate piece locations easier.
(* white chess pawn *) newgraph xaxis min 0 max 10 nodraw yaxis min 0 max 10 nodraw (* pawn base *) newline bezier poly pfill 1 linethickness 10 pts 0 0 2.5 0 7.5 0 10 0 10 2 8 2 6 4 5.5 4 4.5 4 4 4 2 2 0 2 0 0 (* pawn center circle *) newline poly pfill 1 linethickness 10 pts shell : echo "" | awk '{ \ pi = atan2(0, -1); \ for (i = 0; i <= 360; i += 1) { \ printf(" %f %f",2*sin(i*pi/180)+5,2*cos(i*pi/180)+6); \ } printf("\n") }' (* pawn top circle *) newline poly pfill 1 linethickness 10 pts shell : echo "" | awk '{ \ pi = atan2(0, -1); \ for (i = 0; i <= 360; i += 1) { \ printf(" %f %f",1*sin(i*pi/180)+5,1*cos(i*pi/180)+9); \ } printf("\n") }' |
Above is a white chess pawn. This white pawn is made up of three simple elements: the base, the center circle, the top circle. The base can be described as a jgraph bezier polygon. You will notice there are straight lines in this polygon. I just specify a straight line by putting the two bezier control points collinearly between the endpoints. I fill the polygon with white (pfill 1) so that when the piece is on a dark square we do not see the square background in the middle of the piece. After we have the base, the head of the pawn is two circles. While I could have worked out each individual point along the circles, it is much easier to let awk do the work for us.
We can easily alter the white pawn to be a black pawn by changing the pfill to 0 of each of the three polygons. The black pawn looks as follows:
(* black chess pawn *) newgraph xaxis min 0 max 10 nodraw yaxis min 0 max 10 nodraw (* pawn base *) newline bezier poly pfill 0 linethickness 10 pts 0 0 2.5 0 7.5 0 10 0 10 2 8 2 6 4 5.5 4 4.5 4 4 4 2 2 0 2 0 0 (* pawn center circle *) newline poly pfill 0 linethickness 10 pts shell : echo "" | awk '{ \ pi = atan2(0, -1); \ for (i = 0; i <= 360; i += 1) { \ printf(" %f %f",2*sin(i*pi/180)+5,2*cos(i*pi/180)+6); \ } printf("\n") }' (* pawn top circle *) newline poly pfill 0 linethickness 10 pts shell : echo "" | awk '{ \ pi = atan2(0, -1); \ for (i = 0; i <= 360; i += 1) { \ printf(" %f %f",1*sin(i*pi/180)+5,1*cos(i*pi/180)+9); \ } printf("\n") }' |
All of the other chess pieces were generated in a similar manner. The images of the resulting pieces are below.
White Pieces | Black Pieces | |
---|---|---|
Pawn | ||
Bishop | ||
Knight | ||
Rook | ||
Queen | ||
King |
(* chess board *) newgraph xaxis min 0 max 80 hash 10 mhash 0 grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 5 : A hash_label at 15 : B hash_label at 25 : C hash_label at 35 : D hash_label at 45 : E hash_label at 55 : F hash_label at 65 : G hash_label at 75 : H yaxis min 0 max 80 hash 10 mhash 0 grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 5 : 1 hash_label at 15 : 2 hash_label at 25 : 3 hash_label at 35 : 4 hash_label at 45 : 5 hash_label at 55 : 6 hash_label at 65 : 7 hash_label at 75 : 8 (* print dark square background *) shell : echo "" | awk '{ \ for (rank = 0; rank < 8; rank++) { \ if (rank % 2 == 0) file = 0; \ else file = 1; \ for (; file < 8; file += 2) { \ printf("newline poly ppattern estripe 45 pfill .8 pts ");\ printf("%d %d %d %d %d %d %d %d\n",\ file * 10, rank * 10, \ file * 10 + 10, rank * 10, \ file * 10 + 10, rank * 10 + 10, \ file * 10, rank * 10 + 10); \ } \ } \ }' newcurve eps ps_pieces/r.ps marksize 8 8 pts 5 75 newcurve eps ps_pieces/n.ps marksize 8 8 pts 15 75 newcurve eps ps_pieces/b.ps marksize 8 8 pts 25 75 newcurve eps ps_pieces/q.ps marksize 8 8 pts 35 75 newcurve eps ps_pieces/k.ps marksize 8 8 pts 45 75 newcurve eps ps_pieces/b.ps marksize 8 8 pts 55 75 newcurve eps ps_pieces/n.ps marksize 8 8 pts 65 75 newcurve eps ps_pieces/r.ps marksize 8 8 pts 75 75 newcurve eps ps_pieces/p.ps marksize 8 8 pts 5 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 15 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 25 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 35 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 45 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 55 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 65 65 newcurve eps ps_pieces/p.ps marksize 8 8 pts 75 65 newcurve eps ps_pieces/P.ps marksize 8 8 pts 5 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 15 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 25 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 35 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 45 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 55 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 65 15 newcurve eps ps_pieces/P.ps marksize 8 8 pts 75 15 newcurve eps ps_pieces/R.ps marksize 8 8 pts 5 5 newcurve eps ps_pieces/N.ps marksize 8 8 pts 15 5 newcurve eps ps_pieces/B.ps marksize 8 8 pts 25 5 newcurve eps ps_pieces/Q.ps marksize 8 8 pts 35 5 newcurve eps ps_pieces/K.ps marksize 8 8 pts 45 5 newcurve eps ps_pieces/B.ps marksize 8 8 pts 55 5 newcurve eps ps_pieces/N.ps marksize 8 8 pts 65 5 newcurve eps ps_pieces/R.ps marksize 8 8 pts 75 5 |
The jgraph board code is exactly the same as the empty board shown previously; we just have to specify where we would like to place the pieces. For example, the white king is specified by the following code:
newcurve eps ps_pieces/K.ps marksize 8 8 pts 45 5
While typing this everytime works, it can be quite tedious to try and calculate the location of where you want to place each piece, especially when most all the pieces are left on the board. We probably want a more intuitive way to specify piece locations.In chess there are several different formats one can use to specify a particular board and/or the current state of the game. The International Chess Federation (FIDE) requires players to write down their moves using standard algebraic notation. Another common notation is the Forsyth-Edwards Notation (FEN), which describes the current state of a game. As an example here, we will use a format similar to the GNU Chess (https://www.gnu.org/software/chess/) board output in terminal mode.
The format goes like this. Each square's state is specified by a character. Below is a chart of all the possible square states and their corresponding character representation.
Character | Square State |
---|---|
. | empty square |
P | white pawn on square |
B | white bishop on square |
N | white knight on square |
R | white rook on square |
K | white king on square |
Q | white queen on square |
p | black pawn on square |
b | black bishop on square |
n | black knight on square |
r | black rook on square |
k | black king on square |
q | black queen on square |
Each row of the board is specified by eight of the above characters and is terminated by a newline. The board is specified from the white player's perspective. For example, the initial board would be specified by the following:
rnbqkbnr pppppppp ........ ........ ........ ........ PPPPPPPP RNBQKBNR |
This representation will make it much easier to specify a particular board. We now need a way of converting this representation to a jgraph chess board with the pieces located in their corresponding positions. I have written a C program (gen_chessboard.c), which will translate the board for us.
Let's say we want to specify Fischer versus Spassky, Game 6 of the 1972 World Chess Championship, widely known as the Match of the Century, taking place during the Cold War. The final board of the game is in the file example_boards/fischer_spassky_game6_1972.txt and shown below:
....q..k ..r.r... ....PR.p p.p..... P.Bp...P .P...... ......P. ......K. |
We want to convert this to a jgraph board. We can use our C program gen_chessboard. It can read the board directly off of stdin. In order to generate the board, we could run the following:
UNIX> cat example_boards/fischer_spassky_game6_1972.txt | ./gen_chessboard >fischer_spassky_game6_1972.jgrUNIX> cat fischer_spassky_game6_1972.jgr (* chess board *) newgraph xaxis min 0 max 80 hash 10 mhash 0 grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 5 : A hash_label at 15 : B hash_label at 25 : C hash_label at 35 : D hash_label at 45 : E hash_label at 55 : F hash_label at 65 : G hash_label at 75 : H yaxis min 0 max 80 hash 10 mhash 0 grid_lines no_draw_hash_marks no_auto_hash_labels hash_label at 5 : 1 hash_label at 15 : 2 hash_label at 25 : 3 hash_label at 35 : 4 hash_label at 45 : 5 hash_label at 55 : 6 hash_label at 65 : 7 hash_label at 75 : 8 (* print dark square background *) shell : echo "" | awk '{ \ for (rank = 0; rank < 8; rank++) { \ if (rank % 2 == 0) file = 0; \ else file = 1; \ for (; file < 8; file += 2) { \ printf("newline poly ppattern estripe 45 pfill .8 pts ");\ printf("%d %d %d %d %d %d %d %d\n",\ file * 10, rank * 10, \ file * 10 + 10, rank * 10, \ file * 10 + 10, rank * 10 + 10, \ file * 10, rank * 10 + 10); \ } \ } \ }' newcurve eps ps_pieces/q.ps marksize 8 8 pts 45 75 newcurve eps ps_pieces/k.ps marksize 8 8 pts 75 75 newcurve eps ps_pieces/r.ps marksize 8 8 pts 25 65 newcurve eps ps_pieces/r.ps marksize 8 8 pts 45 65 newcurve eps ps_pieces/P.ps marksize 8 8 pts 45 55 newcurve eps ps_pieces/R.ps marksize 8 8 pts 55 55 newcurve eps ps_pieces/p.ps marksize 8 8 pts 75 55 newcurve eps ps_pieces/p.ps marksize 8 8 pts 5 45 newcurve eps ps_pieces/p.ps marksize 8 8 pts 25 45 newcurve eps ps_pieces/P.ps marksize 8 8 pts 5 35 newcurve eps ps_pieces/B.ps marksize 8 8 pts 25 35 newcurve eps ps_pieces/p.ps marksize 8 8 pts 35 35 newcurve eps ps_pieces/P.ps marksize 8 8 pts 75 35 newcurve eps ps_pieces/P.ps marksize 8 8 pts 15 25 newcurve eps ps_pieces/P.ps marksize 8 8 pts 65 15 newcurve eps ps_pieces/K.ps marksize 8 8 pts 65 5UNIX> jgraph fischer_spassky_game6_1972.jgr >fischer_spassky_game6_1972.psThe resulting board is below: