Introduction
Introduction Statistics Contact Development Disclaimer Help
generate.sh - chess-puzzles - chess puzzle book generator
git clone git://git.codemadness.org/chess-puzzles
Log
Files
Refs
README
LICENSE
---
generate.sh (9356B)
---
1 #!/bin/sh
2
3 fenbin="./fen"
4 db="lichess_db_puzzle.csv"
5 # default, green, grey
6 theme="default"
7 lang="en" # en, nl
8 #fenopts="-d" # dutch mode (for speak output)
9
10 # texts / localization.
11 # English
12 if [ "$lang" = "en" ]; then
13 text_solutions="Solutions"
14 text_solutionstxtlabel="Text listing of solutions"
15 text_puzzles="Puzzles"
16 text_puzzle="Puzzle"
17 text_puzzlerating="Puzzel rating"
18 text_point="point"
19 text_points="points"
20 text_whitetomove="white to move"
21 text_blacktomove="black to move"
22 text_title="${text_puzzles}"
23 text_header="${text_puzzles}!"
24 pgnmapping="KQRBN"
25 fi
26
27 # Dutch
28 if [ "$lang" = "nl" ]; then
29 text_solutions="Oplossingen"
30 text_solutionstxtlabel="Tekstbestand, lijst met oplossingen"
31 text_puzzles="Puzzels"
32 text_puzzle="Puzzel"
33 text_puzzlerating="Puzzel moeilijkheidsgraad"
34 text_point="punt"
35 text_points="punten"
36 text_whitetomove="wit aan zet"
37 text_blacktomove="zwart aan zet"
38 text_title="${text_puzzles}"
39 text_header="${text_puzzles}!"
40 # Dutch: (K)oning, (D)ame, (T)oren, (L)oper, (P)aard.
41 pgnmapping="KDTLP"
42 fi
43
44 if ! test -f "$db"; then
45 printf 'File "%s" not found, run `make db` to update it\n' "$db"…
46 exit 1
47 fi
48
49 index="puzzles/index.html"
50 indexvt="puzzles/index.vt"
51
52 # clean previous files.
53 rm -rf puzzles
54 mkdir -p puzzles/solutions
55
56 solutions="$(mktemp)"
57 seedfile="$(mktemp)"
58 seed=20240101 # must be a integer value
59 # seed for random sorting, makes it deterministic for the same system
60 # seed must be sufficiently long.
61 echo "${seed}_chess_puzzles" > "$seedfile"
62
63 # shuffle(file, amount)
64 shuffle() {
65 f="$1"
66 total="$2"
67 nlines="$(wc -l < "$f")"
68 nlines="$((nlines + 0))"
69 results="$(mktemp)"
70
71 # generate list of lines to use. Not perfectly random but good enough.
72 LC_ALL=C awk -v "seed=$seed" -v "nlines=$nlines" -v "total=$total" '
73 BEGIN {
74 srand(seed);
75 for (i = 0; i < total; i++)
76 sel[int(rand() * nlines)] = 1;
77 }
78 sel[NR] {
79 print $0;
80 }' "$f" > "$results"
81
82 # now we have less results we can use the slow sort -R.
83 sort -R --random-source "$seedfile" "$results"
84 rm -f "$results"
85 }
86
87 # solutions.txt header.
88 solutionstxt="puzzles/solutions.txt"
89 printf '%s\n\n' "${text_solutions}" >> "$solutionstxt"
90
91 cat > "$indexvt" <<!
92 ${text_header}
93
94 !
95
96 cat > "$index" <<!
97 <!DOCTYPE html>
98 <html dir="ltr" lang="${lang}">
99 <head>
100 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
101 <title>${text_title}</title>
102 <style type="text/css">
103 body {
104 font-family: sans-serif;
105 width: 775px;
106 margin: 0 auto;
107 padding: 0 10px;
108 }
109 a {
110 color: #000;
111 }
112 h2 a {
113 color: #000;
114 text-decoration: none;
115 }
116 h2 a:hover:after {
117 content: " #";
118 }
119 .puzzle {
120 float: left;
121 margin-right: 25px;
122 }
123 footer {
124 clear: both;
125 }
126 details summary {
127 cursor: pointer; /* show hand */
128 }
129 @media (prefers-color-scheme: dark) {
130 body {
131 background-color: #000;
132 color: #bdbdbd;
133 }
134 h2 a, a {
135 color: #bdbdbd;
136 }
137 }
138 </style>
139 </head>
140 <body>
141 <header>
142 <h1>${text_header}</h1>
143 </header>
144 <main>
145 !
146
147 # shuffle, some sort of order and point system based on rating of puzzle.
148 count=1
149
150 groupsdir="$(mktemp -d)"
151 test "$groupsdir" = "" && exit 1
152
153 grep 'mateIn1' "$db" > "$groupsdir/matein1.csv"
154 grep 'mateIn2' "$db" > "$groupsdir/matein2.csv"
155 grep 'mateIn3' "$db" > "$groupsdir/matein3.csv"
156 grep 'mateIn4' "$db" > "$groupsdir/matein4.csv"
157 grep 'mateIn5' "$db" > "$groupsdir/matein5.csv"
158 LC_ALL=C awk -F ',' 'int($4) < 2000 { print $0 }' "$groupsdir/matein5.cs…
159 LC_ALL=C awk -F ',' 'int($4) >= 2000 { print $0 }' "$groupsdir/matein5.c…
160 LC_ALL=C awk -F ',' 'int($4) >= 2700 { print $0 }' "$groupsdir/matein5.c…
161
162 (
163 shuffle "$groupsdir/matein1.csv" 100 | sed 10q | LC_ALL=C awk '{ print $…
164 shuffle "$groupsdir/matein2.csv" 100 | sed 10q | LC_ALL=C awk '{ print $…
165 shuffle "$groupsdir/matein3.csv" 100 | sed 10q | LC_ALL=C awk '{ print $…
166 shuffle "$groupsdir/matein4.csv" 100 | sed 10q | LC_ALL=C awk '{ print $…
167 shuffle "$groupsdir/matein5_lt_2000.csv" 100 | sed 5q | LC_ALL=C awk '{ …
168 shuffle "$groupsdir/matein5_ge_2000.csv" 100 | sed 3q | LC_ALL=C awk '{ …
169 shuffle "$groupsdir/matein5_ge_2700.csv" 100 | sed 2q | LC_ALL=C awk '{ …
170 rm -rf "$groupsdir"
171 ) | \
172 while read -r line; do
173 i="$count"
174 fen=$(printf '%s' "$line" | cut -f 2 -d ',')
175
176 tomove=$(printf '%s' "$line" | cut -f 2 -d ',' | cut -f 2 -d ' ')
177 allmoves="$(printf '%s' "$line" | cut -f 3 -d ',')"
178 firstmove=$(printf '%s' "$line" | cut -f 3 -d ',' | cut -f 1 -d …
179 rating=$(printf '%s' "$line" | cut -f 4 -d ',')
180 ratingdev=$(printf '%s' "$line" | cut -f 5 -d ',')
181 lichess=$(printf '%s' "$line" | cut -f 9 -d ',')
182
183 case "$tomove" in
184 "w") tomove="w";;
185 "b") tomove="b";;
186 *) tomove="w";; # default
187 esac
188
189 # first move is played so flip when white (not black).
190 flip=""
191 test "$tomove" = "w" && flip="-f"
192
193 # added field: points
194 points=$(printf '%s' "$line" | cut -f "11" -d ',')
195 if [ "$points" = "1" ]; then
196 points="$points ${text_point}"
197 else
198 points="$points ${text_points}"
199 fi
200
201 img="$i.svg"
202 txt="$i.txt"
203 vt="$i.vt"
204 destfen="puzzles/$i.fen"
205 destsvg="puzzles/$img"
206 desttxt="puzzles/$txt"
207 destvt="puzzles/$vt"
208
209 "$fenbin" $fenopts -m "$pgnmapping" -t "$theme" $flip -o svg "$f…
210 "$fenbin" $fenopts -m "$pgnmapping" -t "$theme" $flip -o ascii "…
211 "$fenbin" $fenopts -m "$pgnmapping" -t "$theme" $flip -o tty "$f…
212 "$fenbin" $fenopts -m "$pgnmapping" -t "$theme" $flip -o fen "$f…
213 pgn=$("$fenbin" $fenopts -l -m "$pgnmapping" -o pgn "$fen" "$fir…
214
215 printf '<div class="puzzle" id="puzzle-%s">\n' "$i" >> "$index"
216 printf '<h2><a href="#puzzle-%s">%s %s</a></h2>\n' "$i" "${text_…
217 test "$lichess" != "" && printf '<a href="%s">' "$lichess" >> "$…
218
219 title=""
220 test "$rating" != "" && title="${text_puzzlerating}: $rating"
221
222 printf '<img src="%s" alt="%s #%s" title="%s" width="360" height…
223 "$img" "${text_puzzle}" "$i" "$title" >> "$index"
224 test "$lichess" != "" && printf '</a>' >> "$index"
225 echo "" >> "$index"
226
227 movetext=""
228 # if there is a first move, inverse to move.
229 if test "$firstmove" != ""; then
230 case "$tomove" in
231 "w") movetext=", ${text_blacktomove}";;
232 "b") movetext=", ${text_whitetomove}";;
233 esac
234 else
235 case "$tomove" in
236 "w") movetext=", ${text_whitetomove}";;
237 "b") movetext=", ${text_blacktomove}";;
238 esac
239 fi
240
241 printf '<p><b>%s</b>%s</p>\n' "$points" "$movetext" >> "$index"
242 printf '%s%s\n' "$points" "$movetext" >> "$desttxt"
243 printf '\n%s%s\n' "$points" "$movetext" >> "$destvt"
244
245 # vt
246 printf 'Puzzle %s\n\n' "$i" >> "$indexvt"
247 cat "$destvt" >> "$indexvt"
248 printf '\n\n' >> "$indexvt"
249
250 # solutions per puzzle.
251 printf '<div class="puzzle-solution">\n' >> "$solutions"
252 printf '<h2><a href="#puzzle-%s">%s %s</a></h2>\n' "$i" "${text_…
253
254 m="${allmoves}"
255 movecount=0
256 # create a move list, removing one move each step, for generating
257 # the solution images.
258
259 # add initial puzzle aswell for context.
260 ptitlespeak="$("$fenbin" $fenopts -l -o speak "$fen" "$firstmove…
261 printf '<img src="%s" width="180" height="180" loading="lazy" al…
262 "${i}.svg" "$ptitlespeak" "$pgn, $ptitlespeak" >> "$solu…
263
264 # solution PGN
265 pgn_solution="$("$fenbin" $fenopts -m "$pgnmapping" -o pgn "$fen…
266
267 destsolpgn="puzzles/solutions/${i}.pgn"
268 printf '%s\n' "$pgn_solution" > "$destsolpgn"
269
270 # printf 'DEBUG: #%s: "%s" "%s"\n' "$i" "$fen" "$allmoves" >&2
271
272 while [ "$m" != "" ]; do
273 prevmoves="$m"
274
275 echo "$m"
276
277 m="${m% }"
278 m="${m%[^ ]*}"
279 m="${m% }"
280
281 test "$prevmoves" = "$m" && break # same, break also
282 done | sort | while read -r movelist; do
283 # first move is already shown, skip it.
284 if test "$movecount" = "0"; then
285 movecount=$((movecount + 1))
286 continue
287 fi
288
289 # process move list in sequence.
290 destsolsvg="puzzles/solutions/${i}_${movecount}.svg"
291 "$fenbin" $fenopts -m "$pgnmapping" -t "$theme" $flip -o…
292
293 # PGN of moves so far.
294 pgn="$("$fenbin" $fenopts $fenopts -l -m "$pgnmapping" -…
295 ptitlespeak="$("$fenbin" $fenopts -l -o speak "$fen" "$m…
296
297 printf '<img src="%s" width="180" height="180" loading="…
298 "solutions/${i}_${movecount}.svg" "$ptitlespeak"…
299
300 movecount=$((movecount + 1))
301 done
302
303 printf '<p><b>PGN:</b> %s</p>\n' "${pgn_solution}" >> "$solution…
304 printf '</div>\n' >> "$solutions"
305
306 printf '</div>\n' >> "$index"
307
308 # add PGN solution to solutions text file.
309 printf '%s. %s\n' "$i" "${pgn_solution}" >> "$solutionstxt"
310
311 count=$((count + 1))
312 done
313
314 # solutions / spoilers
315 printf '<footer><br/><br/><details>\n<summary>%s</summary>\n' "$text_sol…
316 printf '<p><a href="solutions.txt">%s</a></p>\n' "${text_solutionstxtlab…
317
318 # add solutions HTML to index page.
319 cat "$solutions" >> "$index"
320 echo "</details>\n<br/><br/></footer>\n" >> "$index"
321
322 # add solutions to vt index page.
323 printf '\n\n\n\n\n\n\n\n\n\n' >> "$indexvt"
324 printf '\n\n\n\n\n\n\n\n\n\n' >> "$indexvt"
325 printf '\n\n\n\n\n' >> "$indexvt"
326 cat "$solutionstxt" >> "$indexvt"
327
328 cat >> "$index" <<!
329 </main>
330 </body>
331 </html>
332 !
333
334 rm -f "$solutions" "$seedfile"
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.