/*
pptdb, generate neural network training data from a playtak.com
database dump
Copyright (C) 2021, tslil clingman
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
int generate;
uint64_t heights[16];
FILE *training_fh = NULL;
float max_flats;
uint8_t outcome_black;
static void
write_input(const int dx, const int dy, const uint8_t swap) {
// Two numbers for flats remaining
fprintf(training_fh,"%d,%.8f,%.8f,",
ply & 1 ? 1 : -1,
(float)(white_count & 127)/max_flats,
(float)(black_count & 127)/max_flats);
// Write the board layers
float val;
int col, row;
row = (dy>0)?-1:board_size;
for (int i = 0; i < board_size; i++) {
row += dy;
col = (dx>0)?-1:board_size;
for (int j = 0; j < board_size; j++) {
col += dx;
const uint8_t k =
(swap) ? THE_COORDS(row, col) : THE_COORDS(col, row);
val = 0;
if (COUNT_AT(k)>0) {
// Top layer of stacks is handled differently to indicate
// stone type
if (STONE_AT(k) == STONE_STANDING) {
val = (colours[k] & 1) ? +0.25 : -0.25;
} else if (STONE_AT(k) == STONE_CAPSTONE) {
val = (colours[k] & 1) ? +1.00 : -1.00;
} else {
val = (colours[k] & 1) ? +0.50 : -0.50;
} }
fprintf(training_fh,"%.2f,", val);
}
}
fprintf(training_fh, "%d,%d\n", outcome_black ? 1 : 0, outcome_black ? 0 : 1);
}
// Warning: performs _no_ checks on input whatsoever
static enum ACT_RESULT
parse_line(const char *pt, const ssize_t read) {
ssize_t idx;
enum ACT_RESULT r;
int total_plies = 0;
for (idx=0;idx d_col) dir=M_LEFT;
else if (s_row < d_row) dir=M_UP;
else if (s_row > d_row) dir=M_DOWN;
uint8_t steps = 0;
do {
idx+=2;
drops[steps++] = pt[idx] - '0';
} while (idx+21) heights[COUNT_AT(k)]+=1;
}
}
}
// Generate training data, not too early in the game and not at
// the end, under all eight symmetries of the board
if (generate && ply > 7 && ply < total_plies && ply + 10 >= total_plies) {
write_input(+1, +1, 1); write_input(+1, +1, 0);
write_input(+1, -1, 1); write_input(+1, -1, 0);
write_input(-1, +1, 1); write_input(-1, +1, 0);
write_input(-1, -1, 1); write_input(-1, -1, 0);
}
// Parse next action
while (idx=read) return ACT_OK;
next_ply();
}
return ACT_OK;
}
const char* license = "pptdb, generate neural network training data from a playtak.com database dump\n\
\n\
Copyright (C) 2021, tslil clingman\n\
\n\
This program comes with ABSOLUTELY NO WARRANTY; and is made available under the terms of the GNU GPL v3 license. This is free software, and you are welcome to redistribute it under certain conditions; see COPYING for details.\n";
int main(int argc, char **argv) {
(void)(argc);
enum ACT_RESULT r;
enum WIN_TYPE win;
uint32_t games = 0, overflow=0, illegal = 0;
uint32_t road_wins=0, flat_wins=0, road_turns=0, flat_turns=0,
white_wins = 0, black_wins = 0;
for (int k = 0; k < 16; k++) heights[k] = 0;
size_t len = 0;
ssize_t read = 0;
FILE *playtak_fh = NULL;
char *line = NULL, td_fn[65];
const uint8_t size = argv[1][0]-'0';
playtak_fh = fopen(argv[2], "r");
if (playtak_fh == NULL) exit(EXIT_FAILURE);
if (argc > 3 && (!strncmp("generate", argv[3], 8))) {
generate=1;
max_flats = (size == 5) ? 21.0 : 30.0;
snprintf(td_fn, 64, "data/parsed-%d.csv",size);
training_fh = fopen(td_fn, "w");
if (training_fh == NULL) exit(EXIT_FAILURE);
} else generate=0;
while ((read = getline(&line, &len, playtak_fh)) != -1) {
// Reset everything
reset_state(size);
// Store the outcome of this game. Black win = 1
outcome_black = (line[read-4] == '0');
// Parse the line
r = parse_line(line,read-4);
// Adjust counts if we're not generating training data
if (generate == 0) {
if (r == ACT_ILLEGAL) {
illegal++;
printf("Illegal:\n%s",line);
} else if (r == ACT_OVERFLOW) {
printf("Overflow:\n%s",line);
overflow++;
} else {
win = check_win();
if (win == WIN_FLAT_BLACK
|| win == WIN_FLAT_WHITE
|| win == WIN_DRAW) {
flat_wins++;
flat_turns += ply/2+1;
} else {
road_wins++;
road_turns += ply/2+1;
}
if (win == WIN_FLAT_BLACK || win == WIN_ROAD_BLACK)
black_wins++;
else if (win == WIN_FLAT_WHITE || win == WIN_ROAD_WHITE)
white_wins++;
}
}
games++;
}
fclose(playtak_fh);
if (generate) fclose(training_fh);
if (line) free(line);
if (illegal || overflow) putchar('\n');
printf("Read %d games\n",games);
if (generate==0) {
printf("Illegals: %d\nOverflows: %d\n\
Black wins: %.3f%%\n\
Road wins: %d\nFlat wins: %d\n\
Average turns to road win: %.3f\n\
Average turns to flat win: %.3f\n",
illegal, overflow,
(double)black_wins / (double)(black_wins+white_wins) * 100,
road_wins, flat_wins,
(double)(road_turns)/(double)(road_wins),
(double)(flat_turns)/(double)(flat_wins));
for (int k = 2; k < 16; k++) {
printf("Height %2d: %7ld\n",k,heights[k]);
}
}
exit(EXIT_SUCCESS);
}