Introduction
Introduction Statistics Contact Development Disclaimer Help
initial repo - chess-puzzles - chess puzzle book generator
git clone git://git.codemadness.org/chess-puzzles
Log
Files
Refs
README
LICENSE
---
commit c8aed5b7783cae9c06f50dfcb5ab0af851edf54a
Author: Hiltjo Posthuma <[email protected]>
Date: Sun, 17 Dec 2023 21:17:57 +0100
initial repo
Diffstat:
A LICENSE | 15 +++++++++++++++
A Makefile | 11 +++++++++++
A README | 37 +++++++++++++++++++++++++++++…
A fen_to_ascii.c | 276 ++++++++++++++++++++++++++++++
A fen_to_svg.c | 287 +++++++++++++++++++++++++++++…
A generate.sh | 138 ++++++++++++++++++++++++++++++
6 files changed, 764 insertions(+), 0 deletions(-)
---
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2023 Hiltjo Posthuma <[email protected]>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,11 @@
+build: clean
+ ${CC} -o fen_to_svg fen_to_svg.c ${CFLAGS} ${LDFLAGS}
+ ${CC} -o fen_to_ascii fen_to_ascii.c ${CFLAGS} ${LDFLAGS}
+
+db:
+ rm -f lichess_db_puzzle.csv.zst lichess_db_puzzle.csv
+ curl -O 'https://database.lichess.org/lichess_db_puzzle.csv.zst'
+ zstd -d < lichess_db_puzzle.csv.zst > lichess_db_puzzle.csv
+
+clean:
+ rm -f fen_to_svg fen_to_ascii
diff --git a/README b/README
@@ -0,0 +1,37 @@
+chess puzzle book generator
+---------------------------
+
+This was a christmas hack for fun and non-profit.
+
+
+The generate.sh script generates puzzles.
+The puzzles used are from the lichess.org puzzle database.
+This database is a big CSV file.
+
+The generate index page is a HTML page, it lists the puzzles.
+Each puzzle is an SVG image.
+
+
+Files
+-----
+
+* generate.sh:
+ Read puzzles, shuffle them. Do some sorting based on difficulty and
+ assign score points.
+* fen_to_svg.c:
+ Read FEN and a few moves and generate an SVG image of the board.
+* fen_to_ascii.c:
+ Read FEN and a few moves and generate a text representation of the board.
+
+
+References
+----------
+
+* SVG of the pieces:
+ https://github.com/lichess-org/lila/tree/master/public/piece/cburnett
+
+* lichess FEN puzzle database
+ https://database.lichess.org/#puzzles
+
+* lichess.org
+ https://lichess.org/
diff --git a/fen_to_ascii.c b/fen_to_ascii.c
@@ -0,0 +1,276 @@
+/* TODO: option to flip board? */
+
+#include <stdio.h>
+#include <string.h>
+
+static char board[8][8];
+static char highlight[8][8];
+
+static int side_to_move = 'w'; /* default: white to move */
+static int white_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid…
+static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid…
+
+static const int showcoords = 1; /* config: show board coordinates? */
+
+int
+isvalidsquare(int x, int y)
+{
+ return !(x < 0 || x >= 8 || y < 0 || y >= 8);
+}
+
+/* place a piece, if possible */
+void
+place(int piece, int x, int y)
+{
+ if (!isvalidsquare(x, y))
+ return;
+
+ board[y][x] = piece;
+}
+
+/* get piece, if possible */
+int
+getpiece(int x, int y)
+{
+ if (!isvalidsquare(x, y))
+ return 0;
+ return board[y][x];
+}
+
+int
+squaretoxy(const char *s, int *x, int *y)
+{
+ if (*s >= 'a' && *s <= 'h' &&
+ *(s + 1) >= '1' && *(s + 1) <= '8') {
+ *x = *s - 'a';
+ *y = '8' - *(s + 1);
+ return 1;
+ }
+ return 0;
+}
+
+void
+highlightmove(int x1, int y1, int x2, int y2)
+{
+ if (isvalidsquare(x1, y1))
+ highlight[y1][x1] = 1;
+
+ if (isvalidsquare(x2, y2))
+ highlight[y2][x2] = 1;
+}
+
+void
+showpiece(int c)
+{
+ const char *s = "";
+
+ /* simple or use unicode character */
+#if 1
+ putchar(c);
+ return;
+#endif
+
+ switch (c) {
+ case 'K': s = "♔"; break;
+ case 'Q': s = "♕"; break;
+ case 'R': s = "♖"; break;
+ case 'B': s = "♗"; break;
+ case 'N': s = "♘"; break;
+ case 'P': s = "♙"; break;
+ case 'k': s = "♚"; break;
+ case 'q': s = "♛"; break;
+ case 'r': s = "♜"; break;
+ case 'b': s = "♝"; break;
+ case 'n': s = "♞"; break;
+ case 'p': s = "♟"; break;
+ }
+
+ if (*s)
+ fputs(s, stdout);
+}
+
+void
+showboardfen(void)
+{
+ int x, y, piece, skip = 0;
+
+ for (y = 0; y < 8; y++) {
+ if (y > 0)
+ putchar('/');
+ skip = 0;
+ for (x = 0; x < 8; x++) {
+ piece = getpiece(x, y);
+ if (piece) {
+ if (skip)
+ putchar(skip + '0');
+ putchar(piece);
+ skip = 0;
+ } else {
+ skip++;
+ }
+ }
+ if (skip)
+ putchar(skip + '0');
+ }
+
+ /* ? TODO: detect en passant, invalid castling etc? */
+}
+
+/* show board */
+/* TODO: show fancier, unicode and background square color */
+/* TODO: use the output format similar to stockfish "d" command */
+void
+showboard(void)
+{
+ int x, y, piece;
+
+ printf("Board FEN:\n");
+ showboardfen();
+ printf("\n\n");
+
+ for (y = 0; y < 8; y++) {
+ printf("+---+---+---+---+---+---+---+---+\n");
+ for (x = 0; x < 8; x++) {
+ if (x == 0)
+ putchar('|');
+ fputs(" ", stdout);
+ piece = getpiece(x, y);
+ if (piece)
+ showpiece(piece);
+ else
+ fputs(" ", stdout);
+ fputs(" ", stdout);
+ putchar('|');
+ }
+ if (showcoords) {
+ putchar(' ');
+ putchar('8' - y);
+ }
+ putchar('\n');
+ }
+ printf("+---+---+---+---+---+---+---+---+\n");
+ if (showcoords)
+ printf(" a | b | c | d | e | f | g | h |\n");
+
+ fputs("\n", stdout);
+
+#if 0
+ if (side_to_move == 'w') {
+ fputs("White to move\n", stdout);
+ } else if (side_to_move == 'b')
+ fputs("Black to move\n", stdout);
+
+ if (white_can_castle[0])
+ fputs("White can castle king side\n", stdout);
+ if (white_can_castle[1])
+ fputs("White can castle queen side\n", stdout);
+ if (black_can_castle[0])
+ fputs("Black can castle king side\n", stdout);
+ if (black_can_castle[1])
+ fputs("Black can castle queen side\n", stdout);
+#endif
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *fen, *moves, *s;
+ int x, y, x2, y2, field, piece;
+ char pieces[] = "PNBRQKpnbrqk", square[3];
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
+ return 1;
+ }
+
+ fen = argv[1];
+ moves = argv[2];
+
+ /* initial board state, FEN format */
+ x = y = field = 0;
+ for (s = fen; *s; s++) {
+ /* next field, fields are: piece placement data, active color,
+ Castling availability, En passant target square,
+ Halfmove clock, Fullmove number */
+ if (*s == ' ') {
+ field++;
+ continue;
+ }
+
+ switch (field) {
+ case 0: /* piece placement data */
+ /* skip square */
+ if (*s >= '1' && *s <= '9') {
+ x += (*s - '0');
+ continue;
+ }
+ /* next rank */
+ if (*s == '/') {
+ x = 0;
+ y++;
+ continue;
+ }
+ /* is piece? place it */
+ if (strchr(pieces, *s))
+ place(*s, x++, y);
+ break;
+ case 1: /* active color */
+ if (*s == 'w' || *s == 'b')
+ side_to_move = *s;
+ break;
+ case 2: /* castling availability */
+ if (*s == '-') {
+ white_can_castle[0] = 0;
+ white_can_castle[1] = 0;
+ black_can_castle[0] = 0;
+ black_can_castle[1] = 0;
+ } else if (*s == 'K') {
+ white_can_castle[0] = 1;
+ } else if (*s == 'Q') {
+ white_can_castle[1] = 1;
+ } else if (*s == 'k') {
+ black_can_castle[0] = 1;
+ } else if (*s == 'q') {
+ black_can_castle[1] = 1;
+ }
+ break;
+ case 3: /* TODO: en-passant square, rest of the fields */
+ break;
+ }
+ /* TODO: parse which side to move, en-passant, etc */
+ }
+
+ /* process moves */
+ square[2] = '\0';
+ x = y = x2 = y2 = -1;
+ for (s = moves; *s; s++) {
+ if (*s == ' ')
+ continue;
+ if ((*s >= 'a' && *s <= 'h') &&
+ (*(s + 1) >= '1' && *(s + 1) <= '8') &&
+ (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
+ (*(s + 3) >= '1' && *(s + 3) <= '8')) {
+ square[0] = *s;
+ square[1] = *(s + 1);
+
+ s += 2;
+ squaretoxy(square, &x, &y);
+ piece = getpiece(x, y);
+
+ place(0, x, y); /* clear square */
+
+ /* place piece at new location */
+ square[0] = *s;
+ square[1] = *(s + 1);
+ squaretoxy(square, &x2, &y2);
+ place(piece, x2, y2);
+ s += 2;
+ }
+ }
+ /* highlight last move */
+ highlightmove(x, y, x2, y2);
+
+ showboard();
+
+ return 0;
+}
diff --git a/fen_to_svg.c b/fen_to_svg.c
@@ -0,0 +1,287 @@
+/* TODO: option to flip board? */
+
+#include <stdio.h>
+#include <string.h>
+
+static char board[8][8];
+static char highlight[8][8];
+
+static int side_to_move = 'w'; /* default: white to move */
+static int white_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid…
+static int black_can_castle[2] = { 0, 0 }; /* allow king side, allow queen sid…
+
+static const int showcoords = 1; /* config: show board coordinates? */
+
+int
+isvalidsquare(int x, int y)
+{
+ return !(x < 0 || x >= 8 || y < 0 || y >= 8);
+}
+
+/* place a piece, if possible */
+void
+place(int piece, int x, int y)
+{
+ if (!isvalidsquare(x, y))
+ return;
+
+ board[y][x] = piece;
+}
+
+/* get piece, if possible */
+int
+getpiece(int x, int y)
+{
+ if (!isvalidsquare(x, y))
+ return 0;
+ return board[y][x];
+}
+
+int
+squaretoxy(const char *s, int *x, int *y)
+{
+ if (*s >= 'a' && *s <= 'h' &&
+ *(s + 1) >= '1' && *(s + 1) <= '8') {
+ *x = *s - 'a';
+ *y = '8' - *(s + 1);
+ return 1;
+ }
+ return 0;
+}
+
+void
+highlightmove(int x1, int y1, int x2, int y2)
+{
+ if (isvalidsquare(x1, y1))
+ highlight[y1][x1] = 1;
+
+ if (isvalidsquare(x2, y2))
+ highlight[y2][x2] = 1;
+}
+
+void
+showpiece(int c)
+{
+ const char *s = "";
+
+ /* lichess default set,
+ extracted from https://github.com/lichess-org/lila/tree/master/publ…
+ switch (c) {
+ case 'K': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'Q': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'R': s = "<g fill=\"#fff\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'B': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'N': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'P': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2…
+ case 'k': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'q': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\…
+ case 'r': s = "<g fill-rule=\"evenodd\" stroke=\"#000\" stroke-width=\…
+ case 'b': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'n': s = "<g fill=\"none\" fill-rule=\"evenodd\" stroke=\"#000\" …
+ case 'p': s = "<path d=\"M22.5 9c-2.21 0-4 1.79-4 4 0 .89.29 1.71.78 2…
+ }
+
+ if (*s)
+ fputs(s, stdout);
+}
+
+void
+showboardfen(void)
+{
+ int x, y, piece, skip = 0;
+
+ for (y = 0; y < 8; y++) {
+ if (y > 0)
+ putchar('/');
+ skip = 0;
+ for (x = 0; x < 8; x++) {
+ piece = getpiece(x, y);
+ if (piece) {
+ if (skip)
+ putchar(skip + '0');
+ putchar(piece);
+ skip = 0;
+ } else {
+ skip++;
+ }
+ }
+ if (skip)
+ putchar(skip + '0');
+ }
+
+ /* ? TODO: detect en passant, invalid castling etc? */
+}
+
+void
+showboard(void)
+{
+ /* lichess default theme colors */
+ const char *darksquare = "#b58863";
+ const char *lightsquare = "#f0d9b5";
+ const char *darksquarehi = "#aaa23a";
+ const char *lightsquarehi = "#cdd26a";
+ const char *color;
+ int x, y, piece;
+
+ fputs("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www…
+ "<svg width=\"360\" height=\"360\" viewBox=\"0 0 360 360\" xml…
+ "<rect fill=\"#fff\" stroke=\"#000\" x=\"0\" y=\"0\" width=\"3…
+
+ fputs("<!-- Board FEN: ", stdout);
+ showboardfen();
+ fputs(" -->\n", stdout);
+
+ for (y = 0; y < 8; y++) {
+ for (x = 0; x < 8; x++) {
+ if (x % 2 == 0) {
+ if (y % 2 == 0)
+ color = highlight[y][x] ? lightsquareh…
+ else
+ color = highlight[y][x] ? darksquarehi…
+ } else {
+ if (y % 2 == 0)
+ color = highlight[y][x] ? darksquarehi…
+ else
+ color = highlight[y][x] ? lightsquareh…
+ }
+
+ printf("<g><rect x=\"%d\" y=\"%d\" width=\"45\" height…
+ x * 45, y * 45, color);
+
+ piece = getpiece(x, y);
+ if (piece) {
+ printf("<g transform=\"translate(%d %d)\">", x…
+ showpiece(piece);
+ fputs("</g>\n", stdout);
+ }
+ }
+ }
+
+ if (showcoords) {
+ x = 7;
+ for (y = 0; y < 8; y++) {
+ if (y % 2 == 0)
+ color = highlight[y][x] ? lightsquarehi : ligh…
+ else
+ color = highlight[y][x] ? darksquarehi : darks…
+ printf("<text x=\"%d\" y=\"%d\" fill=\"%s\" dominant-b…
+ (x * 45) + 37, (y * 45) + 3, color, '8' - y);
+ }
+ y = 7;
+ for (x = 0; x < 8; x++) {
+ if (x % 2 == 0)
+ color = highlight[y][x] ? lightsquarehi : ligh…
+ else
+ color = highlight[y][x] ? darksquarehi : darks…
+ printf("<text x=\"%d\" y=\"%d\" fill=\"%s\" dominant-b…
+ (x * 45) + 2, (y + 1) * 45 - 3, color, x + 'a'…
+ }
+ }
+
+ fputs("</svg>\n", stdout);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *fen, *moves, *s;
+ int x, y, x2, y2, field, piece;
+ char pieces[] = "PNBRQKpnbrqk", square[3];
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s <FEN> <moves>\n", argv[0]);
+ return 1;
+ }
+
+ fen = argv[1];
+ moves = argv[2];
+
+ /* initial board state, FEN format */
+ x = y = field = 0;
+ for (s = fen; *s; s++) {
+ /* next field, fields are: piece placement data, active color,
+ Castling availability, En passant target square,
+ Halfmove clock, Fullmove number */
+ if (*s == ' ') {
+ field++;
+ continue;
+ }
+
+ switch (field) {
+ case 0: /* piece placement data */
+ /* skip square */
+ if (*s >= '1' && *s <= '9') {
+ x += (*s - '0');
+ continue;
+ }
+ /* next rank */
+ if (*s == '/') {
+ x = 0;
+ y++;
+ continue;
+ }
+ /* is piece? place it */
+ if (strchr(pieces, *s))
+ place(*s, x++, y);
+ break;
+ case 1: /* active color */
+ if (*s == 'w' || *s == 'b')
+ side_to_move = *s;
+ break;
+ case 2: /* castling availability */
+ if (*s == '-') {
+ white_can_castle[0] = 0;
+ white_can_castle[1] = 0;
+ black_can_castle[0] = 0;
+ black_can_castle[1] = 0;
+ } else if (*s == 'K') {
+ white_can_castle[0] = 1;
+ } else if (*s == 'Q') {
+ white_can_castle[1] = 1;
+ } else if (*s == 'k') {
+ black_can_castle[0] = 1;
+ } else if (*s == 'q') {
+ black_can_castle[1] = 1;
+ }
+ break;
+ case 3: /* TODO: en-passant square, rest of the fields */
+ break;
+ }
+ /* TODO: parse which side to move, en-passant, etc */
+ }
+
+ /* process moves */
+ square[2] = '\0';
+ x = y = x2 = y2 = -1;
+ for (s = moves; *s; s++) {
+ if (*s == ' ')
+ continue;
+ if ((*s >= 'a' && *s <= 'h') &&
+ (*(s + 1) >= '1' && *(s + 1) <= '8') &&
+ (*(s + 2) >= 'a' && *(s + 2) <= 'h') &&
+ (*(s + 3) >= '1' && *(s + 3) <= '8')) {
+ square[0] = *s;
+ square[1] = *(s + 1);
+
+ s += 2;
+ squaretoxy(square, &x, &y);
+ piece = getpiece(x, y);
+
+ place(0, x, y); /* clear square */
+
+ /* place piece at new location */
+ square[0] = *s;
+ square[1] = *(s + 1);
+ squaretoxy(square, &x2, &y2);
+ place(piece, x2, y2);
+ s += 2;
+ }
+ }
+ /* highlight last move */
+ highlightmove(x, y, x2, y2);
+
+ showboard();
+
+ return 0;
+}
diff --git a/generate.sh b/generate.sh
@@ -0,0 +1,138 @@
+#!/bin/sh
+
+index="puzzles/index.html"
+mkdir -p puzzles
+
+cat > "$index" <<!
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Puzzles</title>
+<style type="text/css">
+body {
+ font-family: sans-serif;
+ width: 960px;
+ margin: 0 auto;
+ padding: 0 10px;
+}
+.puzzle {
+ float: left;
+ margin-right: 25px;
+}
+</style>
+</head>
+<body>
+<header>
+<h1>Puzzles, happy christmas mating!</h1>
+<!--<p>View the bottom of the SVG source for <a href="https://en.wikipedia.org…
+</header>
+<main>
+!
+
+# shuffle, some sort of order and point system based on rating of puzzle.
+
+db="lichess_db_puzzle.csv"
+count=1
+
+(grep 'mateIn1' < "$db" | shuf -n 100 | sed 10q
+grep 'mateIn2' < "$db" | shuf -n 100 | sed 10q
+grep 'mateIn3' < "$db" | shuf -n 100 | sed 10q
+grep 'mateIn4' < "$db" | shuf -n 100 | sed 10q
+LC_ALL=C awk -F ',' '(" " $8 " ") ~ / mateIn5 / && int($4) < 2000 { print $0 }…
+LC_ALL=C awk -F ',' '(" " $8 " ") ~ / mateIn5 / && int($4) >= 2000 { print $0 …
+LC_ALL=C awk -F ',' '(" " $8 " ") ~ / mateIn5 / && int($4) >= 2700 { print $0 …
+) |
+LC_ALL=C awk -F ',' '
+{
+ points="1 point"; # default
+}
+(" " $8 " ") ~ / mateIn2 / {
+ points="2 points";
+}
+(" " $8 " ") ~ / mateIn3 / {
+ points="3 points";
+}
+(" " $8 " ") ~ / mateIn4 / {
+ points="4 points";
+}
+(" " $8 " ") ~ / mateIn5 / && int($4) < 2000 {
+ points="5 points";
+}
+(" " $8 " ") ~ / mateIn5 / && int($4) >= 2000 {
+ points="7 points";
+}
+(" " $8 " ") ~ / mateIn5 / && int($4) >= 2700 {
+ points="10 points";
+}
+{
+ print $0 "," points;
+}' | \
+while read -r line; do
+ i="$count"
+ fen=$(printf '%s' "$line" | cut -f 2 -d ',')
+ tomove=$(printf '%s' "$line" | cut -f 2 -d ',' | cut -f 2 -d ' ')
+ moves=$(printf '%s' "$line" | cut -f 3 -d ',' | cut -b 1-4 ) # first m…
+ rating=$(printf '%s' "$line" | cut -f 4 -d ',')
+ ratingdev=$(printf '%s' "$line" | cut -f 5 -d ',')
+ lichess=$(printf '%s' "$line" | cut -f 9 -d ',')
+
+ # added field
+ points=$(printf '%s' "$line" | cut -f "11" -d ',')
+
+ img="$i.svg"
+ txt="$i.txt"
+ destsvg="puzzles/$img"
+ desttxt="puzzles/$txt"
+
+ ./fen_to_svg "$fen" "$moves" > "$destsvg"
+ ./fen_to_ascii "$fen" "$moves" > "$desttxt"
+
+ printf '<div class="puzzle">' >> "$index"
+ printf '<h2>Puzzle %s</h2>\n' "$i" >> "$index"
+ test "$lichess" != "" && printf '<a href="%s">' "$lichess" >> "$index"
+
+ title=""
+ test "$rating" != "" && title="Puzzle rating: $rating"
+
+ printf '<img src="%s" alt="Puzzle #%s" title="%s" width="360" height="…
+ "$img" "$i" "$title" >> "$index"
+ test "$lichess" != "" && printf '</a>' >> "$index"
+ echo "" >> "$index"
+
+ case "$tomove" in
+ "w") tomove="w";;
+ "b") tomove="b";;
+ *) tomove="w";; # default
+ esac
+
+ movetext=""
+ # if there is a first move, inverse to move.
+ if test "moves" != ""; then
+ case "$tomove" in
+ "w") movetext=", black to move";;
+ "b") movetext=", white to move";;
+ esac
+ else
+ case "$tomove" in
+ "w") movetext=", white to move";;
+ "b") movetext=", black to move";;
+ esac
+ fi
+
+ printf '<p><b>%s</b>%s</p>\n' "$points" "$movetext" >> "$index"
+ printf '%s%s\n' "$points" "$movetext" >> "$desttxt"
+
+ printf '</div>\n' >> "$index"
+
+ # DEBUG
+ #echo "$count" >&2
+
+ count=$((count + 1))
+done
+
+cat >> "$index" <<!
+</main>
+</body>
+</html>
+!
You are viewing proxied material from codemadness.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.