diff options
| -rw-r--r-- | .clang-format | 192 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | include/actions.c | 508 | ||||
| -rw-r--r-- | include/actions.h | 29 | ||||
| -rw-r--r-- | include/lcdlib.c | 53 | ||||
| -rw-r--r-- | include/lcdlib.h | 7 | ||||
| -rw-r--r-- | include/negamax.c | 208 | ||||
| -rw-r--r-- | include/negamax.h | 10 | ||||
| -rw-r--r-- | include/nn1986.c | 26 | ||||
| -rw-r--r-- | include/nn1986.h | 2 | ||||
| -rw-r--r-- | include/tak.c | 670 | ||||
| -rw-r--r-- | include/tak.h | 53 | ||||
| -rw-r--r-- | include/tps.c | 351 | ||||
| -rw-r--r-- | include/tps.h | 8 | ||||
| -rw-r--r-- | include/tt_llcht.c | 27 | ||||
| -rw-r--r-- | include/tt_llcht.h | 9 | ||||
| -rw-r--r-- | include/weights.c | 10 | ||||
| -rw-r--r-- | include/weights.h | 3 | ||||
| -rw-r--r-- | include/xorshift64.h | 11 | ||||
| -rw-r--r-- | include/zobrist.c | 23 | ||||
| -rw-r--r-- | include/zobrist.h | 8 | ||||
| -rwxr-xr-x | resources/extract.sh | 3 | ||||
| -rw-r--r-- | src/ct1986.c | 260 | ||||
| -rw-r--r-- | src/ctlm.c | 240 | ||||
| -rw-r--r-- | src/cttei.c | 96 | ||||
| -rw-r--r-- | src/geminict.c | 203 | ||||
| -rw-r--r-- | src/nn_train.py | 10 | ||||
| -rw-r--r-- | src/pptdb.c | 390 |
28 files changed, 1927 insertions, 1485 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..48b2c67 --- /dev/null +++ b/.clang-format @@ -0,0 +1,192 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + @@ -42,7 +42,7 @@ Total params: 1,986 Trainable params: 1,986 Non-trainable params: 0 ``` -which was trained on the binary classification problem of predicting the winner from a given board state. As input the network is fed the top layer of the board only (see nn1986.c for details) as well as `flats used/flats remaining` fractions for both players and a single float indicating the parity of the board. At the time of training, on the dataset given by `resources/extract.sh`, this achieves ~82% accuracy on the validation set. +which was trained on the binary classification problem of predicting the winner from a given board state. As input the network is fed the top layer of the board only (see nn1986.c for details) as well as `flats used/flats remaining` fractions for both players and a single float indicating the parity of the board. At the time of training, on the dataset given by `resources/extract.sh`, this achieves ~75% accuracy on the validation set. ## License diff --git a/include/actions.c b/include/actions.c index 795c135..6303822 100644 --- a/include/actions.c +++ b/include/actions.c @@ -16,37 +16,42 @@ */ #include "actions.h" +#include "tak.h" + +#include <stdio.h> + +static uint8_t al_board_size; // =================================================================== // Helper method declarations // =================================================================== -#define DANGER_MIN(a,b) (((a)<(b))?(a):(b)) +#define DANGER_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define CLR_STONE NUM_MASK -static inline void -list_append(action_list_t *list, const enum A_TYPE type, - const int8_t loc, const uint8_t data0, - const uint8_t data1); +static inline void list_append(action_list_t *list, const enum A_TYPE type, + const int8_t loc, const uint8_t data0, + const uint8_t data1); + +static inline void list_prepend(action_list_t *list, const enum A_TYPE type, + const int8_t loc, const uint8_t data0, + const uint8_t data1); -static inline void -list_prepend(action_list_t *list, const enum A_TYPE type, - const int8_t loc, const uint8_t data0, - const uint8_t data1); +static inline void inline_next_ply(tak_state_p state); -static inline void -inline_next_ply(void); +static inline void inline_prev_ply(tak_state_p state); -static inline void -inline_prev_ply(void); +static inline uint8_t check_no_overflow(tak_state_p state, const uint8_t loc, + const int8_t delta, const uint8_t num, + const uint8_t steps, + const uint8_t gaps); // =================================================================== // Exported method implementations // =================================================================== -int action_move_to_front(const action_t action, - action_list_t *list) { +int action_move_to_front(const action_t action, action_list_t *list) { action_node_t *n = list->head; // TODO: what if it's not in the list? @@ -64,7 +69,6 @@ int action_move_to_front(const action_t action, return EXIT_FAILURE; } - void action_list_free(action_list_t *list) { if (list) { action_node_t *n = list->head, *nn; @@ -80,7 +84,8 @@ void action_list_free(action_list_t *list) { // Keep track of move offsets int8_t move_deltas[4]; -void action_list_init(void) { +void action_list_init(const uint8_t board_size) { + al_board_size = board_size; move_deltas[0] = +board_size; move_deltas[1] = -board_size; move_deltas[2] = -1; @@ -89,7 +94,7 @@ void action_list_init(void) { // We bias place over move by prepending place actions and appending // move actions to the generated list -action_list_t *action_list_generate(void) { +action_list_t *action_list_generate(tak_state_p state) { action_list_t *list = malloc(sizeof(struct action_list_s)); // TODO: trap errno @@ -103,278 +108,297 @@ action_list_t *action_list_generate(void) { * well save on the conditional. */ - const uint8_t material = (ply & 1) ? black_count : white_count, - flat = material & 0x7F, - cap = ((ply >= 2) && (material & 0x80)), - standing = ((ply >= 2) && flat); + const uint8_t material = + (state->ply & 1) ? state->black_count : state->white_count, + flat = material & 0x7F, + cap = ((state->ply >= 2) && (material & 0x80)), + standing = ((state->ply >= 2) && flat); // Step across the board - for (int row = 0; row < board_size; row++) { - for (int col = 0; col < board_size; col++) { + for (int row = 0; row < state->board_size; row++) { + for (int col = 0; col < state->board_size; col++) { // We'll need these at various points: the location of this // square and the maximum number of stones we could pick up - const int loc = THE_COORDS(col, row); - const uint8_t count = DANGER_MIN(COUNT_AT(loc), board_size); + const int loc = THE_COORDS(al_board_size, col, row); + const uint8_t count = DANGER_MIN(COUNT_AT(state, loc), al_board_size); // Only try moves after CPS and if the colour is correct if (count) { - if (ply >= 2 && ((colours[loc] & 1) == current_colour)) { - - // Pre-compute end-stops and crushes - uint8_t end_stops[4], crushes[4] = {0, 0, 0, 0}; - - // These are upper bounds, not counting walls and such. - // UP DOWN LEFT RIGHT - end_stops[0] = DANGER_MIN(board_size - row - 1, count); - end_stops[1] = DANGER_MIN(row, count); - end_stops[2] = DANGER_MIN(col, count); - end_stops[3] = DANGER_MIN(board_size - col - 1, count); - - // Now we check for caps and walls - const uint8_t cap_top = STONE_AT(loc) == STONE_CAPSTONE; - for (int d = 0; d < 4; d++){ - const int delta = move_deltas[d]; - const int stop = end_stops[d]; - end_stops[d] = 0; - for (int k = 1; k <= stop; k++) { - const enum STONE_VARIANT stone = STONE_AT(loc+k*delta); - if (stone == STONE_STANDING) { - if (cap_top) { - crushes[d] = 0xFF; - end_stops[d]++; - } - break; - } else if (stone == STONE_CAPSTONE) { - break; - } - end_stops[d]++; - } - } - /* - * For each direction, generate all possible ordered integer - * partitions of 1 ≤ num ≤ count whose number of summands is - * exactly 1 ≤ summands ≤ min(end_stops[dir], num) -- we - * write summands as steps. - * - * We exploit the `gaps' bijection here and elsewhere - * between ordered {integer partitions of n with s summands} - * and {binary strings of length n-1 with s-1 set bits}. - */ - for (enum MOVE_DIRECTION dir=M_UP; dir<=M_RIGHT; dir++) { - for (uint8_t num = 1; num <= count; num++) { - for (uint8_t steps = 1; - steps <= end_stops[dir] && steps <= num; - steps++) { - uint8_t gaps = - ((1<<(board_size - 2)) - 1) >> (board_size-steps-1); - // For 5x5 this givess 0b0000[0XXX] where steps-1 of - // those X's are 1s (starting with LSB) because 4-1=3 - // and 5-1=4 - do { - /* - * We skip the partition if it calls for multiple - * stones at the end with a crush. - */ - const uint8_t last_drop_check = - (num > 1) ? (gaps & (1 << (num - 2))) : 1; - if (crushes[dir] == 0 || last_drop_check) { - // We have to record a crush! - const uint8_t crush = - (steps == end_stops[dir]) && crushes[dir]; - // Store the move - - list_append(list, A_MOVE, loc, - (crush << 7) | gaps, - (dir<<4) | num); - } - /* - * With thanks to - * https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation - * we have the following magic to generate the next - * permutation of steps-many set bits - */ - uint8_t t = (gaps | (gaps - 1)); - gaps = (t + 1) - | (((~t & -~t) - 1) >> (__builtin_ctz(gaps) + 1)); - } while (gaps && (gaps + 1 <= (1 << (num - 1)))); - } - } - } - } + if (state->ply >= 2 && + ((state->colours[loc] & 1) == state->current_colour)) { + + // Pre-compute end-stops and crushes + uint8_t end_stops[4], crushes[4] = {0, 0, 0, 0}; + + // These are upper bounds, not counting walls and such. + // UP DOWN LEFT RIGHT + end_stops[0] = DANGER_MIN(al_board_size - row - 1, count); + end_stops[1] = DANGER_MIN(row, count); + end_stops[2] = DANGER_MIN(col, count); + end_stops[3] = DANGER_MIN(al_board_size - col - 1, count); + + // Now we check for caps and walls + const uint8_t cap_top = STONE_AT(state, loc) == STONE_CAPSTONE; + for (int d = 0; d < 4; d++) { + const int delta = move_deltas[d]; + const int stop = end_stops[d]; + end_stops[d] = 0; + for (int k = 1; k <= stop; k++) { + const enum STONE_VARIANT stone = STONE_AT(state, loc + k * delta); + if (stone == STONE_STANDING) { + if (cap_top) { + crushes[d] = k; + end_stops[d]++; + } + break; + } else if (stone == STONE_CAPSTONE) { + break; + } + end_stops[d]++; + } + } + /* + * For each direction, generate all possible ordered integer + * partitions of 1 ≤ num ≤ count whose number of summands is in the + * range 1 ≤ # summands ≤ min(end_stops[dir], num) -- we write + * summands as steps. + * + * We exploit the `gaps' bijection here and elsewhere between ordered + * {integer partitions of n with s summands} and {binary strings of + * length n-1 with s-1 set bits}. + */ + for (enum MOVE_DIRECTION dir = M_UP; dir <= M_RIGHT; dir++) { + const int8_t delta = move_deltas[dir]; + for (uint8_t num = 1; num <= count; num++) { + for (uint8_t steps = 1; steps <= end_stops[dir] && steps <= num; + steps++) { + uint8_t gaps = ((1 << (al_board_size - 2)) - 1) >> + (al_board_size - steps - 1); + // For 5x5 this gives 0b0000[0XXX] where steps-1 of those X's + // are 1s (starting with LSB) because 4-1=3 and 5-1=4 + do { + /* + * We skip the partition if it calls for multiple stones at + * the end with a crush, or if it would cause any stack to + * grow beyond height 15. + */ + const uint8_t no_overflow = + check_no_overflow(state, loc, delta, num, steps, gaps); + const uint8_t last_drop_check = + (num > 1) ? (gaps & (1 << (num - 2))) : 1; + const uint8_t can_and_must_crush = + crushes[dir] == steps && last_drop_check; + const uint8_t crush_check = + can_and_must_crush || crushes[dir] != steps; + if (no_overflow && crush_check) { + // Store the move + list_append(list, A_MOVE, loc, + (can_and_must_crush << 7) | gaps, + (dir << 4) | num); + } + /* + * With thanks to + * https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation + * we have the following magic to generate the next + * permutation of steps-many set bits + */ + uint8_t t = (gaps | (gaps - 1)); + gaps = + (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(gaps) + 1)); + } while (gaps && (gaps + 1 <= (1 << (num - 1)))); + } + } + } + } } // end of if (count) { ... } else if (material) { - // Empty square, generate placements - if (flat) { - list_prepend(list, A_PLACE, loc, STONE_FLAT, 0); - if (standing) - list_prepend(list, A_PLACE, loc, STONE_STANDING,0); - } - if (cap) - list_prepend(list, A_PLACE, loc, STONE_CAPSTONE, 0); + // Empty square, generate placements + if (flat) { + list_prepend(list, A_PLACE, loc, STONE_FLAT, 0); + if (standing) + list_prepend(list, A_PLACE, loc, STONE_STANDING, 0); + } + if (cap) + list_prepend(list, A_PLACE, loc, STONE_CAPSTONE, 0); } } } return list; } -void action_take(const action_t action) { +void action_take(tak_state_p state, const action_t action) { const int8_t loc = A_GET_LOC(action); if (A_GET_TYPE(action) == A_PLACE) { - const uint8_t black = (current_colour == C_BLACK); + const uint8_t black = (state->current_colour == C_BLACK); switch (A_GET_DATA0(action)) { - case STONE_FLAT: { - if (black) black_count--; - else white_count--; - colours[loc] = current_colour; - celldat[loc] = NUM_INC | STONE_FLAT; - break; - } - case STONE_STANDING: { - if (black) black_count--; - else white_count--; - colours[loc] = current_colour; - celldat[loc] = NUM_INC | STONE_STANDING; - break; - } - default: { - if (black) black_count &= 0x7F; - else white_count &= 0x7F; - colours[loc] = current_colour; - celldat[loc] = NUM_INC | STONE_CAPSTONE; - break; - } + case STONE_FLAT: { + if (black) + state->black_count--; + else + state->white_count--; + state->colours[loc] = state->current_colour; + state->celldat[loc] = NUM_INC | STONE_FLAT; + break; + } + case STONE_STANDING: { + if (black) + state->black_count--; + else + state->white_count--; + state->colours[loc] = state->current_colour; + state->celldat[loc] = NUM_INC | STONE_STANDING; + break; + } + default: { + if (black) + state->black_count &= 0x7F; + else + state->white_count &= 0x7F; + state->colours[loc] = state->current_colour; + state->celldat[loc] = NUM_INC | STONE_CAPSTONE; + break; + } } } else { /* - * See the discussion around line 135 for an explanation of the - * encoding. Here we are not interested in whether we crushed, it - * will work out by anyway because we overwrite the top stone - * type. See (*) later for when we do need to know. + * See the discussion around line 160 for an explanation of the encoding. + * Here we are not interested in whether we crushed, it will work out by + * anyway because we overwrite the top stone type. See (*) later for when we + * do need to know. */ const uint8_t gaps = A_GET_DATA0(action) & 0x7F, - num = A_GET_DATA1(action) & 0x0F, // unpack - dir = A_GET_DATA1(action) >> 4; + num = A_GET_DATA1(action) & 0x0F, // unpack + dir = A_GET_DATA1(action) >> 4; int8_t delta = move_deltas[dir]; // Use the Kernighan method to count the set bits int8_t steps = 1; - for (uint8_t _gaps = gaps; _gaps; steps++) _gaps &= _gaps - 1; + for (uint8_t _gaps = gaps; _gaps; steps++) + _gaps &= _gaps - 1; // Move top stone type to destination - celldat[loc+steps*delta] &= CLR_STONE; // necessary for crushing - celldat[loc+steps*delta] |= STONE_AT(loc); - celldat[loc] &= CLR_STONE; - celldat[loc] |= STONE_FLAT; // should be optimised out - - uint8_t total = 1, gap_bit = 1 << (num - 2); // it's not important - // what negative - // shifts do here, we - // don't use gap_bit - // if num < 2 + state->celldat[loc + steps * delta] &= CLR_STONE; // necessary for crushing + state->celldat[loc + steps * delta] |= STONE_AT(state, loc); + state->celldat[loc] &= CLR_STONE; + state->celldat[loc] |= STONE_FLAT; // should be optimised out + + uint8_t total = 1, gap_bit = 1 << (num - 2); // it's not important what + // negative shifts do here, we + // don't use gap_bit if num < 2 + // move stuff starting at destination for (uint8_t d = 1; d < num; d++, total++, gap_bit >>= 1) { // We took a step, move everything over so far if (gaps & gap_bit) { - colours[loc+steps*delta] <<= total; - colours[loc+steps*delta] |= colours[loc] & ((1 << total) - 1); - colours[loc] >>= total; - celldat[loc+steps*delta] += total*NUM_INC; - celldat[loc] -= total*NUM_INC; - // Reset for next step - total = 0; - steps--; + state->colours[loc + steps * delta] <<= total; + state->colours[loc + steps * delta] |= + state->colours[loc] & ((1 << total) - 1); + state->colours[loc] >>= total; + state->celldat[loc + steps * delta] += total * NUM_INC; + state->celldat[loc] -= total * NUM_INC; + // Reset for next step + total = 0; + steps--; } } // Move what remains (steps == 1 here always, so we simplify) - colours[loc+delta] <<= total; - colours[loc+delta] |= colours[loc] & ((1 << total) - 1); - colours[loc] >>= total; - celldat[loc+delta] += total*NUM_INC; - celldat[loc] -= total*NUM_INC; + state->colours[loc + delta] <<= total; + state->colours[loc + delta] |= state->colours[loc] & ((1 << total) - 1); + state->colours[loc] >>= total; + state->celldat[loc + delta] += total * NUM_INC; + state->celldat[loc] -= total * NUM_INC; } // Next ply - inline_next_ply(); + inline_next_ply(state); } -void action_undo(const action_t action) { +void action_undo(tak_state_p state, const action_t action) { // Previous ply - inline_prev_ply(); + inline_prev_ply(state); const int8_t loc = A_GET_LOC(action); if (A_GET_TYPE(action) == A_PLACE) { - const uint8_t black = (current_colour == C_BLACK); - celldat[loc] = 0; + const uint8_t black = (state->current_colour == C_BLACK); + state->celldat[loc] = 0; if (A_GET_DATA0(action) == STONE_CAPSTONE) { - if (black) black_count |= 0x80; - else white_count |= 0x80; + if (black) + state->black_count |= 0x80; + else + state->white_count |= 0x80; } else { - if (black) black_count++; - else white_count++; + if (black) + state->black_count++; + else + state->white_count++; } } else { // See action_take for comments, this is the time reversal, but // there is one caveat -- undoing a crush! (*) const uint8_t gaps = A_GET_DATA0(action) & 0x7F, - crush = A_GET_DATA0(action) & 0x80, - num = A_GET_DATA1(action) & 0x0F, - dir = A_GET_DATA1(action) >> 4; + crush = A_GET_DATA0(action) & 0x80, + num = A_GET_DATA1(action) & 0x0F, + dir = A_GET_DATA1(action) >> 4; const int8_t delta = move_deltas[dir]; int8_t steps = 1; uint8_t gap_bit = 1, total = 1; for (int8_t d = 1; d < num; d++, total++, gap_bit <<= 1) { if (gaps & gap_bit) { - colours[loc] <<= total; - colours[loc] |= colours[loc+steps*delta] & ((1 << total) - 1); - colours[loc+steps*delta] >>= total; - celldat[loc] += total*NUM_INC; - celldat[loc+steps*delta] -= total*NUM_INC; - total = 0; - steps++; + state->colours[loc] <<= total; + state->colours[loc] |= + state->colours[loc + steps * delta] & ((1 << total) - 1); + state->colours[loc + steps * delta] >>= total; + state->celldat[loc] += total * NUM_INC; + state->celldat[loc + steps * delta] -= total * NUM_INC; + total = 0; + steps++; } } - colours[loc] <<= total; - colours[loc] |= colours[loc+steps*delta] & ((1 << total) - 1); - colours[loc+steps*delta] >>= total; + state->colours[loc] <<= total; + state->colours[loc] |= + state->colours[loc + steps * delta] & ((1 << total) - 1); + state->colours[loc + steps * delta] >>= total; - celldat[loc] += total*NUM_INC; + state->celldat[loc] += total * NUM_INC; // celldat[loc] &= CLR_STONE; is not necessary, as STONE_FLAT == 0 - celldat[loc] |= STONE_AT(loc+steps*delta); - celldat[loc+steps*delta] -= total*NUM_INC; - celldat[loc+steps*delta] &= CLR_STONE; + state->celldat[loc] |= STONE_AT(state, loc + steps * delta); + state->celldat[loc + steps * delta] -= total * NUM_INC; + state->celldat[loc + steps * delta] &= CLR_STONE; if (crush) { - celldat[loc+steps*delta] |= STONE_STANDING; + state->celldat[loc + steps * delta] |= STONE_STANDING; } else { - celldat[loc+steps*delta] |= STONE_FLAT; // should be optimised out + state->celldat[loc + steps * delta] |= + STONE_FLAT; // should be optimised out } } } -void action_to_ptn(const action_t action, char* out_ptn) { +void action_to_ptn(const action_t action, char *out_ptn) { const int8_t loc = A_GET_LOC(action); if (A_GET_TYPE(action) == A_PLACE) { - generate_place(loc, A_GET_DATA0(action), out_ptn); + generate_place(al_board_size, loc, A_GET_DATA0(action), out_ptn); } else { const uint8_t gaps = A_GET_DATA0(action) & 0x7F, - num = A_GET_DATA1(action) & 0x0F, // unpack - dir = A_GET_DATA1(action) >> 4; + num = A_GET_DATA1(action) & 0x0F, // unpack + dir = A_GET_DATA1(action) >> 4; - uint8_t drops[board_size]; // we only ever need board_size-1 in - // drops actually, the last spot is to - // skip a bounds check at (**) + uint8_t drops[al_board_size]; // we only ever need al_board_size-1 in drops + // actually, the last spot is to skip a bounds + // check at (**) uint8_t mask = 1, steps = 0; // Translate to a drop sequence - drops[0] = 1; mask = 1; + drops[0] = 1; + mask = 1; for (uint8_t d = 1; d < num; d++) { if (gaps & mask) { - steps++; - drops[steps] = 1; // (**) no bounds check + steps++; + drops[steps] = 1; // (**) no bounds check } else { - drops[steps] += 1; + drops[steps] += 1; } mask <<= 1; } - generate_move(loc, dir, steps+1, drops, out_ptn); + generate_move(al_board_size, loc, dir, steps + 1, drops, out_ptn); } } @@ -382,10 +406,9 @@ void action_to_ptn(const action_t action, char* out_ptn) { // Helper method implementations // =================================================================== -static inline void -list_append(action_list_t *list, const enum A_TYPE type, - const int8_t loc, const uint8_t data0, - const uint8_t data1) { +static inline void list_append(action_list_t *list, const enum A_TYPE type, + const int8_t loc, const uint8_t data0, + const uint8_t data1) { action_node_t *new = malloc(sizeof(action_node_t)); // TODO: trap errno @@ -403,10 +426,9 @@ list_append(action_list_t *list, const enum A_TYPE type, list->length++; } -static inline void -list_prepend(action_list_t *list, const enum A_TYPE type, - const int8_t loc, const uint8_t data0, - const uint8_t data1) { +static inline void list_prepend(action_list_t *list, const enum A_TYPE type, + const int8_t loc, const uint8_t data0, + const uint8_t data1) { action_node_t *new = malloc(sizeof(action_list_t)); // TODO: trap errno @@ -421,24 +443,46 @@ list_prepend(action_list_t *list, const enum A_TYPE type, list->length++; } -static inline void -inline_next_ply(void) { - ply++; - if (ply == 2) { - current_colour = C_WHITE; +static inline void inline_next_ply(tak_state_p state) { + state->ply++; + if (state->ply == 2) { + state->current_colour = C_WHITE; } else { - if (current_colour == C_BLACK) current_colour = C_WHITE; - else current_colour = C_BLACK; + if (state->current_colour == C_BLACK) + state->current_colour = C_WHITE; + else + state->current_colour = C_BLACK; } } -static inline void -inline_prev_ply(void) { - if (ply>0) ply--; - if (ply == 1) { - current_colour = C_WHITE; +static inline void inline_prev_ply(tak_state_p state) { + if (state->ply > 0) + state->ply--; + if (state->ply == 1) { + state->current_colour = C_WHITE; } else { - if (current_colour == C_BLACK) current_colour = C_WHITE; - else current_colour = C_BLACK; + if (state->current_colour == C_BLACK) + state->current_colour = C_WHITE; + else + state->current_colour = C_BLACK; + } +} + +static inline uint8_t check_no_overflow(tak_state_p state, const uint8_t loc, + const int8_t delta, const uint8_t num, + const uint8_t steps, + const uint8_t gaps) { + uint8_t total = 1, gap_bit = 1 << (num - 2), step = steps; + for (uint8_t d = 1; d < num; d++, total++, gap_bit >>= 1) { + if (gaps & gap_bit) { + if (COUNT_AT(state, loc + step * delta) + total > 15) + return 0; + step--; + total = 0; + } } + if (COUNT_AT(state, loc + delta) + total > 15) + return 0; + + return 1; } diff --git a/include/actions.h b/include/actions.h index 8df9392..1550cce 100644 --- a/include/actions.h +++ b/include/actions.h @@ -18,8 +18,8 @@ #ifndef ACTIONS_H #define ACTIONS_H -#include <stdlib.h> #include <stdint.h> +#include <stdlib.h> #include <tak.h> @@ -33,16 +33,15 @@ typedef uint32_t action_t; #define A_DATA1_SHIFT 24 #define A_DATA0_SHIFT 16 -#define A_LOC_SHIFT 8 +#define A_LOC_SHIFT 8 -#define A_GET_DATA1(a) (enum A_TYPE)((a)>>A_DATA1_SHIFT) -#define A_GET_DATA0(a) (int8_t)(((a)>>A_DATA0_SHIFT) & 0xFF) -#define A_GET_LOC(a) (uint8_t)(((a)>>A_LOC_SHIFT) & 0xFF) -#define A_GET_TYPE(a) (uint8_t)((a) & 0xFF) -#define A_BUILD(type,loc,data0,data1) ((type) \ - | (loc) << A_LOC_SHIFT \ - | (data0) << A_DATA0_SHIFT \ - | (data1) << A_DATA1_SHIFT) +#define A_GET_DATA1(a) (enum A_TYPE)((a) >> A_DATA1_SHIFT) +#define A_GET_DATA0(a) (int8_t)(((a) >> A_DATA0_SHIFT) & 0xFF) +#define A_GET_LOC(a) (uint8_t)(((a) >> A_LOC_SHIFT) & 0xFF) +#define A_GET_TYPE(a) (uint8_t)((a)&0xFF) +#define A_BUILD(type, loc, data0, data1) \ + ((type) | (loc) << A_LOC_SHIFT | (data0) << A_DATA0_SHIFT | \ + (data1) << A_DATA1_SHIFT) typedef struct action_node_s { struct action_node_s *next; @@ -64,15 +63,15 @@ extern int8_t move_deltas[4]; // Methods // =================================================================== -void action_list_init(void); +void action_list_init(const uint8_t board_size); void action_list_free(action_list_t *list); -action_list_t *action_list_generate(void); +action_list_t *action_list_generate(tak_state_p state); int action_move_to_front(const action_t action, action_list_t *list); -void action_take(const action_t action); -void action_undo(const action_t action); +void action_take(tak_state_p state, const action_t action); +void action_undo(tak_state_p state, const action_t action); -void action_to_ptn(const action_t action, char* out_ptn); +void action_to_ptn(const action_t action, char *out_ptn); #endif diff --git a/include/lcdlib.c b/include/lcdlib.c index 69d6df0..beced28 100644 --- a/include/lcdlib.c +++ b/include/lcdlib.c @@ -17,38 +17,32 @@ #include "lcdlib.h" -static char previous_lines[LCD_HEIGHT][LCD_WIDTH+1]; -static const char* esc = "\x1B[L"; +static char previous_lines[LCD_HEIGHT][LCD_WIDTH + 1]; +static const char *esc = "\x1B[L"; static FILE *lcd = NULL; static int line_idx; -int -lcd_begin(void) { +int lcd_begin(void) { lcd = fopen("/dev/lcd", "w"); - if (lcd == NULL) return EXIT_FAILURE; + if (lcd == NULL) + return EXIT_FAILURE; lcd_clear(); return EXIT_SUCCESS; } -void -lcd_end(void) { - fclose(lcd); -} +void lcd_end(void) { fclose(lcd); } -void -lcd_set_blink(void) { +void lcd_set_blink(void) { fprintf(lcd, "%sB", esc); fflush(lcd); } -void -lcd_stop_blink(void) { +void lcd_stop_blink(void) { fprintf(lcd, "%sb", esc); fflush(lcd); } -void -lcd_clear(void) { +void lcd_clear(void) { line_idx = 0; for (int y = 0; y + 1 < LCD_HEIGHT; y++) { fprintf(lcd, "%sy%dx0;%sk", esc, y, esc); @@ -57,18 +51,17 @@ lcd_clear(void) { fflush(lcd); } -void -lcd_put_line(const enum LCD_WRITE_MODE mode, const char *line) { +void lcd_put_line(const enum LCD_WRITE_MODE mode, const char *line) { char last_line = 0; if (line_idx == LCD_HEIGHT) { if (mode == L_SCROLL) { // If we're at the bottom, ``shift'' everything up for (int y = 1; y < LCD_HEIGHT; y++) { - // Go to the start of row y, clear the line, and print the - // previous string there - fprintf(lcd, "%sy%dx0;%sk%s", esc, y-1, esc, previous_lines[y]); - // Overwrite the stored previous line with the next - strncpy(previous_lines[y-1], previous_lines[y], LCD_WIDTH+1); + // Go to the start of row y, clear the line, and print the + // previous string there + fprintf(lcd, "%sy%dx0;%sk%s", esc, y - 1, esc, previous_lines[y]); + // Overwrite the stored previous line with the next + strncpy(previous_lines[y - 1], previous_lines[y], LCD_WIDTH + 1); } } last_line = 1; @@ -77,20 +70,20 @@ lcd_put_line(const enum LCD_WRITE_MODE mode, const char *line) { fprintf(lcd, "%sy%dx0;%sk%s", esc, line_idx, esc, line); fflush(lcd); // Store this line, null-terminate! - if (last_line) line_idx--; - strncpy(previous_lines[line_idx], line, LCD_WIDTH+1); + if (last_line) + line_idx--; + strncpy(previous_lines[line_idx], line, LCD_WIDTH + 1); previous_lines[line_idx][LCD_WIDTH] = 0; - if (mode == L_SCROLL && line_idx < LCD_HEIGHT) line_idx++; + if (mode == L_SCROLL && line_idx < LCD_HEIGHT) + line_idx++; } -void -lcd_printf_line(const enum LCD_WRITE_MODE mode, - const char *format, ...) { - char buf[LCD_WIDTH+1]; +void lcd_printf_line(const enum LCD_WRITE_MODE mode, const char *format, ...) { + char buf[LCD_WIDTH + 1]; va_list(args); va_start(args, format); - vsnprintf(buf, LCD_WIDTH+1, format, args); + vsnprintf(buf, LCD_WIDTH + 1, format, args); va_end(args); lcd_put_line(mode, buf); diff --git a/include/lcdlib.h b/include/lcdlib.h index c514ba0..d8225c2 100644 --- a/include/lcdlib.h +++ b/include/lcdlib.h @@ -15,16 +15,16 @@ along with ct. If not, see <https://www.gnu.org/licenses/>. */ -#include <stdlib.h> #include <stdarg.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> // =================================================================== // Types // =================================================================== -#define LCD_WIDTH 16 +#define LCD_WIDTH 16 #define LCD_HEIGHT 2 enum LCD_WRITE_MODE { L_OVERWRITE, L_SCROLL }; @@ -42,5 +42,4 @@ void lcd_stop_blink(void); void lcd_put_line(const enum LCD_WRITE_MODE mode, const char *line); -void lcd_printf_line(const enum LCD_WRITE_MODE mode, - const char *format, ...); +void lcd_printf_line(const enum LCD_WRITE_MODE mode, const char *format, ...); diff --git a/include/negamax.c b/include/negamax.c index e85aba9..0f2c450 100644 --- a/include/negamax.c +++ b/include/negamax.c @@ -16,6 +16,7 @@ */ #include "negamax.h" +#include "actions.h" // =================================================================== // Variables @@ -30,43 +31,40 @@ static uint64_t negamax_best_action; // Helper declarations // =================================================================== -static float negamax(const uint8_t cur_depth, const uint8_t init_depth, - float alpha, float beta, - const float colour, const uint64_t hash); +static float negamax(tak_state_p state, const uint8_t cur_depth, + const uint8_t init_depth, float alpha, float beta, + const float colour, const uint64_t hash); // =================================================================== // Exported functions // =================================================================== void negamax_init(const uint8_t new_board_size) { - board_size = new_board_size; - action_list_init(); - zobrist_init(); - tt_init(); + action_list_init(new_board_size); + zobrist_init(new_board_size); + tt_init(); } -void negamax_free(void) { - zobrist_free(); -} +void negamax_free(void) { zobrist_free(); } -float negamax_generate(void) { - // We need to start with something outside of [-∞,∞] because those - // values are wins - const float safe_infty = infty + 1; - float result = -infty; +float negamax_generate(tak_state_p state) { + // We need to start with something outside of [-∞,∞] because those + // values are wins + const float safe_infty = infty + 1; + float result = -infty; - negamax_best_action = -1; + negamax_best_action = -1; - tt_init(); - for (int d = 1; d <= negamax_search_depth; d++) { - result = negamax(d, d, -safe_infty, safe_infty, - (ply & 1) ? +1.0 : -1.0, zobrist_compute()); - } - tt_free(); + tt_init(); + for (int d = 1; d <= negamax_search_depth; d++) { + result = negamax(state, d, d, -safe_infty, safe_infty, + (state->ply & 1) ? +1.0 : -1.0, zobrist_compute(state)); + } + tt_free(); - action_to_ptn(negamax_best_action, negamax_ptn); + action_to_ptn(negamax_best_action, negamax_ptn); - return result; + return result; } // =================================================================== @@ -78,89 +76,95 @@ float negamax_generate(void) { static enum TT_FLAG flag; static enum WIN_TYPE w; -static float negamax(const uint8_t cur_depth, const uint8_t init_depth, - float alpha, float beta, - const float colour, const uint64_t hash) { - - tt_entry_t *entry = tt_seek(hash); - - // CAUTION: ≥ breaks search stability (vs =) on shallow depths - if (entry != NULL && entry->depth >= cur_depth) { - if (entry->flag == TT_EXACT) { - return entry->value; - } else if (entry->flag == TT_LOWERBOUND && entry->value > alpha) { - alpha = entry->value; - } else if (entry->flag == TT_UPPERBOUND && entry->value < beta) { - beta = entry->value; - } - if (alpha >= beta) return entry->value; - } +static float negamax(tak_state_p state, const uint8_t cur_depth, + const uint8_t init_depth, float alpha, float beta, + const float colour, const uint64_t hash) { - action_list_t *list; - if ((list = action_list_generate()) == NULL) - return alpha; // should never happen! - - if (entry != NULL) { - action_move_to_front(entry->action, list); - } + tt_entry_t *entry = tt_seek(hash); - if (init_depth > 1 && cur_depth == init_depth) { - action_move_to_front(negamax_best_action, list); + // CAUTION: ≥ breaks search stability (vs =) on shallow depths + if (entry != NULL && entry->depth >= cur_depth) { + if (entry->flag == TT_EXACT) { + return entry->value; + } else if (entry->flag == TT_LOWERBOUND && entry->value > alpha) { + alpha = entry->value; + } else if (entry->flag == TT_UPPERBOUND && entry->value < beta) { + beta = entry->value; } - - // TODO: what to do if this is never written to? - action_t best_action = list->head->action; - float best_value = -infty; - - for (action_node_t *node=list->head; node!=NULL; node=node->next) { - negamax_display_progress(cur_depth, init_depth, list->length); - - action_take(node->action); - - // Compute the value of the node - float node_value; - if (ply >= 2*board_size - 2 && (w = check_win()) < 0xFF) { - node_value = -colour*infty; - // Check win if far enough into the game - if (w == WIN_ROAD_BLACK || w == WIN_FLAT_BLACK) { - node_value = colour*infty; - } else if (w == WIN_DRAW) { - node_value = 0; - } - } else if (cur_depth > 1) { - // If nobody won, or too early and not leaf, recurse - node_value = -negamax(cur_depth - 1, init_depth, - -beta, -alpha, - -colour, zobrist_compute()); - } else { - node_value = colour * nn1986_evaluate_black_win(); - } - action_undo(node->action); - - if (node_value > best_value) { - best_value = node_value; - best_action = node->action; - } - - if (best_value > alpha) alpha = best_value; - if (alpha >= beta) break; + if (alpha >= beta) + return entry->value; + } + + action_list_t *list; + if ((list = action_list_generate(state)) == NULL) + return alpha; // should never happen! + + if (entry != NULL) { + action_move_to_front(entry->action, list); + } + + if (init_depth > 1 && cur_depth == init_depth) { + action_move_to_front(negamax_best_action, list); + } + + // TODO: what to do if this is never written to? + action_t best_action = list->head->action; + float best_value = -infty; + + for (action_node_t *node = list->head; node != NULL; node = node->next) { + negamax_display_progress(cur_depth, init_depth, list->length); + + action_take(state, node->action); + + // Compute the value of the node + float node_value; + if (state->ply >= 2 * state->board_size - 2 && + (w = check_win(state)) < 0xFF) { + node_value = -colour * infty; + // Check win if far enough into the game + if (w == WIN_ROAD_BLACK || w == WIN_FLAT_BLACK) { + node_value = colour * infty; + } else if (w == WIN_DRAW) { + node_value = 0; + } + } else if (cur_depth > 1) { + // If nobody won, or too early and not leaf, recurse + node_value = -negamax(state, cur_depth - 1, init_depth, -beta, -alpha, + -colour, zobrist_compute(state)); + } else { + node_value = colour * nn1986_evaluate_black_win(state); } + action_undo(state, node->action); - action_list_free(list); - if (cur_depth == init_depth) negamax_best_action = best_action; - - flag = TT_EXACT; - if (best_value >= beta) flag = TT_LOWERBOUND; - else if (best_value <= alpha) flag = TT_UPPERBOUND; - - if (entry == NULL) { - tt_insert(hash, flag, cur_depth, best_value, best_action); - } else { - entry->flag = flag; - entry->value = best_value; - entry->depth = cur_depth; - entry->action = best_action; + if (node_value > best_value) { + best_value = node_value; + best_action = node->action; } - return best_value; + if (best_value > alpha) + alpha = best_value; + if (alpha >= beta) + break; + } + + action_list_free(list); + if (cur_depth == init_depth) + negamax_best_action = best_action; + + flag = TT_EXACT; + if (best_value >= beta) + flag = TT_LOWERBOUND; + else if (best_value <= alpha) + flag = TT_UPPERBOUND; + + if (entry == NULL) { + tt_insert(hash, flag, cur_depth, best_value, best_action); + } else { + entry->flag = flag; + entry->value = best_value; + entry->depth = cur_depth; + entry->action = best_action; + } + + return best_value; } diff --git a/include/negamax.h b/include/negamax.h index e491baa..eedb7dd 100644 --- a/include/negamax.h +++ b/include/negamax.h @@ -15,12 +15,12 @@ along with ct. If not, see <https://www.gnu.org/licenses/>. */ -#include <stdint.h> #include <math.h> +#include <stdint.h> -#include <tak.h> #include <actions.h> #include <nn1986.h> +#include <tak.h> #include <tt_llcht.h> #include <zobrist.h> @@ -33,8 +33,8 @@ extern char negamax_ptn[9]; extern uint8_t negamax_search_depth; extern void negamax_display_progress(const uint8_t cur_depth, - const uint8_t init_depth, - const uint32_t length); + const uint8_t init_depth, + const uint32_t length); // =================================================================== // Methods @@ -50,4 +50,4 @@ void negamax_free(void); * `negamax_ptn', and return its value. The `negamax_display_progress' * function is called on every new square at the top level. */ -float negamax_generate(void); +float negamax_generate(tak_state_p state); diff --git a/include/nn1986.c b/include/nn1986.c index b9c551c..117a034 100644 --- a/include/nn1986.c +++ b/include/nn1986.c @@ -28,22 +28,22 @@ static float dense1[DENSE_NUM]; static float output[2]; #define RELU(x) ((x) = ((x) < 0) ? 0 : (x)) -float nn1986_evaluate_black_win(void) { +float nn1986_evaluate_black_win(tak_state_p state) { /* --------------- * * Populate input * * --------------- */ - for (unsigned int y = 0; y < board_size; y++) { - for (unsigned int x = 0; x < board_size; x++) { - const unsigned int loc = x + y * board_size; - const unsigned int count = COUNT_AT(loc); + for (unsigned int y = 0; y < state->board_size; y++) { + for (unsigned int x = 0; x < state->board_size; x++) { + const unsigned int loc = x + y * state->board_size; + const unsigned int count = COUNT_AT(state, loc); float lookup = 0; if (count > 0) { - if (STONE_AT(loc) == STONE_STANDING) { - lookup = (colours[loc] & 1) ? +0.25 : -0.25; - } else if (STONE_AT(loc) == STONE_CAPSTONE) { - lookup = (colours[loc] & 1) ? +1.00 : -1.00; + if (STONE_AT(state, loc) == STONE_STANDING) { + lookup = (state->colours[loc] & 1) ? +0.25 : -0.25; + } else if (STONE_AT(state, loc) == STONE_CAPSTONE) { + lookup = (state->colours[loc] & 1) ? +1.00 : -1.00; } else { - lookup = (colours[loc] & 1) ? +0.50 : -0.50; + lookup = (state->colours[loc] & 1) ? +0.50 : -0.50; } } cur_board[3 + loc] = lookup; @@ -53,9 +53,9 @@ float nn1986_evaluate_black_win(void) { * Convolution layer * * ------------------ */ // Add input of flat counts and ply parity - cur_board[0] = (ply & 1) ? 1 : -1; - cur_board[1] = (float)(white_count & 127) / 21.0; - cur_board[2] = (float)(black_count & 127) / 21.0; + cur_board[0] = (state->ply & 1) ? 1 : -1; + cur_board[1] = (float)(state->white_count & 127) / 21.0; + cur_board[2] = (float)(state->black_count & 127) / 21.0; /* ------------------ * * First dense layer * * ------------------ */ diff --git a/include/nn1986.h b/include/nn1986.h index 4e99ac2..02dca0e 100644 --- a/include/nn1986.h +++ b/include/nn1986.h @@ -17,4 +17,4 @@ #include <tak.h> -float nn1986_evaluate_black_win(void); +float nn1986_evaluate_black_win(tak_state_p state); diff --git a/include/tak.c b/include/tak.c index 5fd8e9a..a5f2f44 100644 --- a/include/tak.c +++ b/include/tak.c @@ -16,57 +16,55 @@ */ #include "tak.h" +#include <stdlib.h> // =================================================================== -// Globals +// Helpers // =================================================================== -enum WIN_TYPE won; -uint8_t board_size; -data_t celldat[36]; -colour_stack_t colours[36]; -enum COLOUR current_colour; -uint8_t white_count, black_count, ply; +#define NUM_SQUARES(board_size) (board_size * board_size) -// =================================================================== -// Helpers -// =================================================================== +tak_state_p new_tak_state(const uint8_t board_size) { + tak_state_p state = malloc(sizeof(struct tak_state_s)); + reset_state(state, board_size); + return state; +} -#define NUM_SQUARES (board_size * board_size) +void free_tak_state(tak_state_p state) { free(state); } // =================================================================== // General state stuff // =================================================================== -void -reset_state(const uint8_t new_board_size) { +void reset_state(tak_state_p state, const uint8_t new_board_size) { if (new_board_size == 6) { - board_size = 6; - white_count = 128 | 30; - black_count = 128 | 30; + state->board_size = 6; + state->white_count = 128 | 30; + state->black_count = 128 | 30; } else { - board_size = 5; - white_count = 128 | 21; - black_count = 128 | 21; + state->board_size = 5; + state->white_count = 128 | 21; + state->black_count = 128 | 21; } - ply = 0; - won = 0xFF; // i may live to regret this hack - current_colour = C_BLACK; + state->ply = 0; + state->won = 0xFF; // i may live to regret this hack + state->current_colour = C_BLACK; - for (uint8_t k = 0; k < NUM_SQUARES; k++ ) { - celldat[k] = 0; + for (uint8_t k = 0; k < NUM_SQUARES(new_board_size); k++) { + state->celldat[k] = 0; } } -void -next_ply(void) { - ply++; - if (ply == 2) { - current_colour = C_WHITE; +void next_ply(tak_state_p state) { + state->ply++; + if (state->ply == 2) { + state->current_colour = C_WHITE; } else { - if (current_colour == C_BLACK) current_colour = C_WHITE; - else current_colour = C_BLACK; + if (state->current_colour == C_BLACK) + state->current_colour = C_WHITE; + else + state->current_colour = C_BLACK; } } @@ -74,47 +72,57 @@ next_ply(void) { // Placing stones // =================================================================== -enum ACT_RESULT -try_place(const int8_t location, const enum COLOUR colour, - const enum STONE_VARIANT stone) -{ +enum ACT_RESULT try_place(tak_state_p state, const int8_t location, + const enum COLOUR colour, + const enum STONE_VARIANT stone) { // Game is over? - if (won < 0xFF) return GAME_END; + if (state->won < 0xFF) + return GAME_END; // Can't place on an occupied square - if (COUNT_AT(location)) { + if (COUNT_AT(state, location)) { return ACT_ILLEGAL; } else { switch (stone) { - case STONE_STANDING: - if (ply < 2) return ACT_ILLEGAL; - // behold the magic GCC comment which defeates - // -Wimplicit-fallthrough: - // fall through - case STONE_FLAT: { - if (colour == C_BLACK) { - if (black_count & 127) black_count--; - else return ACT_ILLEGAL; - } else { - if (white_count & 127) white_count--; - else return ACT_ILLEGAL; - } - break; + case STONE_STANDING: + if (state->ply < 2) + return ACT_ILLEGAL; + // behold the magic GCC comment which defeates + // -Wimplicit-fallthrough: + // fall through + case STONE_FLAT: { + if (colour == C_BLACK) { + if (state->black_count & 127) + state->black_count--; + else + return ACT_ILLEGAL; + } else { + if (state->white_count & 127) + state->white_count--; + else + return ACT_ILLEGAL; } - case STONE_CAPSTONE: { - if (ply < 2) return ACT_ILLEGAL; - if (colour == C_BLACK) { - if (black_count & 128) black_count &= 127; - else return ACT_ILLEGAL; - } else { - if (white_count & 128) white_count &= 127; - else return ACT_ILLEGAL; - } - break; + break; + } + case STONE_CAPSTONE: { + if (state->ply < 2) + return ACT_ILLEGAL; + if (colour == C_BLACK) { + if (state->black_count & 128) + state->black_count &= 127; + else + return ACT_ILLEGAL; + } else { + if (state->white_count & 128) + state->white_count &= 127; + else + return ACT_ILLEGAL; } + break; + } } - colours[location] = colour; - celldat[location] = NUM_INC | stone; + state->colours[location] = colour; + state->celldat[location] = NUM_INC | stone; return ACT_OK; } } @@ -123,59 +131,63 @@ try_place(const int8_t location, const enum COLOUR colour, // Moving stacks // =================================================================== -static inline void -push_stones(const int8_t location, const uint8_t count, - const uint8_t new_colours, - const enum STONE_VARIANT top_stone) { - colours[location] = (colours[location] << count) | new_colours; - celldat[location] = top_stone - | ((celldat[location] + ((count << NUM_SHIFT))) & NUM_MASK); +static inline void push_stones(tak_state_p state, const int8_t location, + const uint8_t count, const uint8_t new_colours, + const enum STONE_VARIANT top_stone) { + state->colours[location] = (state->colours[location] << count) | new_colours; + state->celldat[location] = + top_stone | + ((state->celldat[location] + ((count << NUM_SHIFT))) & NUM_MASK); } -enum ACT_RESULT -try_move(const int8_t location, const enum MOVE_DIRECTION direction, - const uint8_t steps, const uint8_t drops[5]) { +enum ACT_RESULT try_move(tak_state_p state, const int8_t location, + const enum MOVE_DIRECTION direction, + const uint8_t steps, const uint8_t drops[5]) { // Game is over? - if (won < 0xFF) return GAME_END; + if (state->won < 0xFF) + return GAME_END; // Can't do this - if (steps == 0 || steps > board_size) return ACT_ILLEGAL; + if (steps == 0 || steps > state->board_size) + return ACT_ILLEGAL; // Check for stones at all - const uint8_t avail = COUNT_AT(location); - if (avail == 0) return ACT_ILLEGAL; + const uint8_t avail = COUNT_AT(state, location); + if (avail == 0) + return ACT_ILLEGAL; // Does the current player own the pile? - if ((colours[location] & 1) != current_colour) return ACT_ILLEGAL; + if ((state->colours[location] & 1) != state->current_colour) + return ACT_ILLEGAL; // Is the desired direction and count on the board? int8_t delta = 0; switch (direction) { - case M_UP: { - delta = +board_size; - if (location + delta * steps > NUM_SQUARES) - return ACT_ILLEGAL; - break; - }; - case M_DOWN: { - delta = -board_size; - if (location + delta * steps < 0) - return ACT_ILLEGAL; - break; - }; - case M_RIGHT: { - delta = +1; - if ((location + steps * delta) / board_size - > location / board_size) - return ACT_ILLEGAL; - break; - }; - case M_LEFT: { - delta = -1; - // We need the extra check for zero here because, irritatingly, - // -1 / board_size == 1 / board_size - if ((location + steps * delta < 0) || - ((location + steps * delta) / board_size - < location / board_size)) - return ACT_ILLEGAL; - break; - }; + case M_UP: { + delta = +state->board_size; + if (location + delta * steps > NUM_SQUARES(state->board_size)) + return ACT_ILLEGAL; + break; + }; + case M_DOWN: { + delta = -state->board_size; + if (location + delta * steps < 0) + return ACT_ILLEGAL; + break; + }; + case M_RIGHT: { + delta = +1; + if ((location + steps * delta) / state->board_size > + location / state->board_size) + return ACT_ILLEGAL; + break; + }; + case M_LEFT: { + delta = -1; + // We need the extra check for zero here because, irritatingly, + // -1 / board_size == 1 / board_size + if ((location + steps * delta < 0) || + ((location + steps * delta) / state->board_size < + location / state->board_size)) + return ACT_ILLEGAL; + break; + }; }; // For every square in the direction @@ -185,27 +197,25 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction, if (drops[k] == 0) return ACT_ILLEGAL; // Can't drop more than BOARD_SIZE stones in a square - if (drops[k] > board_size) + if (drops[k] > state->board_size) return ACT_ILLEGAL; // Check for overflows - if (COUNT_AT(location+(k+1)*delta) + drops[k] > 0x0F) + if (COUNT_AT(state, location + (k + 1) * delta) + drops[k] > 0x0F) return ACT_OVERFLOW; // Check for capstone - if (STONE_AT(location+(k+1)*delta) == STONE_CAPSTONE) + if (STONE_AT(state, location + (k + 1) * delta) == STONE_CAPSTONE) return ACT_ILLEGAL; // Check for wall - if ( (STONE_AT(location+(k+1)*delta) == STONE_STANDING) - // If not last drop, or not dropping just one, or not a cap - && ( (k+1 < steps) - || (drops[k] != 1) - || (STONE_AT(location) != STONE_CAPSTONE) ) - ) + if ((STONE_AT(state, location + (k + 1) * delta) == STONE_STANDING) + // If not last drop, or not dropping just one, or not a cap + && ((k + 1 < steps) || (drops[k] != 1) || + (STONE_AT(state, location) != STONE_CAPSTONE))) return ACT_ILLEGAL; total += drops[k]; } // Can't ask to move 0, more than board_size, or stones available - if ( (total == 0) || (total > board_size) || (total > avail) ) + if ((total == 0) || (total > state->board_size) || (total > avail)) return ACT_ILLEGAL; // Nothing illegal, do it. First we add the stones to the @@ -213,15 +223,14 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction, uint8_t j = total; for (uint8_t k = 0; k < steps; k++) { j -= drops[k]; - push_stones(location+(k+1)*delta, - drops[k], - (colours[location] >> j) & (0xFFFF >> (0x10 - drops[k])), - (k == steps - 1) ? STONE_AT(location) : STONE_FLAT); + push_stones(state, location + (k + 1) * delta, drops[k], + (state->colours[location] >> j) & (0xFFFF >> (0x10 - drops[k])), + (k == steps - 1) ? STONE_AT(state, location) : STONE_FLAT); } // Then we drop them from the source - colours[location] >>= total; - const uint8_t dec_count = celldat[location] - (total << NUM_SHIFT); - celldat[location] = dec_count & NUM_MASK; + state->colours[location] >>= total; + const uint8_t dec_count = state->celldat[location] - (total << NUM_SHIFT); + state->celldat[location] = dec_count & NUM_MASK; return ACT_OK; } @@ -231,9 +240,10 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction, // =================================================================== // Check for the presence of a road connecting opposite sides -static enum WIN_TYPE -check_road_colour(const enum COLOUR colour) { - int component[NUM_SQUARES], touching[NUM_SQUARES]; +static enum WIN_TYPE check_road_colour(tak_state_p state, + const enum COLOUR colour) { + int component[NUM_SQUARES(state->board_size)], + touching[NUM_SQUARES(state->board_size)]; /* We're doing a poor version of a disjoint set data structure to @@ -249,10 +259,10 @@ check_road_colour(const enum COLOUR colour) { the same reason we also don't do path flattening/halving or anything. */ - for (int k=0; k<NUM_SQUARES; k++) { + for (int k = 0; k < NUM_SQUARES(state->board_size); k++) { component[k] = k; // every square is in its own connected // component initially - touching[k] = 0; // and not connected to any sides + touching[k] = 0; // and not connected to any sides } // touching is the bit mask for connectivity, @@ -260,90 +270,95 @@ check_road_colour(const enum COLOUR colour) { // 1 2 4 8 int touch = 5; - for (int row = 0; row < board_size; row++) { - for (int col = 0; col < board_size; col++) { - const int cur = THE_COORDS(col, row); - if (COUNT_AT(cur) - && (colours[cur] & 1) == colour - && STONE_AT(cur) != STONE_STANDING) { - - // do we have any neighbours to the left and below? - const int left_neighbour = ((cur % board_size > 0) - && (COUNT_AT(cur - 1)) // wont ever be out of bounds - && ((colours[cur - 1] & 1) == colour) - && (STONE_AT(cur - 1) != STONE_STANDING)); - - const int lowr_neighbour = ((cur >= board_size) - && (COUNT_AT(cur - board_size)) - && ((colours[cur - board_size] & 1) == colour) - && (STONE_AT(cur - board_size) != STONE_STANDING)); - - // always take the component of the lower neighbour if - // possible, failing that take the left neighbour, otherwise - // we're not yet connected, so update our own component. - if (lowr_neighbour) { - // look up the root of the lower neighbour - int root = cur - board_size; - while (root != component[root]) - root = component[root]; - // join the set - component[cur] = root; - if (touch) { - // something new - touching[root] |= touch; - // are we done? - if ( (touching[root] & 0x3) == 0x3 || (touching[root] & 0xC) == 0xC) - return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; - } - // if we also have a left neighbour then we should `merge' - // sets, and here we assume that the left neighbour set is - // always smaller (may not be) for the direction of merge - if (left_neighbour) { - int left_root = cur - 1; - while (left_root != component[left_root]) - left_root = component[left_root]; - // merge - const int left_touch = touching[left_root]; - if (left_touch) { - touching[root] |= left_touch; - if ( (touching[root] & 0x3) == 0x3 || (touching[root] & 0xC) == 0xC) - return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; - } - component[left_root] = root; - } - } else if (left_neighbour) { - int root = cur - 1; - while (root != component[root]) - root = component[root]; - component[cur] = root; - if (touch) { - touching[root] |= touch; - if ( (touching[root] & 0x3) == 0x3 || (touching[root] & 0xC) == 0xC) - return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; - } - } else if (touch) { - // we had no left or lower neighbour, so we're on our own - touching[cur] = touch; - } + for (int row = 0; row < state->board_size; row++) { + for (int col = 0; col < state->board_size; col++) { + const int cur = THE_COORDS(state->board_size, col, row); + if (COUNT_AT(state, cur) && (state->colours[cur] & 1) == colour && + STONE_AT(state, cur) != STONE_STANDING) { + + // do we have any neighbours to the left and below? + const int left_neighbour = + ((cur % state->board_size > 0) && + (COUNT_AT(state, cur - 1)) // wont ever be out of bounds + && ((state->colours[cur - 1] & 1) == colour) && + (STONE_AT(state, cur - 1) != STONE_STANDING)); + + const int lowr_neighbour = + ((cur >= state->board_size) && + (COUNT_AT(state, cur - state->board_size)) && + ((state->colours[cur - state->board_size] & 1) == colour) && + (STONE_AT(state, cur - state->board_size) != STONE_STANDING)); + + // always take the component of the lower neighbour if + // possible, failing that take the left neighbour, otherwise + // we're not yet connected, so update our own component. + if (lowr_neighbour) { + // look up the root of the lower neighbour + int root = cur - state->board_size; + while (root != component[root]) + root = component[root]; + // join the set + component[cur] = root; + if (touch) { + // something new + touching[root] |= touch; + // are we done? + if ((touching[root] & 0x3) == 0x3 || (touching[root] & 0xC) == 0xC) + return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; + } + // if we also have a left neighbour then we should `merge' + // sets, and here we assume that the left neighbour set is + // always smaller (may not be) for the direction of merge + if (left_neighbour) { + int left_root = cur - 1; + while (left_root != component[left_root]) + left_root = component[left_root]; + // merge + const int left_touch = touching[left_root]; + if (left_touch) { + touching[root] |= left_touch; + if ((touching[root] & 0x3) == 0x3 || + (touching[root] & 0xC) == 0xC) + return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; + } + component[left_root] = root; + } + } else if (left_neighbour) { + int root = cur - 1; + while (root != component[root]) + root = component[root]; + component[cur] = root; + if (touch) { + touching[root] |= touch; + if ((touching[root] & 0x3) == 0x3 || (touching[root] & 0xC) == 0xC) + return (colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE; + } + } else if (touch) { + // we had no left or lower neighbour, so we're on our own + touching[cur] = touch; + } } - if (col + 2 == board_size) touch |= 8; - else touch &= 0x3; + if (col + 2 == state->board_size) + touch |= 8; + else + touch &= 0x3; } - if (row + 2 == board_size) touch = 6; - else touch = 4; + if (row + 2 == state->board_size) + touch = 6; + else + touch = 4; } return 0xFF; } -enum WIN_TYPE -check_win(void) { +enum WIN_TYPE check_win(tak_state_p state) { // Road? enum WIN_TYPE rb, rw; - rb = check_road_colour(C_BLACK); - rw = check_road_colour(C_WHITE); + rb = check_road_colour(state, C_BLACK); + rw = check_road_colour(state, C_WHITE); if (rb == WIN_ROAD_BLACK && rw == WIN_ROAD_WHITE) { - return (ply & 1) ? rb : rw; // Dragons + return (state->ply & 1) ? rb : rw; // Dragons } else if (rw == WIN_ROAD_WHITE) { return rw; } else if (rb == WIN_ROAD_BLACK) { @@ -352,18 +367,21 @@ check_win(void) { // Do we do a flat count? int8_t total = 0, board_full = 1; - for (uint8_t k = 0; k < NUM_SQUARES; k++) { - if (COUNT_AT(k) == 0) { + for (uint8_t k = 0; k < NUM_SQUARES(state->board_size); k++) { + if (COUNT_AT(state, k) == 0) { board_full = 0; - } else if (STONE_AT(k) == STONE_FLAT) { - total += ((colours[k] & 1) == C_BLACK) ? +1 : -1 ; + } else if (STONE_AT(state, k) == STONE_FLAT) { + total += ((state->colours[k] & 1) == C_BLACK) ? +1 : -1; } } - if (black_count == 0 || white_count == 0 || board_full) { + if (state->black_count == 0 || state->white_count == 0 || board_full) { // Decide based on count - if (total > 0) return WIN_FLAT_BLACK; - else if (total < 0) return WIN_FLAT_WHITE; - else return WIN_DRAW; + if (total > 0) + return WIN_FLAT_BLACK; + else if (total < 0) + return WIN_FLAT_WHITE; + else + return WIN_DRAW; } return 0xFF; @@ -372,38 +390,57 @@ check_win(void) { // PTN place parser // =================================================================== -#define NULL 0 - -#define ASSERT_NONEMPTY { \ - if (ptn == NULL || *ptn == 0) return PTN_INVALID; \ +#define ASSERT_NONEMPTY \ + { \ + if (ptn == NULL || *ptn == 0) \ + return PTN_INVALID; \ } -#define ASSERT_MORE { if (*ptn == 0) return PTN_INVALID; } +#define ASSERT_MORE \ + { \ + if (*ptn == 0) \ + return PTN_INVALID; \ + } -enum PTN_RESULT -parse_place(char *ptn, uint8_t *out_location, - enum STONE_VARIANT *out_stone) { +enum PTN_RESULT parse_place(const uint8_t board_size, char *ptn, + uint8_t *out_location, + enum STONE_VARIANT *out_stone) { ASSERT_NONEMPTY; *out_stone = STONE_FLAT; switch (*ptn) { - case 'C' : { ptn++; *out_stone = STONE_CAPSTONE; break; }; - case 'S' : { ptn++; *out_stone = STONE_STANDING; break; }; - case 'F' : { ptn++; break; }; + case 'C': { + ptn++; + *out_stone = STONE_CAPSTONE; + break; + }; + case 'S': { + ptn++; + *out_stone = STONE_STANDING; + break; + }; + case 'F': { + ptn++; + break; + }; } ASSERT_MORE; - if ( (*ptn < 'a') || (*ptn > '`' + board_size) ) return PTN_INVALID; + if ((*ptn < 'a') || (*ptn > '`' + board_size)) + return PTN_INVALID; *out_location = *ptn - 'a'; - ptn++; ASSERT_MORE; + ptn++; + ASSERT_MORE; - if ( (*ptn < '1') || (*ptn > board_size + '0') ) return PTN_INVALID; + if ((*ptn < '1') || (*ptn > board_size + '0')) + return PTN_INVALID; *out_location += board_size * (*ptn - '1'); - if (*(++ptn) > 0) return PTN_INVALID; + if (*(++ptn) > 0) + return PTN_INVALID; return PTN_OK; } @@ -412,40 +449,58 @@ parse_place(char *ptn, uint8_t *out_location, // PTN move parser // =================================================================== -enum PTN_RESULT -parse_move(char *ptn, uint8_t *out_location, - enum MOVE_DIRECTION *out_direction, - uint8_t *out_steps, uint8_t out_drops[5]) { +enum PTN_RESULT parse_move(const uint8_t board_size, char *ptn, + uint8_t *out_location, + enum MOVE_DIRECTION *out_direction, + uint8_t *out_steps, uint8_t out_drops[5]) { ASSERT_NONEMPTY; uint8_t picked_up = 1; // Optionally indicate how many stones picked up - if ( (*ptn >= '1') && (*ptn <= '0' + board_size)) { + if ((*ptn >= '1') && (*ptn <= '0' + board_size)) { picked_up = *ptn - '0'; - ptn++; ASSERT_MORE; + ptn++; + ASSERT_MORE; } // column must be on the board - if ( (*ptn < 'a') || (*ptn > '`' + board_size) ) return PTN_INVALID; + if ((*ptn < 'a') || (*ptn > '`' + board_size)) + return PTN_INVALID; *out_location = *ptn - 'a'; - ptn++; ASSERT_MORE; + ptn++; + ASSERT_MORE; // row must be on the board - if ( (*ptn < '1') || (*ptn > board_size + '0') ) return PTN_INVALID; + if ((*ptn < '1') || (*ptn > board_size + '0')) + return PTN_INVALID; *out_location += board_size * (*ptn - '1'); - ptn++; ASSERT_MORE; + ptn++; + ASSERT_MORE; // valid direction switch (*ptn) { - case '+': { *out_direction = M_UP; break; } - case '-': { *out_direction = M_DOWN; break; } - case '<': { *out_direction = M_LEFT; break; } - case '>': { *out_direction = M_RIGHT; break; } - default: return PTN_INVALID; + case '+': { + *out_direction = M_UP; + break; + } + case '-': { + *out_direction = M_DOWN; + break; + } + case '<': { + *out_direction = M_LEFT; + break; + } + case '>': { + *out_direction = M_RIGHT; + break; + } + default: + return PTN_INVALID; } // Handle the case 'n<column><row><direction>' as @@ -463,11 +518,11 @@ parse_move(char *ptn, uint8_t *out_location, uint8_t total = 0; while (*ptn) { // can't drop more than the carry limit, or less than 1 - if ( (*ptn < '1') || (*ptn > '0' + board_size) ) + if ((*ptn < '1') || (*ptn > '0' + board_size)) return PTN_INVALID; // can't move more than the size of the board in any direction - if ( (*out_steps + 1 >= board_size) && *ptn) + if ((*out_steps + 1 >= board_size) && *ptn) return PTN_INVALID; out_drops[*out_steps] = *ptn - '0'; @@ -477,7 +532,8 @@ parse_move(char *ptn, uint8_t *out_location, } // Mismatch between number of stones picked up and total dropped - if ( total != picked_up ) return PTN_INVALID; + if (total != picked_up) + return PTN_INVALID; return PTN_OK; } @@ -486,16 +542,27 @@ parse_move(char *ptn, uint8_t *out_location, // Generate PTN for place // =================================================================== -void -generate_place(const uint8_t in_location, - const enum STONE_VARIANT in_stone, char out_ptn[4]) { +void generate_place(const uint8_t board_size, const uint8_t in_location, + const enum STONE_VARIANT in_stone, char out_ptn[4]) { switch (in_stone) { - case STONE_FLAT: { break; } - case STONE_STANDING: { *out_ptn = 'S'; out_ptn++; break; } - case STONE_CAPSTONE: { *out_ptn = 'C'; out_ptn++; break; } + case STONE_FLAT: { + break; + } + case STONE_STANDING: { + *out_ptn = 'S'; + out_ptn++; + break; + } + case STONE_CAPSTONE: { + *out_ptn = 'C'; + out_ptn++; + break; } - *out_ptn = 'a' + (in_location % board_size); out_ptn++; - *out_ptn = '1' + (in_location / board_size); out_ptn++; + } + *out_ptn = 'a' + (in_location % board_size); + out_ptn++; + *out_ptn = '1' + (in_location / board_size); + out_ptn++; *out_ptn = 0; } @@ -503,29 +570,46 @@ generate_place(const uint8_t in_location, // Generate PTN for move // =================================================================== -void -generate_move(const uint8_t in_location, - const enum MOVE_DIRECTION in_direction, - const uint8_t in_steps, const uint8_t in_drops[5], - char out_ptn[10]) { +void generate_move(const uint8_t board_size, const uint8_t in_location, + const enum MOVE_DIRECTION in_direction, + const uint8_t in_steps, const uint8_t in_drops[5], + char out_ptn[10]) { uint8_t total = 0; - for (uint8_t k = 0; k<in_steps; k++) total+=in_drops[k]; + for (uint8_t k = 0; k < in_steps; k++) + total += in_drops[k]; if (total > 1) { - *out_ptn = '0' + total; out_ptn++; + *out_ptn = '0' + total; + out_ptn++; } - *out_ptn = 'a' + (in_location % board_size); out_ptn++; - *out_ptn = '1' + (in_location / board_size); out_ptn++; + *out_ptn = 'a' + (in_location % board_size); + out_ptn++; + *out_ptn = '1' + (in_location / board_size); + out_ptn++; switch (in_direction) { - case M_UP: { *out_ptn = '+'; break; } - case M_DOWN: { *out_ptn = '-'; break; } - case M_LEFT: { *out_ptn = '<'; break; } - case M_RIGHT: { *out_ptn = '>'; break; } - }; out_ptn++; + case M_UP: { + *out_ptn = '+'; + break; + } + case M_DOWN: { + *out_ptn = '-'; + break; + } + case M_LEFT: { + *out_ptn = '<'; + break; + } + case M_RIGHT: { + *out_ptn = '>'; + break; + } + }; + out_ptn++; for (uint8_t k = 0; (total > 1) && (k < in_steps); k++) { - *out_ptn = '0' + in_drops[k]; out_ptn++; + *out_ptn = '0' + in_drops[k]; + out_ptn++; } *out_ptn = 0; @@ -535,24 +619,26 @@ generate_move(const uint8_t in_location, // Driver // =================================================================== -static uint8_t -is_not_placement(char *ptn) { - if (ptn == 0) return 0; - for (;;ptn++) { +static uint8_t is_not_placement(char *ptn) { + if (ptn == 0) + return 0; + for (;; ptn++) { switch (*ptn) { - case '+': - case '-': - case '>': - case '<': return 1; - case 0: return 0; + case '+': + case '-': + case '>': + case '<': + return 1; + case 0: + return 0; } } } -enum ACT_RESULT -do_ptn(char *ptn) { +enum ACT_RESULT do_ptn(tak_state_p state, char *ptn) { // Game over? - if (won < 0xFF) return GAME_END; + if (state->won < 0xFF) + return GAME_END; enum PTN_RESULT ptn_res; enum ACT_RESULT act_res; @@ -563,11 +649,13 @@ do_ptn(char *ptn) { uint8_t steps, drops[5]; enum MOVE_DIRECTION direction; // Parse it as a move - ptn_res = parse_move(ptn, &location, &direction, &steps, drops); + ptn_res = parse_move(state->board_size, ptn, &location, &direction, &steps, + drops); // If valid PTN, try to do it if (ptn_res == PTN_OK) { - if (ply < 2) return ACT_ILLEGAL; - act_res = try_move(location, direction, steps, drops); + if (state->ply < 2) + return ACT_ILLEGAL; + act_res = try_move(state, location, direction, steps, drops); } else { return ACT_INVALID_PTN; } @@ -575,10 +663,10 @@ do_ptn(char *ptn) { // It was not a move enum STONE_VARIANT stone; // Was it a valid placement? - ptn_res = parse_place(ptn, &location, &stone); + ptn_res = parse_place(state->board_size, ptn, &location, &stone); // If so, try it if (ptn_res == PTN_OK) - act_res = try_place(location, current_colour, stone); + act_res = try_place(state, location, state->current_colour, stone); else return ACT_INVALID_PTN; } @@ -586,16 +674,16 @@ do_ptn(char *ptn) { if (act_res == ACT_OK) { // Don't bother checking that the game was won early on, could be // more conservative here :) - if (ply >= board_size) { - won = check_win(); - if (won < 0xFF) { - // Winning move, but no need to update current colour - ply++; - return GAME_END; + if (state->ply >= state->board_size) { + state->won = check_win(state); + if (state->won < 0xFF) { + // Winning move, but no need to update current colour + state->ply++; + return GAME_END; } } // Only step if the game isn't over yet - next_ply(); + next_ply(state); } return act_res; } diff --git a/include/tak.h b/include/tak.h index 26f4ae6..9f458f6 100644 --- a/include/tak.h +++ b/include/tak.h @@ -49,60 +49,61 @@ enum WIN_TYPE { typedef uint8_t data_t; typedef uint16_t colour_stack_t; +typedef struct tak_state_s { + data_t celldat[36]; + colour_stack_t colours[36]; + enum WIN_TYPE won; + enum COLOUR current_colour; + uint8_t white_count, black_count, ply, board_size; +} * tak_state_p; + #define NUM_SHIFT 4 #define NUM_MASK (0xF << NUM_SHIFT) // 0b11110000 #define NUM_INC (0x1 << NUM_SHIFT) // 0b00010000 #define STONE_MASK 3 // 0b00000011 -#define STONE_AT(l) (celldat[(l)] & STONE_MASK) -#define COUNT_AT(l) (celldat[(l)] >> NUM_SHIFT) -#define THE_COORDS(col, row) ((col) + (row)*board_size) - -// =================================================================== -// Variables -// =================================================================== - -// NOTE: We only support one capstone per player and 5s or 6s games. - -extern enum WIN_TYPE won; -extern uint8_t board_size; -extern data_t celldat[36]; -extern colour_stack_t colours[36]; -extern enum COLOUR current_colour; -extern uint8_t white_count, black_count, ply; +#define STONE_AT(state, l) (state->celldat[(l)] & STONE_MASK) +#define COUNT_AT(state, l) (state->celldat[(l)] >> NUM_SHIFT) +#define THE_COORDS(board_size, col, row) ((col) + (row)*board_size) // =================================================================== // Methods // =================================================================== +tak_state_p new_tak_state(const uint8_t board_size); +void free_tak_state(tak_state_p state); + // ------------------------------------------------------------------- // Game state -void reset_state(const uint8_t new_board_size); -void next_ply(void); +void reset_state(tak_state_p state, const uint8_t new_board_size); +void next_ply(tak_state_p state); -enum ACT_RESULT try_place(const int8_t location, const enum COLOUR colour, +enum ACT_RESULT try_place(tak_state_p state, const int8_t location, + const enum COLOUR colour, const enum STONE_VARIANT stone); -enum ACT_RESULT try_move(const int8_t location, +enum ACT_RESULT try_move(tak_state_p state, const int8_t location, const enum MOVE_DIRECTION direction, const uint8_t steps, const uint8_t drops[5]); -enum WIN_TYPE check_win(void); +enum WIN_TYPE check_win(tak_state_p state); // ------------------------------------------------------------------- // PTN related -enum PTN_RESULT parse_place(char *in_ptn, uint8_t *out_location, +enum PTN_RESULT parse_place(const uint8_t board_size, char *in_ptn, + uint8_t *out_location, enum STONE_VARIANT *out_stone); -enum PTN_RESULT parse_move(char *in_ptn, uint8_t *out_location, +enum PTN_RESULT parse_move(const uint8_t board_size, char *in_ptn, + uint8_t *out_location, enum MOVE_DIRECTION *out_direction, uint8_t *out_steps, uint8_t out_drops[5]); -void generate_place(const uint8_t in_location, +void generate_place(const uint8_t board_size, const uint8_t in_location, const enum STONE_VARIANT in_stone, char out_ptn[4]); -void generate_move(const uint8_t in_location, +void generate_move(const uint8_t board_size, const uint8_t in_location, const enum MOVE_DIRECTION in_direction, const uint8_t in_steps, const uint8_t in_drops[5], char out_ptn[10]); @@ -110,5 +111,5 @@ void generate_move(const uint8_t in_location, // ------------------------------------------------------------------- // Game driver -enum ACT_RESULT do_ptn(char *ptn); +enum ACT_RESULT do_ptn(tak_state_p state, char *ptn); #endif diff --git a/include/tps.c b/include/tps.c index 7be0e8d..ad0fe21 100644 --- a/include/tps.c +++ b/include/tps.c @@ -4,134 +4,166 @@ // Load TPS string // =================================================================== -#define TPS_ASSERT_MORE { if (*tps == 0) return TPS_INVALID; } +#define TPS_ASSERT_MORE \ + { \ + if (*tps == 0) \ + return TPS_INVALID; \ + } -enum TPS_RESULT -load_tps(char* tps) { +enum TPS_RESULT load_tps(tak_state_p state, char *tps) { // TODO: Ensure NULL termination? - if (tps == NULL) return TPS_INVALID; + if (tps == NULL) + return TPS_INVALID; uint8_t prefix = 0; // Check if we're likely of the form [TPS "blah"] if (!strncmp(tps, "[TPS \"", 6)) { - prefix=1; + prefix = 1; // Now we can worry about just the TPS part tps += 6; } // Reset everything - reset_state(board_size); + reset_state(state, state->board_size); // Parse squares, NOTE: We assume that board_size matches TPS size. - int col = 0, row = board_size-1, skip, parsing = 1; + int col = 0, row = state->board_size - 1, skip, parsing = 1; while (parsing) { switch (*tps) { - case ' ': { - // we're done - parsing = 0; - tps++; TPS_ASSERT_MORE; - break; - } - case 'x': { - // empty squares - tps++; TPS_ASSERT_MORE; - skip = 0; - if (*tps >= '2' && *tps <= '0'+board_size) { - skip = *tps - '1'; - tps++; TPS_ASSERT_MORE; - } else if (*tps != ',' && *tps != '/' && *tps != ' ') { - return TPS_INVALID; - } - col += skip; - if (col >= board_size + 1) return TPS_INVALID; - break; - } - case '/': { - // next row - if (col + 1 != board_size) return TPS_INVALID; - row--; col = 0; - if (row < 0) return TPS_INVALID; - tps++; TPS_ASSERT_MORE; - break; - } - case ',': { - // next column - col++; - if (col >= board_size) return TPS_INVALID; - tps++; TPS_ASSERT_MORE; - break; + case ' ': { + // we're done + parsing = 0; + tps++; + TPS_ASSERT_MORE; + break; + } + case 'x': { + // empty squares + tps++; + TPS_ASSERT_MORE; + skip = 0; + if (*tps >= '2' && *tps <= '0' + state->board_size) { + skip = *tps - '1'; + tps++; + TPS_ASSERT_MORE; + } else if (*tps != ',' && *tps != '/' && *tps != ' ') { + return TPS_INVALID; } - default: { - const int l = THE_COORDS(col, row); - uint8_t num_read = 0, reading = 1; - // Read in a stack of colours, optionally terminated by an S - // or C to change the top stone type - while (reading) { - switch (*tps) { - // Reading a stone colour - case '2': { - // check next letter to make sure we have the material - tps++; TPS_ASSERT_MORE; - if (*tps == 'C') { - if (black_count & 128) black_count &= 127; - else return TPS_INVALID; - } else if (black_count & 127) { - black_count--; - } else return TPS_INVALID; - colours[l] <<= 1; - celldat[l] += NUM_INC; - colours[l] |= 1; - num_read++; - break; - } - case '1': { - tps++; TPS_ASSERT_MORE; - if (*tps == 'C') { - if (white_count & 128) white_count &= 127; - else return TPS_INVALID; - } else if (white_count & 127) { - white_count--; - } else return TPS_INVALID; - colours[l] <<= 1; - celldat[l] += NUM_INC; - num_read++; - break; - } - case 'S': { - // Have we already read a stone type? - if (STONE_AT(l) != STONE_FLAT) return TPS_INVALID; - celldat[l] |= STONE_STANDING; - tps++; TPS_ASSERT_MORE; - break; - } - case 'C': { - if (STONE_AT(l) != STONE_FLAT) return TPS_INVALID; - celldat[l] |= STONE_CAPSTONE; - tps++; TPS_ASSERT_MORE; - break; - } - case ',': // fall-through - case '/': { - // done here - reading=0; - break; - } - default: return TPS_INVALID; - } - if (num_read > 0xF) return TPS_INVALID; - } + col += skip; + if (col >= state->board_size + 1) + return TPS_INVALID; + break; + } + case '/': { + // next row + if (col + 1 != state->board_size) + return TPS_INVALID; + row--; + col = 0; + if (row < 0) + return TPS_INVALID; + tps++; + TPS_ASSERT_MORE; + break; + } + case ',': { + // next column + col++; + if (col >= state->board_size) + return TPS_INVALID; + tps++; + TPS_ASSERT_MORE; + break; + } + default: { + const int l = THE_COORDS(state->board_size, col, row); + uint8_t num_read = 0, reading = 1; + // Read in a stack of colours, optionally terminated by an S + // or C to change the top stone type + while (reading) { + switch (*tps) { + // Reading a stone colour + case '2': { + // check next letter to make sure we have the material + tps++; + TPS_ASSERT_MORE; + if (*tps == 'C') { + if (state->black_count & 128) + state->black_count &= 127; + else + return TPS_INVALID; + } else if (state->black_count & 127) { + state->black_count--; + } else + return TPS_INVALID; + state->colours[l] <<= 1; + state->celldat[l] += NUM_INC; + state->colours[l] |= 1; + num_read++; + break; + } + case '1': { + tps++; + TPS_ASSERT_MORE; + if (*tps == 'C') { + if (state->white_count & 128) + state->white_count &= 127; + else + return TPS_INVALID; + } else if (state->white_count & 127) { + state->white_count--; + } else + return TPS_INVALID; + state->colours[l] <<= 1; + state->celldat[l] += NUM_INC; + num_read++; + break; + } + case 'S': { + // Have we already read a stone type? + if (STONE_AT(state, l) != STONE_FLAT) + return TPS_INVALID; + state->celldat[l] |= STONE_STANDING; + tps++; + TPS_ASSERT_MORE; + break; + } + case 'C': { + if (STONE_AT(state, l) != STONE_FLAT) + return TPS_INVALID; + state->celldat[l] |= STONE_CAPSTONE; + tps++; + TPS_ASSERT_MORE; + break; + } + case ',': // fall-through + case '/': { + // done here + reading = 0; + break; + } + default: + return TPS_INVALID; + } + if (num_read > 0xF) + return TPS_INVALID; } } + } } // Now it's time to parse the ply number. First, the active player - if (*tps != '1' && *tps != '2') return TPS_INVALID; - ply += *tps - '1'; - tps++; TPS_ASSERT_MORE; + if (*tps != '1' && *tps != '2') + return TPS_INVALID; + state->ply += *tps - '1'; + tps++; + TPS_ASSERT_MORE; // Space - if (*tps != ' ') return TPS_INVALID; - tps++; TPS_ASSERT_MORE; + if (*tps != ' ') + return TPS_INVALID; + tps++; + TPS_ASSERT_MORE; // Turn number, atoi doesn't detect errors so let's do it ourselves uint8_t p = 0; @@ -139,21 +171,27 @@ load_tps(char* tps) { p *= 10; if (*tps >= '0' && *tps <= '9') { p += *tps - '0'; - } else return TPS_INVALID; + } else + return TPS_INVALID; tps++; - } while ( (prefix && *tps && *tps != '"') || (!prefix && *tps) ); - if (p == 0) return TPS_INVALID; - ply += 2*(p - 1); + } while ((prefix && *tps && *tps != '"') || (!prefix && *tps)); + if (p == 0) + return TPS_INVALID; + state->ply += 2 * (p - 1); - current_colour = (ply & 1) ? C_BLACK : C_WHITE; - if (ply < 2) current_colour = C_BLACK - current_colour; + state->current_colour = (state->ply & 1) ? C_BLACK : C_WHITE; + if (state->ply < 2) + state->current_colour = C_BLACK - state->current_colour; if (prefix) { - tps++; TPS_ASSERT_MORE; - if (*tps != ']' ) return TPS_INVALID; + tps++; + TPS_ASSERT_MORE; + if (*tps != ']') + return TPS_INVALID; tps++; - if (*tps != 0) return TPS_INVALID; + if (*tps != 0) + return TPS_INVALID; } return TPS_OK; @@ -163,55 +201,68 @@ load_tps(char* tps) { // Generate TPS string // =================================================================== -void -generate_tps(char *out_tps) { +void generate_tps(tak_state_p state, char *out_tps) { strcpy(out_tps, "[TPS \""); out_tps += 6; - for (int8_t row = board_size - 1; row >= 0; row--) { - for (int8_t col = 0; col < board_size; col++) { - const int8_t l = THE_COORDS(col, row); - const uint8_t count = COUNT_AT(l); + for (int8_t row = state->board_size - 1; row >= 0; row--) { + for (int8_t col = 0; col < state->board_size; col++) { + const int8_t l = THE_COORDS(state->board_size, col, row); + const uint8_t count = COUNT_AT(state, l); if (count) { - colour_stack_t c = colours[l], s = 1<<(count - 1); - for (int k=0; k<count; k++, s >>=1, out_tps++) { - if (c & s) *out_tps = '2'; - else *out_tps = '1'; - } - switch (STONE_AT(l)) { - case STONE_CAPSTONE: { - *out_tps = 'C'; out_tps++; break; - } - case STONE_STANDING: { - *out_tps = 'S'; out_tps++; break; - } - default: break; - } + colour_stack_t c = state->colours[l], s = 1 << (count - 1); + for (int k = 0; k < count; k++, s >>= 1, out_tps++) { + if (c & s) + *out_tps = '2'; + else + *out_tps = '1'; + } + switch (STONE_AT(state, l)) { + case STONE_CAPSTONE: { + *out_tps = 'C'; + out_tps++; + break; + } + case STONE_STANDING: { + *out_tps = 'S'; + out_tps++; + break; + } + default: + break; + } } else { - int8_t skip = 1; - while (col < board_size && COUNT_AT(l+skip) == 0) { - skip++; - col++; - } - *out_tps = 'x'; out_tps++; - if (skip > 1) { - *out_tps = '0'+skip; out_tps++; - } + int8_t skip = 1; + while (col < state->board_size && COUNT_AT(state, l + skip) == 0) { + skip++; + col++; + } + *out_tps = 'x'; + out_tps++; + if (skip > 1) { + *out_tps = '0' + skip; + out_tps++; + } } - if (col + 1 < board_size) { - *out_tps = ','; out_tps++; + if (col + 1 < state->board_size) { + *out_tps = ','; + out_tps++; } } if (row > 0) { - *out_tps = '/'; out_tps++; + *out_tps = '/'; + out_tps++; } } - *out_tps = ' '; out_tps++; - *out_tps = '1' + (ply & 1); out_tps++; - *out_tps = ' '; out_tps++; + *out_tps = ' '; + out_tps++; + *out_tps = '1' + (state->ply & 1); + out_tps++; + *out_tps = ' '; + out_tps++; - out_tps += sprintf(out_tps, "%d", ply/2 + 1); + out_tps += sprintf(out_tps, "%d", state->ply / 2 + 1); strcpy(out_tps, "\"]"); } diff --git a/include/tps.h b/include/tps.h index 70cf1de..075b3f8 100644 --- a/include/tps.h +++ b/include/tps.h @@ -1,11 +1,9 @@ #include <tak.h> -#include <string.h> // for strnlen, strncmp, and strcpy #include <stdio.h> // for sprintf (in a single place! grrr) +#include <string.h> // for strnlen, strncmp, and strcpy // NOTE: We assume that board_size matches TPS size. -enum TPS_RESULT -load_tps(char* in_tps); +enum TPS_RESULT load_tps(tak_state_p state, char *in_tps); -void -generate_tps(char *out_tps); +void generate_tps(tak_state_p state, char *out_tps); diff --git a/include/tt_llcht.c b/include/tt_llcht.c index b80da39..7b2269b 100644 --- a/include/tt_llcht.c +++ b/include/tt_llcht.c @@ -21,30 +21,29 @@ // Variables // =================================================================== -static tt_entry_t *table[TT_LLCHT_SIZE+1]; +static tt_entry_t *table[TT_LLCHT_SIZE + 1]; // =================================================================== // Helper declarations // =================================================================== -tt_entry_t * new_ll_node(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action); - +tt_entry_t *new_ll_node(const uint64_t key, const enum TT_FLAG flag, + const uint8_t depth, const float value, + const action_t action); // =================================================================== // Exported functions // =================================================================== int tt_init(void) { - for (uint32_t k=0; k<=TT_LLCHT_SIZE; k++) + for (uint32_t k = 0; k <= TT_LLCHT_SIZE; k++) table[k] = NULL; return EXIT_SUCCESS; } void tt_free(void) { tt_entry_t *n, *nn; - for (uint32_t k=0; k<=TT_LLCHT_SIZE; k++) { + for (uint32_t k = 0; k <= TT_LLCHT_SIZE; k++) { n = table[k]; while (n) { nn = n->next; @@ -61,15 +60,15 @@ tt_entry_t *tt_seek(const uint64_t key) { return lookup; } -int tt_insert(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action) { +int tt_insert(const uint64_t key, const enum TT_FLAG flag, const uint8_t depth, + const float value, const action_t action) { tt_entry_t *new = new_ll_node(key, flag, depth, value, action), *n; // TODO: trap const uint32_t idx = key & TT_LLCHT_SIZE; if ((n = table[idx]) != NULL) { - for (; n->next != NULL; n = n->next); + for (; n->next != NULL; n = n->next) + ; n->next = new; } else { table[idx] = new; @@ -82,9 +81,9 @@ int tt_insert(const uint64_t key, const enum TT_FLAG flag, // Helper function implementations // =================================================================== -tt_entry_t * new_ll_node(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action) { +tt_entry_t *new_ll_node(const uint64_t key, const enum TT_FLAG flag, + const uint8_t depth, const float value, + const action_t action) { tt_entry_t *new = malloc(sizeof(struct tt_node_s)); // TODO: trap errno new->key = key; diff --git a/include/tt_llcht.h b/include/tt_llcht.h index 40d8bdb..dc73d26 100644 --- a/include/tt_llcht.h +++ b/include/tt_llcht.h @@ -18,8 +18,8 @@ #ifndef TT_LLCHT_H #define TT_LLCHT_H -#include <stdlib.h> #include <stdint.h> +#include <stdlib.h> #include <actions.h> @@ -42,7 +42,7 @@ typedef struct tt_node_s { // Variables // =================================================================== -#define TT_LLCHT_SIZE ((uint32_t)((1<<19) - 1)) +#define TT_LLCHT_SIZE ((uint32_t)((1 << 19) - 1)) // =================================================================== // Methods @@ -53,8 +53,7 @@ void tt_free(void); tt_entry_t *tt_seek(const uint64_t key); -int tt_insert(const uint64_t key, const enum TT_FLAG flag, - const uint8_t depth, const float value, - const action_t action); +int tt_insert(const uint64_t key, const enum TT_FLAG flag, const uint8_t depth, + const float value, const action_t action); #endif diff --git a/include/weights.c b/include/weights.c index 82b55f9..1fa864e 100644 --- a/include/weights.c +++ b/include/weights.c @@ -14,20 +14,20 @@ * Trainable params: 1,986 * Non-trainable params: 0 * _________________________________________________________________ - * ([0.4593624770641327, 0.8171698451042175], [0.44635653495788574, 0.819940984249115]) + * ([0.5177317261695862, 0.755382776260376], [0.5241230130195618, 0.7530876398086548]) */ #include "weights.h" const float dense1_weights[DENSE_NUM][INP_NUM] = -{{0.09708841890096664, -0.14983339607715607, 0.9531096816062927, 0.14991514384746552, -0.63932865858078, 0.09746148437261581, -0.1670435070991516, 0.25754305720329285, -0.1731426864862442, -0.1653723269701004, -0.3116675615310669, 0.4331771433353424, 0.07788953930139542, -0.3911878764629364, -0.5864945650100708, -0.5138149261474609, -0.10366032272577286, 0.09420160204172134, 0.3116736114025116, -0.8269373774528503, -0.6619208455085754, -1.0483648777008057, -0.05252189561724663, 0.12044219672679901, 0.677895724773407, 0.9947460293769836, -1.109876036643982, -0.20052704215049744}, {0.04853341355919838, -0.44796833395957947, 1.0772864818572998, 0.12211384624242783, 0.43898314237594604, 0.19653372466564178, -0.010857676155865192, -0.34688177704811096, -1.917777180671692, -1.0062774419784546, -0.772797167301178, -0.6764053106307983, -0.15675123035907745, 0.20477063953876495, 0.0170141514390707, 0.0373976044356823, -0.3958517014980316, -0.17130737006664276, 0.10296492278575897, -0.10372677445411682, -0.07705003023147583, -0.21586216986179352, -0.06457874923944473, 0.18130557239055634, -0.19682471454143524, -0.10427158325910568, -0.6213868260383606, 0.2646593451499939}, {0.05100073665380478, -1.490741491317749, 0.5347241759300232, 0.5138917565345764, 0.7368579506874084, -0.3916100859642029, 0.10224276781082153, -0.8944575190544128, 0.9391179084777832, 0.8531733155250549, -0.7068527936935425, -0.1843581348657608, 0.10034217685461044, 0.7256124019622803, -0.5566624402999878, -0.630030632019043, 0.1081201434135437, 0.06458459794521332, -0.06652732193470001, -0.7848819494247437, 0.06676337122917175, 0.19047099351882935, 0.3317343592643738, -1.125041127204895, -0.15809980034828186, 0.7293155193328857, 0.7303928732872009, 0.24778194725513458}, {-0.10748109966516495, 1.3822530508041382, 0.2629156708717346, 0.6968264579772949, 0.17485041916370392, -0.20862552523612976, -0.12484818696975708, -0.23138242959976196, 0.8940210342407227, 0.7281381487846375, 0.2892467975616455, 0.07963291555643082, -0.07487558573484421, -0.1968744993209839, 0.8000355362892151, 0.6640182733535767, 0.22926642000675201, 0.2277926504611969, -0.37833377718925476, -0.2742082476615906, 0.8170139193534851, 0.4202984571456909, 0.27552902698516846, -0.46328070759773254, -0.3581807315349579, 0.10414467751979828, 0.7333625555038452, 0.35470449924468994}, {-0.1888720840215683, 0.9495699405670166, -0.6001124978065491, 0.2289646714925766, 0.1645985096693039, 0.010710741393268108, -0.07195031642913818, -0.3604000210762024, 0.40493911504745483, 0.06439553201198578, -0.1027727797627449, -0.18764203786849976, -0.020061621442437172, 0.41247984766960144, 0.0985364243388176, 0.03292955830693245, 0.13963104784488678, -0.1577671319246292, 0.8160413503646851, 0.3458573818206787, 0.15316851437091827, 0.09699071943759918, -0.15548554062843323, 0.06560410559177399, 0.5002033710479736, 0.6853768825531006, 0.913468599319458, 1.762925148010254}, {-0.05926303192973137, 2.1326680183410645, 0.20786024630069733, 0.20509517192840576, 0.3232854902744293, 0.4138268232345581, 0.23191986978054047, 0.1483074426651001, 0.30143123865127563, 0.36913859844207764, 0.2858075201511383, 0.27123841643333435, 0.21376250684261322, 0.2404519021511078, 0.4652462899684906, 0.23301848769187927, 0.3275870382785797, 0.3245834708213806, 0.35785531997680664, 0.21870960295200348, 0.28119996190071106, 0.385022908449173, 0.2985413074493408, 0.015570216812193394, 0.2387431263923645, 0.3773896098136902, 0.3013421595096588, 0.09287303686141968}, {-0.13003307580947876, 1.7538926601409912, -0.6812999844551086, -0.4881831109523773, -0.4694475829601288, 0.75823974609375, 0.2842443883419037, 0.31535980105400085, -0.4027916193008423, 0.6403568387031555, 0.7254506945610046, 0.31957608461380005, 0.6868956089019775, 0.6129562854766846, 0.6620163917541504, -0.19040672481060028, 0.2591014504432678, 0.17981182038784027, 0.3206057548522949, 0.26464489102363586, 0.12509778141975403, -0.1723550260066986, 0.5769479274749756, 0.27363383769989014, 0.40419286489486694, 0.4196736216545105, 0.474353551864624, 0.3851746618747711}, {0.004320172592997551, -0.06554269790649414, 1.0545583963394165, 0.03816256299614906, -0.3641563057899475, -0.04311445355415344, -1.0777692794799805, 0.3634617328643799, -0.2762683629989624, 0.2931346595287323, 0.12660370767116547, -0.8033497333526611, -0.08709059655666351, 0.2099713832139969, 0.38327884674072266, 0.11443039029836655, -0.8581308722496033, -0.6271834969520569, 0.01899813674390316, -0.36976635456085205, -0.9609361290931702, -1.242712140083313, -0.20354503393173218, -0.892693042755127, -1.3654234409332275, -0.1457122266292572, 0.4198227822780609, 0.47160959243774414}, {-0.1309877187013626, 1.7283211946487427, -0.34542015194892883, 0.09756244719028473, 0.10365703701972961, 0.16427665948867798, 0.5429031848907471, 0.000730195315554738, 0.9568342566490173, 0.43416130542755127, 0.5171336531639099, -0.03411416709423065, 0.09991542249917984, 0.22394727170467377, 0.46084511280059814, 0.2941528856754303, 0.40269896388053894, 0.4282401502132416, -0.043696314096450806, 0.9397956728935242, 0.4523789584636688, 0.21760058403015137, 0.25844889879226685, -0.0975789725780487, 1.4064749479293823, -0.4462650716304779, -0.0176702868193388, -0.15949156880378723}, {-0.09322677552700043, 1.4953668117523193, -0.6572163701057434, 0.03580909222364426, 0.07035914063453674, 1.2231422662734985, 0.14995643496513367, -0.01055422704666853, -0.3619900643825531, 0.00962253101170063, 1.1480656862258911, 0.04119277000427246, -0.029596557840704918, -0.20450031757354736, -0.20949582755565643, 1.3544684648513794, -0.07676524668931961, -0.33410149812698364, 0.14368489384651184, 0.18317444622516632, 0.9521495699882507, 0.2047186642885208, -0.14690256118774414, -0.002987049985677004, 0.22252139449119568, 0.5207418203353882, 0.3862583041191101, 0.04728662222623825}, {0.12120318412780762, -0.32054218649864197, 0.2999326288700104, 0.914248526096344, -0.25369349122047424, 1.0056365728378296, 1.0900052785873413, -1.9740498065948486, -0.2208552062511444, 0.12854935228824615, 0.17538198828697205, -0.1234835833311081, -1.1125203371047974, -0.3354377746582031, -0.5196758508682251, -0.30077362060546875, -0.5856597423553467, -0.8402205109596252, -0.22239884734153748, -0.4105615019798279, -0.38801825046539307, -0.8613605499267578, -0.27762359380722046, 0.49667125940322876, 0.020931968465447426, -0.12382236868143082, -0.4301914572715759, -0.350443035364151}, {-0.07766333967447281, 0.6034705638885498, -4.554388523101807, 0.2126956582069397, 0.15929296612739563, 0.17145121097564697, 0.1601206660270691, 0.17433294653892517, 0.12817388772964478, 0.11653872579336166, 0.14781475067138672, 0.23677119612693787, 0.12034492939710617, 0.1955379694700241, 0.13016147911548615, 0.23828306794166565, 0.14038963615894318, 0.15755616128444672, 0.23868830502033234, 0.26690152287483215, 0.1843731850385666, 0.17341510951519012, 0.057188548147678375, 0.2539713680744171, 0.2696954309940338, 0.18604490160942078, 0.14197516441345215, 0.36821600794792175}, {0.15129533410072327, 0.09887662529945374, 1.2054975032806396, 0.24753500521183014, 0.4909513294696808, -1.6100319623947144, 0.07008431106805801, 0.1423417031764984, -0.09243771433830261, -0.34568139910697937, -1.0303078889846802, 0.18709783256053925, 0.6571977138519287, -0.11068439483642578, -0.14676885306835175, -0.6726709008216858, -0.6291938424110413, 0.6409110426902771, -0.4643811285495758, -0.06342993676662445, -0.3956544101238251, -0.7433932423591614, -1.4594924449920654, -0.2231053113937378, -0.31123557686805725, 0.03604980930685997, -0.01676316000521183, -0.010373279452323914}, {0.08248379826545715, -0.33374691009521484, 0.4519060552120209, -0.3651171028614044, -1.0735950469970703, 0.005808517802506685, 1.2023851871490479, 0.7546958327293396, -0.19511595368385315, -0.5970048904418945, -1.1051145792007446, -0.513593316078186, 1.0888173580169678, 0.2880654036998749, 0.14094868302345276, -0.5696795582771301, -1.0076549053192139, 0.19139567017555237, 0.336557537317276, 0.3891679644584656, 0.09406869858503342, -0.8800191283226013, -0.5774187445640564, 0.18142414093017578, 0.17849640548229218, -0.11618805676698685, -0.6260532736778259, -0.39390552043914795}, {-0.07623733580112457, 1.0555744171142578, -0.17468947172164917, 0.18221747875213623, 0.06131114810705185, -0.014457565732300282, 0.1536666601896286, 0.6676269769668579, 0.17481842637062073, -0.14446255564689636, 0.04878826066851616, 0.27363839745521545, 0.5058372020721436, 0.16395719349384308, 0.19522777199745178, 0.31879734992980957, 0.8337258696556091, 0.612602710723877, 0.18271851539611816, 0.12550194561481476, 0.7062245011329651, 0.2406325489282608, -0.5638207793235779, 0.44285738468170166, 0.49697133898735046, 0.655937135219574, -0.5988529324531555, -0.6180514693260193}, {-0.08515164256095886, 1.8156886100769043, -0.3055272698402405, -0.00542338564991951, 0.28451383113861084, 0.3305817246437073, 0.44789642095565796, 0.007520807906985283, 0.6411338448524475, 0.6627947688102722, 0.3936305642127991, 0.543207585811615, 0.31023091077804565, 0.5907645225524902, -0.5054730772972107, 0.5622344613075256, 0.46472644805908203, 0.7537768483161926, 0.5771557092666626, 0.6231046915054321, 0.5562911629676819, 0.05025006830692291, 0.4974210858345032, -0.021163247525691986, 0.428413450717926, 0.2096228450536728, 0.1297932267189026, 0.15994444489479065}, {0.059478625655174255, -1.2593594789505005, 0.8060709238052368, -0.5756357312202454, -0.5642467141151428, -1.1023842096328735, -1.0840095281600952, -1.7373161315917969, 0.051716454327106476, -0.18114325404167175, 0.03431779146194458, 0.07772735506296158, 0.30920106172561646, 0.06860094517469406, 0.053684305399656296, 0.050935737788677216, 1.5831908967811614e-05, 0.06146225333213806, 0.14663179218769073, 0.01896907575428486, -0.017615582793951035, 0.049037203192710876, 0.3536975681781769, 0.5997693538665771, 0.06265199184417725, 0.018393227830529213, -0.03553879261016846, 0.15440478920936584}, {-0.06590350717306137, 0.6541862487792969, -0.9594393968582153, 1.5689195394515991, 0.995005190372467, 0.7445554733276367, 0.92704838514328, 0.4702519476413727, -0.3339536786079407, -0.18121398985385895, 0.12824110686779022, 0.32404643297195435, 0.08692658692598343, 0.06525395065546036, -0.07403562217950821, -0.08786602318286896, 0.30545052886009216, 0.1610720455646515, 0.025930603966116905, -0.006452936679124832, 0.04217161983251572, -0.00885680504143238, 0.01933605782687664, -0.5424081683158875, 0.03653205558657646, -0.09611544758081436, 0.07054111361503601, -0.33712488412857056}, {-0.033981095999479294, 0.7148251533508301, -0.9412906169891357, -0.14343379437923431, -0.10766273736953735, -0.11414168775081635, -0.13219089806079865, 1.2587040662765503, 0.008397090248763561, -0.10059479624032974, 0.13039082288742065, 0.12154032289981842, 1.238200306892395, -0.19973790645599365, -0.05784938111901283, 0.017947781831026077, -0.04616774618625641, 1.1192306280136108, 0.07938524335622787, -0.005415983498096466, 0.09550166130065918, 0.09772814065217972, 1.2091776132583618, -0.30785369873046875, -0.05821114033460617, -0.06727229803800583, -0.04389581456780434, 1.2299752235412598}, {0.1273789405822754, -0.341524600982666, 1.151167392730713, -0.04134071618318558, -0.07647605985403061, 0.36836978793144226, -1.3937312364578247, -0.16971394419670105, -0.1672888547182083, 0.05098025128245354, 0.4777861535549164, -1.6180260181427002, -0.14700591564178467, -0.42429643869400024, -0.571417510509491, -0.3194080591201782, -1.2477779388427734, 0.7285082340240479, -0.5621447563171387, -0.067803755402565, -0.33690130710601807, -1.2182284593582153, -0.026820745319128036, 0.24996322393417358, -0.04271029680967331, -0.25508779287338257, -0.18486416339874268, -0.2532777190208435}, {0.11533160507678986, 0.3406147062778473, 1.8792569637298584, 0.018996711820364, -0.2056526243686676, -0.33621448278427124, -0.20685425400733948, -0.24743612110614777, -0.17051126062870026, -0.584708034992218, -0.40372198820114136, -0.37256744503974915, -0.34893912076950073, -0.3406921923160553, -0.5737095475196838, 0.9329007267951965, -0.5134408473968506, -0.3319478929042816, -0.1288238763809204, -0.5994487404823303, -0.5022518038749695, -0.49213001132011414, -0.13361960649490356, -0.02503959834575653, -0.33584609627723694, -0.30276021361351013, -0.16746489703655243, 0.13810385763645172}, {-0.09611523896455765, 1.238119125366211, -0.4888734817504883, 0.20628002285957336, 0.37660905718803406, 0.22086504101753235, 1.418500542640686, -0.3454299569129944, 0.2719173729419708, 0.19811256229877472, 0.3238287568092346, 1.0737624168395996, -0.12214085459709167, 0.3549494743347168, 0.2717260420322418, -0.009705607779324055, 0.853428304195404, 0.24796196818351746, 0.33442437648773193, -0.13321736454963684, 0.13895970582962036, 0.3937171995639801, 0.6743841767311096, -0.2558365762233734, 0.33873921632766724, -0.2011198103427887, -0.24151191115379333, 1.0191739797592163}, {0.028014613315463066, -0.4389137625694275, 1.2217202186584473, 0.5615558624267578, 0.05263078957796097, 0.05092257261276245, -0.0025020919274538755, -0.10499066114425659, 0.22626706957817078, -0.18914547562599182, 0.04754278063774109, 0.03034340962767601, -0.22401578724384308, -1.2998645305633545, -0.9751662015914917, -0.7423930764198303, -0.3970774710178375, -0.061214447021484375, -0.08540238440036774, 0.45488816499710083, -0.14393432438373566, -0.23829105496406555, -0.26323971152305603, 0.2596847116947174, 0.37555330991744995, 0.11025014519691467, -0.4083321690559387, 0.15121963620185852}, {-0.21241767704486847, 1.6689105033874512, -0.226408913731575, 0.03731200098991394, 0.26310592889785767, 1.2660009860992432, -0.47913163900375366, -0.4116690158843994, 0.39553773403167725, 0.0419420562684536, 1.0190608501434326, 0.3955974280834198, -0.2669771909713745, 0.22511376440525055, 0.19040349125862122, 0.3689280152320862, 0.5754274725914001, 0.791631281375885, 0.17811143398284912, 0.364437997341156, 0.13787342607975006, 0.1953200399875641, 0.35008370876312256, 0.40746477246284485, 0.021115917712450027, 0.19234441220760345, 0.34583356976509094, 0.221570685505867}, {-0.056629478931427, 1.3422456979751587, -0.48497992753982544, -0.1941925585269928, 0.165594220161438, 0.287276953458786, 0.15132613480091095, 0.38584816455841064, 0.2143339067697525, 0.13520006835460663, 0.2816779315471649, 0.36108213663101196, 0.5532099604606628, 0.2023126780986786, 0.26956668496131897, 0.06489624828100204, 0.8025456070899963, 0.01022995077073574, 0.20568951964378357, 0.3348022401332855, 0.235650435090065, 1.00911283493042, -0.1623430848121643, -0.029755957424640656, 0.16051626205444336, -0.30153003334999084, 1.820574402809143, -0.18349412083625793}, {0.08210670948028564, -0.10644663870334625, 2.0925099849700928, -0.24863389134407043, -0.2665429711341858, -0.40262511372566223, -0.45371878147125244, -0.1377442479133606, -0.39157360792160034, -0.22115609049797058, -0.4804888963699341, -0.2904321551322937, -0.18321593105793, -0.33899354934692383, -0.3302883207798004, -0.2938438951969147, -0.18833966553211212, -0.30292198061943054, -0.35079896450042725, -0.2308332324028015, -0.343620240688324, -0.29516926407814026, -0.2986883819103241, -0.16443338990211487, -0.44009503722190857, -0.27044206857681274, -0.4302333891391754, -0.036748480051755905}, {-0.020061643794178963, 1.2271647453308105, -0.7192057967185974, 0.22154885530471802, -0.2719059884548187, 0.45283734798431396, 0.23891234397888184, 0.06230388209223747, -0.3005612790584564, 0.38583460450172424, 0.09369464963674545, 0.25240558385849, 0.22129446268081665, -0.14313091337680817, -0.03104626201093197, 0.07079270482063293, 0.4938150942325592, 0.4324195086956024, 1.1018677949905396, 1.2313228845596313, 0.8778300881385803, 1.1587250232696533, 0.23411384224891663, -0.05438053980469704, -0.20136210322380066, -0.25242170691490173, 0.27750808000564575, 0.13955263793468475}, {0.21351471543312073, 0.13765887916088104, 2.0183377265930176, -0.007917194627225399, -0.3589908182621002, -0.5994181036949158, -0.11847121268510818, 0.021346328780055046, -0.4103794991970062, -0.41012945771217346, 0.18445296585559845, -0.6636074185371399, -0.24117298424243927, -0.3390832841396332, -0.40450406074523926, -0.3359193205833435, -0.39004817605018616, -0.2984693646430969, -0.22267311811447144, -0.3200683295726776, -0.17157769203186035, -0.15781398117542267, -0.20106711983680725, -0.3199653625488281, -0.28912240266799927, -0.5469598174095154, -0.598488450050354, -0.20015941560268402}, {0.13156303763389587, -0.04746222496032715, 1.4406293630599976, 0.04010009765625, -0.19504183530807495, -0.3422450125217438, -0.30269885063171387, 0.03397633880376816, -0.34146347641944885, -0.2657840847969055, -0.5875772833824158, -0.3439021110534668, -0.24916069209575653, -0.06749272346496582, -0.6978026032447815, -0.5449330806732178, -0.6765002608299255, -0.374035120010376, -0.0997399315237999, -0.7321766018867493, 0.932058572769165, -0.7302301526069641, -0.10420955717563629, 0.09721499681472778, -0.7511874437332153, -0.5356468558311462, -0.7049369215965271, 0.10399650782346725}, {-0.026832129806280136, 0.9518526792526245, 0.027437914162874222, 0.03834706172347069, 0.19063116610050201, 0.06822194904088974, 0.025699865072965622, -0.0034538416657596827, 0.5062559247016907, 0.48999106884002686, 0.839417040348053, 1.0514994859695435, -0.33073392510414124, 0.4111200273036957, -0.09617988020181656, -0.6156681776046753, 0.7947877049446106, 0.5059559345245361, 0.3703654408454895, -0.01992918737232685, 0.010815472342073917, 0.7090519666671753, 0.33787572383880615, 0.3802514672279358, 0.27450019121170044, 0.7134937047958374, 0.47950777411460876, 0.07987868040800095}, {-0.12225848436355591, 1.7318753004074097, -0.2236385941505432, 0.164175882935524, 0.6606665253639221, -0.09252867102622986, -0.09040944278240204, -0.01922728307545185, 0.2076280564069748, 0.5997986793518066, 0.8389816284179688, 1.0328935384750366, 1.4117224216461182, 0.2752927839756012, 0.3150433599948883, 0.3206954002380371, 0.3793025016784668, -0.2018655240535736, 0.1428735852241516, 0.4109397232532501, 0.2945535182952881, 0.2752903401851654, 0.1045895516872406, -0.013057844713330269, 0.33169877529144287, 0.5139592885971069, 0.06500981748104095, -0.03201531246304512}, {0.037458743900060654, -0.0013948864070698619, 1.5822151899337769, 0.2050805389881134, -0.1646299958229065, -0.19420349597930908, -0.09858932346105576, 0.03837038576602936, -0.14196360111236572, -0.5955793857574463, -0.6105048656463623, -0.19990204274654388, -0.14786484837532043, -0.4259253144264221, 1.1276053190231323, -0.5819753408432007, -0.5576790571212769, -0.37708580493927, -0.4070882201194763, -0.5314394235610962, -0.6408591866493225, -0.3505810797214508, 0.024513090029358864, 0.16252656280994415, -0.3316267132759094, -0.22024187445640564, -0.29375335574150085, -0.08565379679203033}, {-0.0819413959980011, 1.0591763257980347, -0.7337607741355896, -0.17952848970890045, 0.8200972676277161, 0.8254687190055847, 0.8399497866630554, 1.0778814554214478, 0.32117852568626404, 0.6869990229606628, 0.4733969271183014, 0.19321654736995697, -0.2765744924545288, 0.39945876598358154, 0.6774672269821167, 0.09932424128055573, -0.20062103867530823, -0.2712205648422241, 0.7035691142082214, 0.20941823720932007, -0.1504993587732315, 0.1819196194410324, 0.0758715346455574, 0.9624840021133423, -0.10010877996683121, 0.047227196395397186, 0.07651358097791672, -0.15292885899543762}, {-0.03150544688105583, -0.02839292772114277, -0.5884301662445068, 0.039681024849414825, 0.08184020221233368, 0.10623382031917572, 0.009769861586391926, -0.07766010612249374, -0.021818384528160095, 0.2412724792957306, 0.11478745937347412, 0.05257875472307205, 0.07520901411771774, 0.05953354015946388, 0.22793656587600708, 0.12766006588935852, 0.15545566380023956, 0.09512616693973541, 0.1359385848045349, 0.2246624231338501, 0.1218600645661354, 0.13645589351654053, 0.022114301100373268, -0.0938657894730568, 0.053409822285175323, 0.04353907331824303, 0.05621011555194855, 0.024152453988790512}, {-0.10731056332588196, 1.9101223945617676, -0.14491631090641022, -0.31954917311668396, -0.13067302107810974, -0.38983073830604553, 1.2752583026885986, 0.10712035745382309, -0.02182578109204769, -0.27314284443855286, 0.5775480270385742, 0.8474040031433105, 0.3230977952480316, -0.09060269594192505, 0.5151476263999939, 0.8193845152854919, 0.4053916931152344, 0.2335839718580246, 1.1781198978424072, 0.8876485228538513, 0.494328111410141, 0.10951576381921768, 0.35883137583732605, 0.031916506588459015, 0.24021664261817932, 0.4334607720375061, 0.32361146807670593, 0.12500637769699097}, {-0.048089589923620224, 0.2517174184322357, -0.6230883598327637, 0.03189172223210335, 0.028296470642089844, 0.05605744197964668, 0.08526457846164703, 0.05624855309724808, 0.04614025354385376, 0.0461905337870121, 0.07688868790864944, 0.1092841625213623, 0.06774014234542847, -0.03262807056307793, 0.08905143290758133, 0.0877608135342598, 0.06686928868293762, 0.07233935594558716, 0.057617634534835815, 0.016904741525650024, 0.04663266986608505, 0.07950703799724579, 0.00545073114335537, 0.07434149831533432, 0.03768325597047806, 0.10711461305618286, 0.06703071296215057, 0.10979264229536057}, {-0.08404885232448578, -0.7368913888931274, 0.4573487937450409, 0.13284821808338165, 0.3613227605819702, 0.14185453951358795, 0.6336719393730164, -1.4996527433395386, 0.14475664496421814, 0.29121872782707214, 0.4278671443462372, 0.1410083919763565, -0.8940686583518982, 0.2855665683746338, 0.42577508091926575, 0.32199257612228394, -0.29421567916870117, -0.47793734073638916, 0.3777045011520386, 0.19965225458145142, -0.2553655505180359, -0.7715121507644653, -0.7749602794647217, -0.9258174300193787, -0.47367092967033386, -0.7522175312042236, -0.6750305891036987, -0.22101743519306183}, {0.14481350779533386, -0.008970635011792183, 1.508664608001709, 0.15015840530395508, -0.14811588823795319, 0.588955819606781, -1.0150330066680908, -0.053266044706106186, 0.07046253234148026, -1.5722743272781372, -1.0555866956710815, -1.0166481733322144, -0.24272829294204712, -0.41724616289138794, -0.8357856273651123, -0.03276902064681053, -0.04676911234855652, -0.26494157314300537, -0.4370666444301605, -0.7593159079551697, -0.053759537637233734, 0.3186907172203064, -0.5872452855110168, 0.03758898749947548, -0.4328208863735199, -0.21179579198360443, -0.40803515911102295, 0.0951615571975708}, {0.00908249244093895, -0.07688987255096436, 0.782505452632904, 0.06486380100250244, -0.2471565157175064, 0.021011406555771828, 0.022204816341400146, 0.1792861968278885, -0.13489873707294464, -0.036091145128011703, -0.43057775497436523, -0.031296003609895706, -0.2873421311378479, 0.22351358830928802, -0.026948416605591774, -0.8745213150978088, 0.11529920995235443, 0.24653159081935883, 0.5388697981834412, 0.47889870405197144, -1.1142454147338867, 0.3187515139579773, 0.38350510597229004, 0.02950381115078926, 0.29876217246055603, -2.0111100673675537, 0.5463553071022034, 0.14435721933841705}, {0.14901532232761383, -1.5044587850570679, 0.8972142338752747, 0.2778427302837372, -0.05853148549795151, 0.1994359791278839, -0.30804818868637085, -0.2415803223848343, -0.22669333219528198, -0.09136048704385757, -0.09575177729129791, -0.5684528946876526, -0.5545351505279541, 0.11623877286911011, -0.16263911128044128, -0.040955785661935806, -0.049217116087675095, -0.8552798628807068, -0.048276450484991074, 0.10525430738925934, 0.33164283633232117, 0.24776573479175568, -0.9200206398963928, 0.14236557483673096, -0.1810273379087448, 0.08166225254535675, 0.7190329432487488, -2.1177501678466797}, {-0.19271403551101685, 1.728354811668396, -0.49745607376098633, 0.13163147866725922, 0.4125182628631592, 0.3173934519290924, 0.3347082734107971, 0.1567714363336563, 0.44411492347717285, 0.5317234992980957, -0.5201308727264404, 0.5674026012420654, 0.41059064865112305, 0.49735933542251587, 0.624692440032959, 0.854070246219635, 0.6220293045043945, 0.3193413019180298, 0.22398653626441956, 0.40847501158714294, 0.5839058756828308, 0.1582852154970169, 0.33516645431518555, 0.03460458666086197, 0.4448821544647217, 0.8498842120170593, 0.3459503650665283, 0.11562537401914597}, {-0.047379519790410995, 1.703660488128662, -0.5990813374519348, -0.5269250273704529, 1.5372254848480225, -0.2775944471359253, 0.001394903170876205, -0.19458095729351044, -0.27556341886520386, 0.9208241105079651, 0.21152672171592712, 0.06251904368400574, 0.2743033468723297, 0.06462933868169785, 0.7903530597686768, 0.39518019556999207, 0.31461477279663086, 0.7033582925796509, 1.100284457206726, 0.583648681640625, 0.5865142941474915, -0.006218436639755964, 0.31119057536125183, 0.5512746572494507, 0.037552036345005035, -0.026546820998191833, 0.3478201627731323, 0.03815087676048279}, {0.028824783861637115, -0.32616135478019714, 1.2353787422180176, -0.4744008779525757, -1.8294140100479126, -0.17039445042610168, -0.16263258457183838, -0.27589941024780273, 0.02396584302186966, -0.6765327453613281, 0.026453670114278793, -0.20710843801498413, 0.12056914716959, -0.027168219909071922, -0.472407728433609, -0.06178409606218338, -0.02956007793545723, -0.03951815888285637, -0.16745562851428986, -0.19822148978710175, -0.06916672736406326, 0.018468298017978668, -0.5161017179489136, -0.3942733108997345, -0.036136265844106674, -0.22772735357284546, -0.1378902643918991, 0.15064162015914917}, {0.03982025757431984, -2.4930081367492676, 0.8281068801879883, -0.4357646107673645, 0.10274703055620193, -0.665107786655426, 0.5115349888801575, 0.32747960090637207, -0.09119489789009094, 0.2945898175239563, -0.1673634648323059, -0.6479430794715881, 0.1562136858701706, -1.237152338027954, -0.3490593731403351, 0.027165303006768227, -0.03953339904546738, -0.7550083994865417, 0.424204021692276, -0.8311765193939209, -0.3301525413990021, -0.052060894668102264, 0.24890226125717163, 0.5295188426971436, 0.2250201553106308, -0.709912896156311, 0.1652745008468628, 0.02529488131403923}, {0.030456073582172394, -0.5592262744903564, 1.432510256767273, -1.1988471746444702, -0.5064346194267273, -0.6237148642539978, 0.40195557475090027, 0.25146642327308655, 0.5024128556251526, -0.12030938267707825, -0.7599889039993286, -1.1147559881210327, -1.3214906454086304, 0.37952062487602234, 0.0130626754835248, -0.057461678981781006, -0.4395413398742676, -0.39032915234565735, -0.04154334217309952, 0.3974667191505432, -0.22250966727733612, -0.495175838470459, 0.04570012539625168, 0.31906959414482117, -0.14886492490768433, 0.3113555312156677, -0.6547025442123413, 0.08879609405994415}, {0.11950501054525375, -0.48032498359680176, 1.2850854396820068, 0.06694980710744858, -0.16385744512081146, -0.3026943802833557, -0.25026676058769226, 0.08888517320156097, 0.06509137898683548, -0.17576169967651367, -0.06554707139730453, -0.08778101950883865, -0.30888912081718445, 0.06313688308000565, -0.03595643863081932, -0.1171422153711319, -0.13362252712249756, -0.10691016912460327, -2.0260233879089355, -0.8719305992126465, -0.5115545392036438, -0.20826612412929535, 0.0837148055434227, -0.10446202009916306, 0.4123838543891907, -0.08748969435691833, -0.28654301166534424, -0.22568418085575104}, {-0.0004980643279850483, 1.6956111192703247, -0.9341049194335938, 0.3910086750984192, 0.9375659823417664, -0.599976658821106, -0.1314917951822281, -0.2129734605550766, 0.21699850261211395, 1.0505825281143188, 0.901665449142456, -0.0852508544921875, -0.17882975935935974, 0.2928134500980377, -0.2693397104740143, 0.8399291038513184, 0.6454485654830933, 0.3374834358692169, 0.04004263877868652, 0.24971531331539154, -0.05535968020558357, 0.7141254544258118, 0.5550016760826111, -0.20664328336715698, 0.16429021954536438, 0.6384597420692444, 0.4723033607006073, -0.08882896602153778}, {-0.14170923829078674, 1.3551650047302246, -0.9581169486045837, 0.9161777496337891, 0.030683813616633415, 0.2503061294555664, 0.07654116302728653, -0.013592132367193699, 0.4500807523727417, 0.961696445941925, 0.3948116898536682, 0.7503361105918884, 0.32386764883995056, -0.4451524317264557, 1.040030598640442, -0.16870202124118805, -0.37502360343933105, 0.5298779606819153, -0.11141359061002731, 1.0228924751281738, -0.31592369079589844, -0.04017551988363266, -0.15074723958969116, 0.0482744537293911, 1.1439263820648193, 0.4571666717529297, 0.12239103764295578, 0.4535315930843353}, {-0.032109931111335754, -0.12122310698032379, 0.8914746642112732, -0.27882638573646545, -0.11921525001525879, 0.32706254720687866, 0.2490244358778, 0.3580411672592163, -0.2604867219924927, -0.21825937926769257, -0.012418774887919426, 0.19902339577674866, 0.2708764672279358, 0.2748216688632965, -0.3405546247959137, -0.8040348291397095, -0.9789102077484131, -1.7298134565353394, -0.25523945689201355, -0.07197760790586472, -0.021183472126722336, 0.24487651884555817, 0.5359469652175903, -0.04558420553803444, -0.1392718106508255, 0.26097846031188965, 0.41951051354408264, 0.2396070510149002}, {-0.1434144526720047, 1.5024970769882202, -0.26019152998924255, -0.032202448695898056, 0.32650431990623474, 0.39354056119918823, 0.19199824333190918, 0.15139684081077576, 0.2088635414838791, 0.23116657137870789, 0.34120866656303406, 0.2512649595737457, 0.04610608145594597, 0.45557311177253723, 0.46523430943489075, 0.3187943994998932, 0.25996607542037964, -0.3529891073703766, 0.18252035975456238, 0.43683773279190063, 0.8012835383415222, 1.1804018020629883, 1.7978644371032715, 0.37052586674690247, 0.6495969295501709, 0.21544672548770905, -0.24423786997795105, -0.04839114099740982}, {0.08772090822458267, 0.036836814135313034, 0.4411259591579437, -0.2324865311384201, -0.4422452747821808, 0.3720940351486206, 0.0609813816845417, 0.4158213138580322, -0.6237788200378418, -1.4070799350738525, 1.0921244621276855, 0.4683806300163269, -0.1926126927137375, 0.5655200481414795, -1.2423927783966064, -0.6283270120620728, -0.5818661451339722, 0.1723531186580658, 0.5311585068702698, -0.6664415597915649, -0.42718756198883057, -0.5389712452888489, -0.5409123301506042, -0.19837777316570282, -0.42452719807624817, -0.42125552892684937, 0.2389526516199112, 0.04127349331974983}, {0.13081054389476776, -0.11356072872877121, 1.4752963781356812, -0.07947410643100739, -0.2676275968551636, -0.3330131471157074, -0.20006857812404633, -0.04646018147468567, -0.4903687834739685, -0.45940980315208435, -0.631168782711029, -0.4270765483379364, -0.3620588183403015, -0.27580520510673523, -0.44114959239959717, -0.7304320335388184, 0.9806434512138367, -0.47282716631889343, -0.19448859989643097, -0.6225467920303345, -1.0841974020004272, -0.738459587097168, -0.8378979563713074, -0.14952285587787628, -0.2907923758029938, -0.20345616340637207, -0.3887461721897125, 0.09503486752510071}, {-0.06538720428943634, 0.7628426551818848, -0.48973286151885986, -0.38497161865234375, 0.15466463565826416, 0.11393487453460693, 0.030808981508016586, -0.3597305119037628, 0.03768155723810196, 0.024493861943483353, 0.04951104521751404, 0.14642468094825745, 0.07216943800449371, -0.12633569538593292, 0.016758088022470474, 0.13920584321022034, 0.13626915216445923, 0.07511813938617706, -0.2962007224559784, -0.1386595219373703, 0.2720275819301605, 0.21500355005264282, 0.6123909950256348, 1.9834942817687988, 0.9948948621749878, 0.9978277683258057, 0.8778850436210632, 0.6260098218917847}, {-0.16871626675128937, 1.4061483144760132, -0.5023764371871948, 0.33703121542930603, 0.8559048771858215, 0.469501256942749, 0.7470555305480957, 0.30814874172210693, 0.564860999584198, 0.40895015001296997, 0.10864124447107315, 0.1458897590637207, 0.3857732117176056, 0.7911720871925354, 0.7119686603546143, -0.250042200088501, 0.17346656322479248, 0.3537016212940216, -0.41765081882476807, 1.0786654949188232, 0.8970625996589661, 0.5761362910270691, 0.5433169603347778, -0.6643967032432556, -0.48398444056510925, 1.2207279205322266, 0.514649510383606, 0.21612684428691864}, {-0.08570192009210587, 1.214324712753296, -0.13377290964126587, 0.34323278069496155, -0.14258965849876404, -0.18832489848136902, -0.08113601058721542, -0.029942357912659645, 0.0971248522400856, 0.11952006071805954, 0.09883774071931839, 0.2491564154624939, 0.07593998312950134, 1.131385087966919, 1.2205246686935425, 1.1922342777252197, 1.2262190580368042, 0.48976269364356995, 0.22512586414813995, 0.33211636543273926, -0.5047371983528137, 0.2883317172527313, 0.23470860719680786, 0.24038122594356537, -0.04741585999727249, -0.5512517094612122, -0.08958519995212555, 0.3993839919567108}, {-0.09156186878681183, 1.447799801826477, -0.8677529096603394, -0.2403821051120758, -0.24082186818122864, 0.09531288594007492, 1.1842302083969116, 0.7055855393409729, 1.238553762435913, 0.830436646938324, 0.7400990724563599, 0.5128685832023621, -0.1964624524116516, -0.3230336308479309, -0.12294219434261322, 0.24010124802589417, 0.3363843262195587, -0.19299542903900146, -0.1038021519780159, 0.10120601207017899, 0.30215927958488464, 0.0030945949256420135, 0.162748321890831, 0.048576682806015015, 0.3265083134174347, 0.43292054533958435, 0.1647973358631134, -0.14344830811023712}, {-0.14595773816108704, 2.036177635192871, -0.15678788721561432, -0.19012169539928436, 0.042336251586675644, 0.09402280300855637, 0.7207157611846924, 0.14010852575302124, 0.013773145154118538, 0.2021285742521286, 0.8130205273628235, 0.697592556476593, 0.19569545984268188, 1.3054842948913574, 0.7752094864845276, 0.8463451862335205, -0.43331101536750793, 0.39584746956825256, -0.026438673958182335, 0.35300928354263306, 0.6822341680526733, 0.5199337005615234, 0.4171527326107025, -0.19292718172073364, 0.30702468752861023, 0.2383618950843811, 0.49791133403778076, 0.2006896585226059}, {-0.016399526968598366, -0.8661689162254333, 0.627953827381134, 0.8040047883987427, 0.2690049409866333, -0.05720654875040054, 0.20661626756191254, 0.49369704723358154, 0.1373131424188614, -0.08826663345098495, -0.16605296730995178, 0.23632067441940308, -0.04646783322095871, 0.3226010203361511, -0.21266025304794312, 0.13406658172607422, 0.3166760206222534, 0.39453834295272827, 0.22649653255939484, -0.2949632406234741, -0.30884310603141785, 0.1574787050485611, 0.8918634653091431, -0.6566658616065979, -1.055477261543274, -0.9904500842094421, -1.3658781051635742, -1.9980671405792236}, {0.12702903151512146, -4.264755725860596, 0.1351483166217804, -0.20723043382167816, -0.2467646598815918, -0.13731075823307037, -0.2164659947156906, -0.14355270564556122, -0.14075502753257751, -0.25379636883735657, -0.17323608696460724, -0.1511029303073883, -0.17861734330654144, -0.15422824025154114, -0.07887014746665955, -0.16572877764701843, -0.1545283943414688, -0.18726830184459686, -0.1911981999874115, -0.22419621050357819, -0.14734145998954773, -0.1506907343864441, -0.26516038179397583, -0.17076921463012695, -0.20366378128528595, -0.2068306803703308, -0.2465706467628479, -0.07892344892024994}, {0.08080519735813141, 0.1585157960653305, 1.8969849348068237, -0.20419242978096008, -0.2912924289703369, -0.36874666810035706, -0.40501853823661804, -0.19646884500980377, -0.142297625541687, -0.22064056992530823, -0.3288157284259796, -0.32355132699012756, -0.5395388007164001, -0.5318061709403992, -0.3192610740661621, -0.27381959557533264, -0.34684738516807556, -0.5140829086303711, -0.373310923576355, -0.413587361574173, -0.2374996393918991, -0.21946990489959717, -0.3940057158470154, -0.18182581663131714, -0.3221309185028076, -0.45614495873451233, -0.12116502225399017, -0.17031502723693848}, {0.07794322818517685, -0.10273882746696472, 1.2109743356704712, 0.018595527857542038, 0.056782107800245285, -0.1575082391500473, -0.1836964339017868, 0.13944111764431, 0.026699164882302284, -0.12828998267650604, -0.10416686534881592, -0.855417013168335, -1.1240910291671753, -0.3680402934551239, -0.5175941586494446, -0.8113775849342346, -0.48369184136390686, 0.42436426877975464, -0.24796444177627563, -0.7017632126808167, -0.33427396416664124, 0.8904720544815063, 0.13182073831558228, 0.0840996578335762, -1.3255901336669922, 0.555604100227356, 0.44455230236053467, 0.6097607612609863}, {-0.034049827605485916, 0.5697606801986694, -0.9041339755058289, 1.4350972175598145, -0.1483038365840912, -0.06558208167552948, -0.2450496107339859, -0.5598021149635315, 1.3650588989257812, 0.09695714712142944, 0.20738567411899567, -0.04335039108991623, 0.010373556055128574, 0.9249184727668762, 0.25404757261276245, 0.1163429543375969, -0.04122623801231384, 0.07139857113361359, 1.4624335765838623, 0.3055124580860138, 0.008223910816013813, -0.06609079241752625, 0.09183429181575775, 1.1958849430084229, 0.025186588987708092, 0.029254700988531113, 0.07879947870969772, -0.4418580234050751}, {0.07264219224452972, -0.8118353486061096, 0.5850833058357239, -0.04886290058493614, -0.21201711893081665, -0.2038731724023819, -0.044785141944885254, 0.33473384380340576, -0.3806909918785095, -0.3222631812095642, -0.1784955859184265, -0.07884243875741959, -0.04943345859646797, -0.7509729266166687, -0.2586313784122467, -0.11834448575973511, -0.3176766037940979, 0.029591834172606468, -0.6633329391479492, 0.31418582797050476, 0.1703609675168991, -0.1421850472688675, -0.09780556708574295, -2.4741933345794678, -0.007773654069751501, -0.2453930675983429, -0.10803715884685516, -0.10720524936914444}, {0.04180590435862541, -0.47792956233024597, 0.5036258101463318, -2.0397746562957764, 0.2890857756137848, 0.31826984882354736, 0.06372813880443573, -0.09525591135025024, -0.5323511362075806, 0.10418450832366943, 0.19146449863910675, 0.11332566291093826, -0.07695935666561127, -0.4690433442592621, -0.19135060906410217, 0.01175900548696518, -0.009661716409027576, 0.09737563133239746, -0.14801274240016937, -0.26320526003837585, -0.08077298104763031, -0.05239444971084595, -9.216830221703276e-05, -0.06783001869916916, -0.2219526469707489, -0.1100030168890953, 0.06168339401483536, -0.01574299857020378}}; +{{0.0335812121629715, -0.21365489065647125, -0.653753936290741, -0.13572198152542114, 0.18898768723011017, 0.06430475413799286, 0.1521165519952774, -0.6386323571205139, 0.5113293528556824, 0.3224753439426422, 0.3006350100040436, 0.4426257014274597, -0.4259096086025238, 0.34491172432899475, 0.26074907183647156, 0.30206671357154846, 0.2114274799823761, -0.5099963545799255, 0.38777005672454834, 0.23917558789253235, 0.32478395104408264, 0.2528369724750519, -0.5045477747917175, 0.10504062473773956, 0.34629005193710327, 0.28095799684524536, 0.31814444065093994, -0.7089307904243469}, {0.0565570704638958, -0.4527612030506134, 0.22363899648189545, -0.4776171147823334, -0.4429882764816284, 0.09122249484062195, 0.08279165625572205, 0.29376256465911865, -0.23718500137329102, -0.5789054036140442, 0.28780052065849304, 0.6442199945449829, 0.03741508722305298, -0.220468670129776, -0.644933819770813, -0.13106265664100647, 0.5042467713356018, 0.43313512206077576, 0.5279864072799683, -0.5684875249862671, -0.8156968355178833, -0.5465362668037415, -0.5424111485481262, 0.04707803204655647, 0.2047167718410492, -0.3449491560459137, -0.26257622241973877, -0.4042203426361084}, {0.002476541558280587, -0.21414169669151306, -0.11842579394578934, 0.14450429379940033, -0.01525128073990345, -0.12563736736774445, -0.27338773012161255, 0.009645791724324226, -0.25494587421417236, -0.2797246277332306, -0.2301362156867981, -0.40248778462409973, -0.2902604341506958, 0.19436009228229523, -0.11030247807502747, 0.08137191087007523, -0.1867382973432541, -0.7496097683906555, -0.008727616630494595, 0.22033251821994781, 0.19767463207244873, 0.11307194083929062, -0.8412720561027527, 0.2657962143421173, -0.07668104767799377, 0.06086883693933487, 0.3835994601249695, -1.091362476348877}, {0.05102699622511864, -0.8378904461860657, 0.4566768705844879, -0.2630152404308319, -0.23932738602161407, -0.19857573509216309, 0.30443575978279114, -0.14038261771202087, -0.14678728580474854, -0.40179580450057983, -0.35921597480773926, -0.14929337799549103, 0.12302257865667343, 0.10777170211076736, -0.12337932735681534, -0.33727583289146423, -0.28758835792541504, 0.37838035821914673, 0.3109462559223175, 0.15170936286449432, 0.17238374054431915, -0.7253879308700562, -0.23942553997039795, 0.11120962351560593, 0.2859588861465454, 0.4778689444065094, -0.679128885269165, -0.226375013589859}, {0.03254811838269234, -0.20261096954345703, -0.07562973350286484, -0.10781332850456238, -0.10312259197235107, -0.07764437049627304, -0.04054751992225647, -0.07112596929073334, -0.06557303667068481, -0.12047363817691803, -0.062015969306230545, -0.026542047038674355, -0.01934126764535904, -0.09312712401151657, -0.03113151155412197, -0.051008112728595734, -0.05768309533596039, -0.10491270571947098, -0.0717678889632225, -0.04455398768186569, -0.02723315730690956, -0.057788874953985214, -0.0033781195525079966, -0.03603564202785492, -0.006476488430052996, -0.021566126495599747, -0.04043968394398689, 0.007654271088540554}, {-0.08095347136259079, -0.26414069533348083, -0.09814666211605072, -0.04380079358816147, -0.5849603414535522, -0.7097421288490295, -0.9047000408172607, -1.3424301147460938, -0.31041404604911804, -0.25597554445266724, -0.11997552961111069, 0.20276427268981934, 0.36256903409957886, 0.019292958080768585, -0.041115161031484604, 0.12530303001403809, 0.20739392936229706, 0.3235205411911011, -0.05591806769371033, -0.05841316655278206, 0.038499265909194946, 0.18055571615695953, 0.293590784072876, 0.16785693168640137, 0.24048064649105072, 0.07176923751831055, 0.08983936905860901, 0.22106173634529114}, {-0.017707331106066704, 0.12255413830280304, -0.6240278482437134, -0.04464518278837204, -0.1846076399087906, 0.6399872899055481, 0.12881889939308167, 0.22656285762786865, -0.1679985672235489, -0.28858682513237, 0.5312493443489075, 0.049816571176052094, -0.24046465754508972, -0.1774766743183136, -0.09163064509630203, 0.7954617142677307, -0.39598366618156433, -0.4399476945400238, 0.6123018860816956, 0.45216771960258484, 0.6593272089958191, -0.07644930481910706, -0.4521935284137726, 0.012832398526370525, 0.028779083862900734, 0.6450971961021423, 0.575737714767456, 0.6349318027496338}, {-0.03650929406285286, -0.14473311603069305, -0.5584736466407776, -0.029627997428178787, -0.1539306640625, -0.12314235419034958, 0.08387640863656998, -0.0337577685713768, -0.17351587116718292, -0.19245818257331848, -0.16416308283805847, 0.016272591426968575, 0.36373433470726013, 0.04089183360338211, 0.02371835894882679, -0.22523774206638336, -0.15100933611392975, 0.45591863989830017, -0.1123512014746666, 0.061778921633958817, -0.13473178446292877, -0.40654733777046204, 0.4156742990016937, -0.03619186207652092, 0.24843069911003113, 0.29947373270988464, 0.36726078391075134, 1.2590346336364746}, {-0.1366739124059677, 0.41514185070991516, -0.2774442732334137, -0.3785100281238556, -0.43781572580337524, 0.0857686847448349, 0.548991322517395, 0.3008037805557251, -0.710213303565979, 0.02195434831082821, 0.5724306702613831, 0.5335829854011536, 0.09624887257814407, 1.017358660697937, 0.8264562487602234, 0.4335733652114868, 0.2976129651069641, -0.07695961743593216, 0.08250663429498672, 0.12967929244041443, -0.04427557811141014, 0.24989163875579834, 0.08119788765907288, 0.05688076093792915, 0.14414691925048828, -0.15780726075172424, 0.12778723239898682, 0.17664006352424622}, {0.045846302062273026, -0.4202306270599365, 0.24253332614898682, 0.058551233261823654, 0.13127459585666656, -0.08259733766317368, -0.5951005220413208, 0.010317057371139526, 0.32319802045822144, -0.2788604497909546, -0.10889868438243866, -0.6505680084228516, 0.0621410608291626, -0.22810311615467072, -0.0803237184882164, 0.4647519290447235, -0.6627072691917419, 0.20077340304851532, 0.1278313249349594, 0.021397558972239494, -0.017719708383083344, -0.65326988697052, 0.03247045353055, -0.003151470795273781, -0.089555524289608, -0.21280834078788757, -0.18042130768299103, -0.13124220073223114}, {0.08920250833034515, -0.4041590988636017, 0.11126764863729477, -0.38825124502182007, -0.37751445174217224, 0.3841644823551178, 0.13915617763996124, -0.427076131105423, -0.42071813344955444, -0.8185845017433167, -0.6395564675331116, -0.3830700218677521, -0.34343987703323364, 0.14143605530261993, 0.2065681666135788, -0.5982153415679932, -0.2753662168979645, -0.5253153443336487, 0.1136728972196579, 0.303848534822464, -0.3599269390106201, -0.48723894357681274, 0.1170220747590065, 0.1082770973443985, 0.2027408331632614, -0.6000553369522095, -0.2399190366268158, 0.21266664564609528}, {-0.044174984097480774, 0.10084715485572815, -0.7766823768615723, 0.5814716219902039, 0.2989753484725952, -0.04704820364713669, -0.23142951726913452, 0.16222569346427917, 0.026166614145040512, 0.3819707930088043, 0.0457681305706501, -0.0551467202603817, 0.09645840525627136, -0.28990161418914795, 0.11402436345815659, 0.445557564496994, 0.3328436315059662, 0.6563848853111267, -0.22550760209560394, 0.1100253015756607, -0.29362085461616516, 0.35912737250328064, 0.07314564287662506, 0.3241541087627411, -0.04152493178844452, -0.18172766268253326, 0.3779054582118988, 0.30225080251693726}, {0.0354388952255249, -0.45912227034568787, 0.07555098086595535, -0.047884486615657806, 0.12533819675445557, 0.11261603981256485, 0.5056780576705933, -0.15080063045024872, -0.14207696914672852, -0.24237896502017975, -0.4537515342235565, -0.7382211685180664, -1.396830439567566, -0.05796787142753601, -0.0972527340054512, -0.0011085039004683495, 0.15182892978191376, 0.38325998187065125, -0.013696794398128986, -0.05116301029920578, 0.24685567617416382, 0.17722700536251068, -0.011363615281879902, 0.032823070883750916, 0.23471832275390625, 0.2214534878730774, -0.12878315150737762, 0.07269603759050369}, {0.1021164283156395, -0.979482114315033, 0.10424260795116425, 0.20152615010738373, -0.4474649131298065, -0.5927112698554993, -0.4682328701019287, -0.25608980655670166, -0.03509359434247017, -0.3745705783367157, -0.5153190493583679, -0.5731074810028076, -0.558528482913971, -0.08479820191860199, -0.38562700152397156, -0.4411310851573944, -0.5317122340202332, -0.5145424604415894, -0.046643827110528946, -0.2316707819700241, -0.3664470911026001, -0.3545966148376465, -0.313737690448761, 0.09879656881093979, -0.2625102400779724, -0.306001216173172, -0.29944929480552673, 0.03161349147558212}, {-0.03801499307155609, -0.2233135849237442, -0.10620100051164627, 0.2713835537433624, 0.21967564523220062, 0.251351535320282, 0.16949021816253662, 0.15099139511585236, 0.05300286412239075, 0.08299478143453598, 0.011512423865497112, 0.01530615333467722, 0.07382016628980637, -0.18710920214653015, 0.03905392810702324, 0.16468313336372375, 0.22495073080062866, 0.3159700930118561, -0.1615748107433319, -0.16977524757385254, -0.17270493507385254, 0.1490594446659088, 0.4793047308921814, -0.0045040980912745, -0.3750409185886383, -0.5658650994300842, -0.7609032392501831, -0.9970420598983765}, {-0.06860953569412231, 0.1561063975095749, 0.41900986433029175, -0.09340472519397736, 0.05546368286013603, -0.32329270243644714, -0.3049590587615967, -0.057696402072906494, -0.17760413885116577, -0.21533682942390442, -0.06622635573148727, -0.20747050642967224, -0.13626375794410706, -0.16855809092521667, -0.06624997407197952, 0.17109455168247223, 0.265641987323761, 0.2269686758518219, -0.31261059641838074, -0.3254770040512085, -0.17686116695404053, -0.184734046459198, -0.17058107256889343, -0.13638293743133545, -0.25341087579727173, -0.06822904199361801, -0.17498566210269928, -0.15365538001060486}, {-0.09274652600288391, 0.8195863366127014, -0.6974982619285583, 0.19567207992076874, 0.3114858567714691, 0.3193179965019226, 0.3051777482032776, 0.1686609983444214, 0.28975042700767517, 0.3609328269958496, 0.34076830744743347, 0.3451266586780548, 0.2754822373390198, 0.2944789528846741, 0.3471467196941376, 0.3111295998096466, 0.36336469650268555, 0.3138508200645447, 0.3493599593639374, 0.3804861307144165, 0.3554949462413788, 0.38007041811943054, 0.304755836725235, 0.1720620095729828, 0.3196488618850708, 0.3476446270942688, 0.2819644510746002, 0.20534354448318481}, {-0.04308394342660904, 0.4313099980354309, 0.0190417543053627, -0.36723119020462036, -0.17420481145381927, 0.5145810842514038, 0.5347347855567932, 0.6282756328582764, 1.2653520107269287, 1.1850699186325073, 0.8361583352088928, 0.4141540825366974, 0.26177582144737244, 0.06430555135011673, 0.4607594609260559, -0.0807068794965744, -0.09359037131071091, 0.09638888388872147, 0.525905191898346, 0.5729591250419617, -0.02258281223475933, -0.17060524225234985, 0.12351763993501663, 0.08509236574172974, 0.4710988402366638, 0.17080940306186676, 0.250908762216568, -0.09069673717021942}, {0.07291662693023682, 0.08596876263618469, -0.08287191390991211, 0.26005038619041443, 0.46491068601608276, 0.5783225893974304, 0.15600703656673431, -0.26880383491516113, -0.17159603536128998, 0.18245145678520203, 0.6828884482383728, -0.21175506711006165, -0.057075608521699905, -0.31850534677505493, 0.12133979052305222, 0.5726630091667175, -0.07307758182287216, -0.0253745187073946, -0.05841955170035362, -0.2049519568681717, 0.542971670627594, -0.0039001810364425182, -0.027620088309049606, -0.4046057164669037, -0.07061299681663513, 0.5127297043800354, 0.17255832254886627, -0.37250733375549316}, {-0.11166863888502121, 0.055800892412662506, -0.5167198777198792, 0.2324250191450119, 0.40913817286491394, 0.6140636801719666, 0.4707394242286682, 1.522460699081421, 0.28594499826431274, 0.3309996426105499, 0.08542972803115845, -0.28014466166496277, 0.139140322804451, 0.1942225694656372, 0.1311720907688141, 0.06602678447961807, 0.13316340744495392, 0.5902721881866455, 0.03358441963791847, -0.01826644130051136, 0.2206089198589325, 0.3234162926673889, 0.29170212149620056, 0.027043171226978302, 0.2018718421459198, -0.010219907388091087, 0.35940054059028625, 0.07707080245018005}, {0.02553723379969597, 0.461318701505661, -0.4059189260005951, 0.05942573770880699, -0.010037711821496487, -0.13757778704166412, 0.22961010038852692, 0.2251977026462555, 1.0914969444274902, 0.9033216834068298, 0.83197420835495, 0.7612583637237549, 0.05771542713046074, -0.10955284535884857, -0.004019961226731539, 0.4693775475025177, 0.07826275378465652, -0.13095584511756897, -0.2168196588754654, -0.3515476584434509, 0.7580985426902771, 0.20290978252887726, -0.16279703378677368, -0.06892823427915573, -0.20307579636573792, 0.954958975315094, -0.2317219376564026, -0.1928693652153015}, {0.062168460339307785, -0.5123471617698669, -0.263359934091568, -0.7685256600379944, 0.08967547863721848, 0.24563723802566528, 0.3980844020843506, 0.3117550015449524, -0.7312137484550476, -0.06169243901968002, 0.25126340985298157, 0.2695813477039337, 0.23361706733703613, -0.969958484172821, 0.12066813558340073, 0.15110082924365997, 0.22164055705070496, 0.14506936073303223, -0.8025405406951904, 0.26169300079345703, 0.11112350225448608, 0.29015427827835083, 0.34564951062202454, -0.9369366765022278, 0.41549447178840637, 0.2582719624042511, 0.3374422788619995, 0.3025016188621521}, {-0.1270698755979538, 0.429225891828537, -0.49225398898124695, -0.11553260684013367, -0.23649732768535614, 0.8932956457138062, -0.11381787061691284, -0.300383061170578, -0.08516164869070053, -0.04815308749675751, 0.6397905349731445, 0.05467788130044937, -0.17419259250164032, 0.05954163148999214, 0.11605441570281982, 0.46235892176628113, 0.005171304568648338, -0.3957885801792145, 0.19777722656726837, 0.7243578433990479, 0.8090712428092957, 0.8684667348861694, 1.0440218448638916, 0.435382217168808, 0.20173248648643494, -0.50189208984375, -0.127868190407753, -0.049834541976451874}, {0.0026459188666194677, 0.11711517721414566, -0.7256444692611694, -0.08485592901706696, 0.9629834890365601, 0.09173507988452911, 0.244176983833313, 0.24677251279354095, 0.15705431997776031, 0.7062681913375854, -0.5933635234832764, -0.10675647109746933, 0.04850605130195618, 0.13815787434577942, 0.4868027865886688, -0.48046332597732544, 0.09973080456256866, 0.0552331916987896, 1.0236599445343018, 1.0715246200561523, 0.8364623188972473, 0.6795467138290405, 0.1431518793106079, -0.09264400601387024, -0.24593685567378998, 0.0526106022298336, 0.5356892347335815, 0.4176342785358429}, {-0.17575381696224213, 0.9493538737297058, -0.9680318832397461, 0.344186007976532, 0.37747424840927124, 0.3827437460422516, 0.3655855357646942, 0.32791411876678467, 0.3741169273853302, 0.42540842294692993, 0.4716174900531769, 0.4630044102668762, 0.4119097888469696, 0.43781936168670654, 0.4984303414821625, 0.3960149586200714, 0.4152538776397705, 0.3874683082103729, 0.37821871042251587, 0.41086938977241516, 0.436718225479126, 0.38621312379837036, 0.3685840666294098, 0.3631429970264435, 0.3682745099067688, 0.3622629940509796, 0.41871270537376404, 0.3119860589504242}, {-0.06097084656357765, 0.3522926867008209, -0.07554367929697037, 0.31942737102508545, 0.029151281341910362, 0.15592512488365173, -0.0009292215690948069, 0.18485626578330994, 0.39177006483078003, 0.2792249321937561, 0.12014344334602356, 0.09458812326192856, 0.028401147574186325, 1.115199089050293, 0.8369911313056946, 0.602891206741333, 0.28732630610466003, -0.11038826406002045, -0.5364417433738708, -0.08979910612106323, 0.6724634766578674, 0.34956303238868713, 0.27176162600517273, -0.5280332565307617, -0.5781199932098389, 0.6316017508506775, 0.41322362422943115, 0.18675293028354645}, {0.06110076978802681, 0.20676849782466888, -0.21055933833122253, 0.14543284475803375, -0.2691429555416107, 0.23192094266414642, -0.16181010007858276, -0.07387831062078476, 0.2630201280117035, -0.1249636858701706, 0.16139020025730133, 0.12681415677070618, 0.24008934199810028, 0.5166671872138977, 0.84417724609375, 0.928178071975708, 0.5734097361564636, 0.7494409680366516, 0.45103031396865845, 0.29169872403144836, -0.17037302255630493, -0.6708592176437378, 0.1958291381597519, 0.17509706318378448, 0.2388417273759842, -0.3683401942253113, -0.46702516078948975, -0.12833642959594727}, {0.00030645611695945263, -0.19412267208099365, -0.1942126452922821, 0.8911823034286499, 0.8041935563087463, 0.6952621936798096, 0.5451593399047852, 0.4937603175640106, -0.24343731999397278, -0.1464550644159317, -0.12816737592220306, 0.024196654558181763, 0.036258477717638016, -0.1814306229352951, -0.21442382037639618, -0.11105196923017502, -0.22053563594818115, -0.24859702587127686, -0.22910651564598083, -0.2101702243089676, -0.14243045449256897, -0.2865407168865204, -0.18984046578407288, -0.07871726900339127, -0.2595853805541992, -0.24533933401107788, -0.26216810941696167, -0.16304023563861847}, {0.052463531494140625, 0.1486791968345642, -0.579024612903595, 1.088742733001709, -0.13386118412017822, -0.1609494388103485, -0.09612634778022766, -0.09550110250711441, 0.9107480645179749, -0.14887897670269012, -0.017151640728116035, 0.020924121141433716, 0.04268282279372215, 0.9172422885894775, 0.04447457566857338, -0.02752840891480446, 0.022488543763756752, -0.09672117233276367, 0.8158107995986938, 0.15294760465621948, 0.04637422040104866, 0.024195043370127678, -0.08632858097553253, 0.4717424511909485, 0.18674905598163605, 0.10150022804737091, 0.025798514485359192, -0.1546076387166977}, {0.029881251975893974, 0.49499452114105225, -0.026262039318680763, 0.00900306273251772, -0.036245543509721756, -0.11946964263916016, 0.172474667429924, 0.5267413854598999, 0.07936062663793564, -0.15437465906143188, 0.16969208419322968, 0.7578750252723694, 0.4837819039821625, 0.08440805226564407, 0.20724894106388092, 0.07721617817878723, 0.7230514883995056, 0.023518960922956467, 0.3058747947216034, 0.1142619401216507, 0.08739539235830307, 0.8077057003974915, -0.38012027740478516, 0.23245155811309814, 0.10439647734165192, -0.07647071778774261, 1.3155752420425415, -0.46643584966659546}, {0.10903043299913406, -0.004875070881098509, 0.2575789988040924, 0.14737094938755035, 0.43150651454925537, -0.5420994162559509, -0.3059577941894531, -0.2527901232242584, 0.19769372045993805, 0.38301345705986023, -0.10965324938297272, -0.21152931451797485, -0.0738074779510498, 0.1658964455127716, 0.4326992332935333, 0.4845859110355377, 0.1578446626663208, -0.10062657296657562, -0.1752672642469406, -0.37322744727134705, 0.17257146537303925, 0.2496408224105835, 0.12594257295131683, -0.37234362959861755, -0.12441913038492203, -0.026296446099877357, 0.1662571132183075, -0.0028839746955782175}, {-0.014218885451555252, -0.5738092064857483, 0.23660679161548615, -0.10611919313669205, -0.12041497230529785, -0.1564393788576126, -0.2974553406238556, -0.13557544350624084, -0.03920785337686539, 0.22239501774311066, -0.6583126187324524, -0.4981720745563507, -0.34942877292633057, 0.09956511110067368, 0.07194441556930542, -0.8891360759735107, 0.09037145227193832, 0.4524118900299072, 0.1884671002626419, 0.04436931014060974, -0.9194300770759583, 0.5126015543937683, 0.5571795105934143, 0.25728949904441833, 0.03548843413591385, -1.0185256004333496, 0.30711427330970764, 0.39558374881744385}, {-0.014499297365546227, -0.6686705946922302, -0.036153871566057205, -1.3211073875427246, -0.6752616167068481, -0.7146933078765869, -0.549763023853302, -0.11895440518856049, 0.5944733619689941, 0.46897026896476746, 0.03513138368725777, -0.41634684801101685, -0.11872824281454086, 0.40422236919403076, 0.26827922463417053, 0.0015694501344114542, -0.1268347054719925, 0.18456166982650757, 0.060881517827510834, 0.1850985437631607, 0.20143119990825653, -0.07189079374074936, 0.19972868263721466, 0.16691307723522186, 0.16700705885887146, 0.14965561032295227, -0.07053949683904648, 0.2440711408853531}, {-0.30115965008735657, 0.3020112216472626, -0.6229689121246338, 0.19976438581943512, 0.25084272027015686, 0.08908466249704361, 0.12059653550386429, 0.03533867746591568, 0.2703179121017456, 0.3352479934692383, 0.3428271412849426, 0.4156206548213959, 0.3420707583427429, 0.2064814567565918, 0.35532060265541077, 0.08173895627260208, 0.07825019955635071, 0.221553236246109, 0.1776820570230484, 0.22577251493930817, 0.22278828918933868, 0.2640128433704376, 0.180125430226326, 0.11645812541246414, 0.3808441460132599, 0.1748972088098526, 0.04822747781872749, 0.20747071504592896}, {0.004458575043827295, 0.03752393275499344, 0.1197284460067749, 0.429423987865448, 0.2881259620189667, 0.6022155284881592, -0.4153423011302948, -0.5097853541374207, 0.42615923285484314, 0.44554516673088074, 0.7217490673065186, 0.8117141127586365, 0.72388756275177, 0.015255422331392765, -0.22130870819091797, 0.13519121706485748, 0.3975375294685364, 0.1678304821252823, 0.10857963562011719, -0.3138495981693268, 0.1589823067188263, 0.2486751675605774, 0.40141168236732483, 0.018049899488687515, -0.08904679864645004, -0.08511554449796677, 0.1515214890241623, 0.4401805102825165}, {-0.15634094178676605, -0.19944559037685394, -0.16159050166606903, 0.537737250328064, 0.047764409333467484, -0.14748850464820862, 0.1200181245803833, -0.07930611819028854, 0.1614770144224167, 0.7068870067596436, 0.5102498531341553, 0.8125320076942444, 0.9490340948104858, 0.2141641080379486, 0.5533105731010437, 0.23265130817890167, 0.15047943592071533, -0.514159083366394, -0.028046829625964165, 0.6813269257545471, 0.1514519900083542, -0.1020088791847229, -0.04611760750412941, 0.22561359405517578, 0.43252548575401306, -0.050761569291353226, -0.09585573524236679, -0.15603257715702057}, {-0.08421202749013901, 0.33921104669570923, -0.41581854224205017, -0.21174439787864685, 0.4582148492336273, 0.11856566369533539, 0.10920864343643188, -0.059966351836919785, 0.3425080180168152, 0.4195125102996826, 0.02871912717819214, 0.06811660528182983, 0.0683729499578476, 0.6100324988365173, 0.2850392162799835, -0.039775870740413666, -0.11169159412384033, -0.18508493900299072, 0.730349063873291, -0.10342872887849808, -0.19325177371501923, -0.12663674354553223, -0.11998621374368668, 1.3490771055221558, -0.5284110307693481, -0.12912636995315552, -0.060148727148771286, -0.1581180840730667}, {0.13426083326339722, -0.13176080584526062, 1.2296770811080933, -0.07961347699165344, -0.3992340862751007, -0.3328780233860016, -0.3540795147418976, -0.06446079909801483, -0.3728063106536865, -0.44019535183906555, -0.4748293459415436, -0.4214479923248291, -0.37979984283447266, -0.31887421011924744, -0.46707987785339355, -0.34212198853492737, -0.4332870543003082, -0.3801964819431305, -0.3589206337928772, -0.49498450756073, -0.5273376107215881, -0.4567064344882965, -0.40370914340019226, -0.004378970246762037, -0.3736163079738617, -0.3421406149864197, -0.34401506185531616, -0.011685256846249104}, {0.08239886164665222, -0.8746750354766846, 0.520552933216095, -0.2309003621339798, -0.27933767437934875, -0.20904868841171265, -0.29178568720817566, -0.056779034435749054, -0.28577834367752075, -0.25492337346076965, -0.26360198855400085, -0.2623720169067383, -0.2106320858001709, -0.11835736036300659, -0.04690302908420563, -0.06490934640169144, -0.13744433224201202, -0.21501925587654114, -0.036219630390405655, -0.11873988062143326, -0.09084317088127136, -0.2095029354095459, -0.11422516405582428, -0.016950659453868866, -0.2354726791381836, -0.17757123708724976, -0.05872594937682152, -0.23141008615493774}, {0.030258534476161003, -0.5337088108062744, -0.06049085408449173, -0.06599123775959015, -0.016824429854750633, -0.1420319825410843, -0.03433123230934143, -0.10755813121795654, -0.011755664832890034, -0.033444661647081375, -0.10537318140268326, -0.04665432870388031, -0.0709884762763977, -0.09382390230894089, -0.05977355316281319, -0.006864430848509073, -0.07894037663936615, -0.07580714672803879, -0.12620750069618225, -0.07429014146327972, -0.11756139993667603, -0.03486189246177673, -0.07912899553775787, -0.038790758699178696, -0.06529578566551208, -0.020097605884075165, -0.06760886311531067, 0.006338239647448063}, {-0.008149570785462856, -0.2281409353017807, -0.02317221276462078, 0.10482294857501984, -0.026631563901901245, -0.02272041141986847, -0.1762792021036148, -0.06379090994596481, 0.28265300393104553, 0.1829858273267746, -0.1753186285495758, -0.16000571846961975, -0.03318013623356819, 0.28647878766059875, 0.06253796070814133, -0.3300016224384308, -0.10609311610460281, -0.14531269669532776, -0.7605944275856018, -0.4989122152328491, -0.3356994390487671, -0.05982646346092224, 0.06342680007219315, -0.04135109484195709, 0.32415950298309326, 0.2208917886018753, -0.07768300175666809, -0.15703800320625305}, {0.03806011378765106, -0.6677188873291016, 0.15192484855651855, -0.16433456540107727, -0.34537896513938904, -0.020495647564530373, -0.03346096724271774, 0.223424032330513, -0.02972494252026081, -0.3487086594104767, -0.0456627681851387, -0.11218554526567459, -0.00014366689720191061, 0.4491022527217865, -0.5417236089706421, -0.6263294816017151, -0.6973318457603455, -0.9182674288749695, -0.2974551320075989, -0.7037410736083984, 0.0874515250325203, 0.14197714626789093, 0.4558337330818176, -0.5843172669410706, -0.5606727004051208, 0.45348820090293884, 0.44328850507736206, 0.4209005534648895}, {-0.08474959433078766, 0.15526627004146576, -0.7985652089118958, 0.21260187029838562, 0.3656609356403351, 0.12335719168186188, 0.060457415878772736, 0.24970696866512299, 0.4984481930732727, 0.3631579279899597, 0.26680564880371094, 0.5937404036521912, 0.2675668001174927, 0.26715323328971863, -0.2635864317417145, -0.6670373678207397, 0.5595815181732178, 0.3275291323661804, 0.3265022933483124, -0.0923314318060875, 0.2361195683479309, 0.8254050016403198, 0.5882598757743835, 0.8333842158317566, 0.4826344847679138, 0.6576237082481384, 0.013852320611476898, -0.13133659958839417}, {-0.03767941892147064, -0.16735343635082245, 0.07242633402347565, 0.09715986251831055, -0.08629732578992844, -0.12105050683021545, 0.19429436326026917, -1.189113974571228, -0.0438414141535759, -0.13045798242092133, 0.17313389480113983, 0.222298264503479, -0.6784869432449341, 0.044389013200998306, -0.04566064849495888, 0.1745270937681198, -0.18878957629203796, -0.68072509765625, -0.17901289463043213, -0.13348782062530518, -0.280407577753067, -0.5236465930938721, -0.09434037655591965, 0.3562553822994232, -0.14296357333660126, -0.17816492915153503, -0.262240469455719, 0.2708267867565155}, {-0.14643076062202454, 0.3134414553642273, -0.016158653423190117, 0.4832289218902588, 0.35327669978141785, 0.033485930413007736, 1.404250144958496, -0.4109203517436981, 0.3232615888118744, 0.03948039561510086, 0.14370359480381012, 1.0806249380111694, -0.43028610944747925, 0.19681444764137268, 0.3559668958187103, 0.24551646411418915, 0.7668668031692505, 0.26227831840515137, 0.24610893428325653, 0.03931723162531853, 0.1685093492269516, 0.42881014943122864, 0.605613648891449, 0.07715323567390442, 0.2259686291217804, 0.12414932996034622, 0.28258103132247925, 0.6711070537567139}, {-0.03460083529353142, 0.015175103209912777, -0.0020290936809033155, -0.2801230251789093, -0.049781594425439835, -0.08237257599830627, -0.24321754276752472, -0.30726316571235657, -0.1131473034620285, -0.016173556447029114, -0.0010477738687768579, -0.20699340105056763, -0.2045988142490387, -0.10566984117031097, -0.0597367063164711, -0.1446806639432907, -0.008996298536658287, -0.1636381596326828, -0.34909534454345703, -0.10394063591957092, 0.07907130569219589, 0.0491563156247139, 0.07572714239358902, 0.8712359666824341, 0.8652707934379578, 0.8136559128761292, 0.7329977750778198, 0.4842419922351837}, {0.028292212635278702, -0.6930311322212219, 0.4168195426464081, -0.722553014755249, 0.6128503084182739, 0.37802034616470337, -0.12130801379680634, -0.16137754917144775, -0.4547799825668335, 0.019849296659231186, -0.07699695229530334, 0.02751479111611843, 0.11456470936536789, -0.46225056052207947, -0.4128100574016571, -0.21820463240146637, -0.05070912092924118, -0.012455608695745468, 0.17457029223442078, -0.6548964381217957, 0.2514891028404236, 0.09665688127279282, -0.023784032091498375, 0.34345829486846924, -1.0899158716201782, 0.057933658361434937, -0.10579057782888412, -0.09446477890014648}, {0.06298044323921204, -0.5140762329101562, 0.10901061445474625, 0.25055184960365295, 0.16310572624206543, 0.1660183221101761, -0.2003139704465866, -0.25939759612083435, -0.759786069393158, -0.5441654324531555, -0.433865487575531, -0.2903525233268738, 0.20317135751247406, -0.05961161479353905, 0.1883774697780609, 0.07006954401731491, -0.348635733127594, 0.00569637306034565, -0.12705902755260468, 0.06386853754520416, 0.30274978280067444, -0.06455851346254349, -0.16498570144176483, -0.2735350728034973, -0.05759710818529129, -0.09640154242515564, -0.2553178668022156, 0.1108042374253273}, {0.16303423047065735, -0.840851902961731, 0.3045694828033447, 0.5177968144416809, 0.010460598394274712, -0.0009595230803824961, -0.164739727973938, -0.2865234613418579, -0.1834029257297516, 0.4267294108867645, 0.0837775319814682, -0.5739225745201111, -0.17942845821380615, 0.06667495518922806, 0.46038922667503357, 0.14962272346019745, -0.34685906767845154, 0.23869825899600983, -0.28814902901649475, -0.7657412886619568, -0.866352379322052, -0.9862637519836426, -0.18093055486679077, -0.2750402092933655, -0.2612379789352417, 0.14520415663719177, 0.41632893681526184, -0.3018798232078552}, {-0.15189743041992188, 0.24816209077835083, -0.39726874232292175, 0.10362628102302551, 0.22738219797611237, 0.13067540526390076, 0.29548943042755127, 0.37722209095954895, 0.17870138585567474, 0.2407064139842987, 0.19497083127498627, 0.3211122453212738, -0.09292492270469666, -0.12265130877494812, 0.4053817391395569, -0.11827366054058075, 0.45297837257385254, 0.11928819864988327, 0.9772109389305115, 0.5449104905128479, 0.39806750416755676, 0.4030953049659729, 0.16402702033519745, -0.14901259541511536, -0.15305542945861816, 0.16489744186401367, 0.21413367986679077, 0.5390959978103638}, {-0.054573457688093185, -0.22824183106422424, -0.3203968405723572, -0.15810002386569977, 0.5835301876068115, 0.38719215989112854, 0.4236435294151306, 0.640129566192627, -0.14881178736686707, 0.47540283203125, 0.09412529319524765, 0.06462755799293518, -0.6389226317405701, -0.10056259483098984, 0.5633905529975891, 0.08276329189538956, -0.1411363184452057, -0.009574373252689838, -0.03582749515771866, 0.6443657279014587, -0.017103971913456917, -0.17268119752407074, 0.06117372587323189, -0.04281193017959595, 0.7488794922828674, -0.06866982579231262, 0.06887611001729965, -0.11549514532089233}, {0.01342778280377388, -0.4836217761039734, -0.11072295904159546, 0.6476761698722839, 0.5931163430213928, -0.7808675169944763, -0.35797253251075745, -0.2272079437971115, 0.7021985054016113, -0.022765103727579117, -0.8641810417175293, -0.20821577310562134, -0.1716800034046173, -0.2285567671060562, -0.4907127618789673, -0.4427620768547058, 0.20067904889583588, 0.24365925788879395, -0.2677304446697235, -0.33728840947151184, 0.0702209398150444, 0.09022712707519531, 0.1330493539571762, -0.3614550530910492, -0.30246731638908386, 0.012839858420193195, 0.3226088583469391, 0.06072837859392166}, {-0.040193911641836166, -0.6861724853515625, -0.4070025682449341, 0.1424286812543869, 0.21161821484565735, 0.36073726415634155, 0.3628085255622864, -0.0990212932229042, 0.42990466952323914, 0.5575714707374573, 0.37092170119285583, 0.2522738575935364, 0.1157609149813652, 0.47637075185775757, 0.48690155148506165, 0.30947044491767883, 0.2960883677005768, 0.07852909713983536, 0.3973768353462219, 0.13431915640830994, 0.36592432856559753, 0.17452998459339142, 0.13116753101348877, -0.42777925729751587, -0.37024176120758057, -0.43283072113990784, -0.5338147878646851, -0.4905080199241638}, {-0.12332254648208618, 0.23759916424751282, -0.2621895968914032, 0.03406616672873497, 0.5511227250099182, -0.12509968876838684, -0.4177529215812683, -0.47927144169807434, 0.14296410977840424, 0.4820209741592407, 0.22033001482486725, -0.13066789507865906, -0.7484548091888428, 0.23563754558563232, 0.2622942626476288, 0.582843542098999, 0.7955005764961243, 0.9946928024291992, 0.14746436476707458, 0.043333325535058975, -0.07848695665597916, 0.10714565217494965, 0.12493138015270233, 0.1611987203359604, 0.04742865636944771, -0.26901474595069885, -0.10293031483888626, 0.010696852579712868}, {0.04099375382065773, -3.2305996417999268, 0.2543967366218567, -0.059577129781246185, -0.14682938158512115, -0.0733993723988533, -0.07150989025831223, -0.08204008638858795, -0.12635663151741028, -0.10393626242876053, -0.022796161472797394, 0.007641270756721497, -0.08665978163480759, -0.01694418303668499, -0.0025942830834537745, -0.03163212165236473, -0.022262264043092728, -0.07357636839151382, -0.07581206411123276, -0.06286846846342087, -0.1153038740158081, -0.04352688044309616, -0.08158870041370392, -0.08570341020822525, -0.06179278343915939, -0.11247510462999344, 0.0021329170558601618, -0.029320182278752327}, {0.029462160542607307, -0.5271976590156555, 0.18926401436328888, 0.02871791645884514, -0.23120182752609253, -0.786915123462677, 0.6471821665763855, 0.4379161298274994, 0.20970848202705383, -0.06591341644525528, -0.7760671973228455, 0.38167643547058105, 0.5764249563217163, 0.014545980840921402, 0.17091333866119385, -0.9253398776054382, -0.09902273863554001, -0.05899110808968544, 0.4204649329185486, 0.21064306795597076, -0.5640349984169006, -0.24353162944316864, -0.18500371277332306, -0.026613807305693626, -0.06437907367944717, -0.34146401286125183, -0.35460934042930603, -0.2743520736694336}, {-0.052965063601732254, -0.5605072379112244, 0.07962799817323685, -0.02648513950407505, -0.2291896939277649, -0.16507042944431305, -0.016116635873913765, 0.4122294485569, 0.023346038535237312, 0.06569206714630127, -0.0031419098377227783, 0.18163825571537018, 0.08935528993606567, -0.09544392675161362, -0.3773246705532074, 0.0589076466858387, 0.40520086884498596, -0.07905229926109314, -0.49348345398902893, -0.35177019238471985, -0.5805748105049133, 0.30384382605552673, 0.058458756655454636, -0.26937973499298096, -0.2887529134750366, -0.48755502700805664, 0.22864623367786407, 0.08268418908119202}, {-0.1134001687169075, -0.1595868170261383, 0.14256395399570465, 0.029054423794150352, 0.15920008718967438, 0.11821631342172623, 0.41081133484840393, 0.22583164274692535, 0.4875009059906006, -0.017819786444306374, 0.18353310227394104, 0.18164801597595215, 0.5451951622962952, 0.04068929702043533, 0.5024164319038391, 0.4954160749912262, 0.15857921540737152, 0.07034330070018768, 0.10076071321964264, -0.22763016819953918, 0.3141815662384033, 0.10078883916139603, 0.3922852873802185, 0.34453365206718445, 0.168269544839859, 0.42013704776763916, 0.07419819384813309, -0.14518938958644867}, {-0.06957618147134781, -0.06440338492393494, -0.7259829640388489, 0.5161219835281372, 0.09093577414751053, 0.4290890097618103, 0.4202098250389099, -0.027972804382443428, 0.545386791229248, 0.44505423307418823, -0.12706060707569122, 0.10054849833250046, 0.056948449462652206, 0.08831918239593506, 0.8375925421714783, 0.025092219933867455, 0.21887224912643433, 0.2599436938762665, -0.6995351910591125, 0.9659162163734436, 0.2467847764492035, 0.5137833952903748, 0.21108582615852356, -0.11285984516143799, 1.2240996360778809, -0.16404935717582703, 0.22046460211277008, 0.013526036404073238}, {-0.004826321732252836, -0.005929495673626661, 0.07865772396326065, -0.35655465722084045, -0.260633260011673, -0.37299594283103943, -0.3571874499320984, 0.6748940348625183, -0.013674028217792511, -0.27069777250289917, -0.28626859188079834, -0.02211541309952736, 0.8759161233901978, -0.2193540334701538, -0.2950937747955322, -0.1518949717283249, -0.01741132326424122, 0.7278527617454529, -0.10758645832538605, -0.14286479353904724, -0.12058365345001221, 0.05432174354791641, 0.7359171509742737, -0.20074452459812164, -0.24474677443504333, -0.20014965534210205, -0.2710004448890686, 0.5048877596855164}, {0.06318517029285431, -0.06626387685537338, 0.09102978557348251, 0.2806074619293213, -0.5871695280075073, 0.01448263693600893, -0.17774152755737305, -0.015175321139395237, 0.26823174953460693, -0.5144285559654236, -0.10162042826414108, -0.11051122844219208, -0.056919533759355545, -0.0963352620601654, -0.292245477437973, 0.07747644931077957, 0.049891501665115356, 0.04416292905807495, -0.10346058011054993, -0.27070391178131104, 0.16639839112758636, 0.13697180151939392, -0.03080388717353344, -0.3958549499511719, -0.08085988461971283, -0.15026159584522247, -0.2458583563566208, -0.1183728277683258}, {-0.031412992626428604, -0.5603559017181396, 0.23181116580963135, 0.13550354540348053, 0.1384330689907074, 0.466655433177948, 0.013126186095178127, -0.1315859854221344, 0.19236598908901215, 0.18724070489406586, 0.3651496469974518, -0.2081764191389084, -0.21705558896064758, -0.8947001695632935, -0.8844435811042786, -0.9548132419586182, -0.8363487720489502, -0.43193918466567993, 0.14401763677597046, 0.17948108911514282, 0.22730839252471924, -0.05247826129198074, -0.04454374313354492, 0.22061742842197418, 0.2703307569026947, 0.2895837426185608, -0.10765346139669418, -0.1715518683195114}, {-0.08773751556873322, 0.1905992329120636, -0.1878463476896286, -0.06142798811197281, -0.07157573848962784, -0.15859191119670868, 0.2888740599155426, 0.29501354694366455, -0.18804210424423218, 0.03719957917928696, 0.04348141327500343, 0.43497395515441895, 0.3348860740661621, 0.046619195491075516, -0.012931774370372295, 0.43330755829811096, 0.783429741859436, 0.7513718605041504, 0.42782992124557495, 0.4602666199207306, 0.8619009256362915, 0.21070736646652222, -0.6946675181388855, 0.36241528391838074, 0.5762568712234497, 0.41478705406188965, -0.7064434289932251, -0.7981423139572144}, {0.0158368032425642, -0.46186450123786926, -0.04968561232089996, 0.08248921483755112, 0.09503590315580368, -0.02358037419617176, -0.31207606196403503, 0.5838796496391296, -0.015739191323518753, 0.14295169711112976, 0.06756915897130966, -0.23699864745140076, -0.031251370906829834, 0.044411782175302505, 0.07595864683389664, -0.06131885573267937, -0.2911010682582855, -0.03894522413611412, 0.26580068469047546, 0.10324547439813614, -0.22770865261554718, -0.43839356303215027, -0.10662800073623657, -1.1684633493423462, -0.6824188828468323, -0.5405550003051758, -0.3048187494277954, 0.12504103779792786}}; const float dense1_biases[DENSE_NUM] = -{-1.7320090532302856, -1.6262712478637695, -0.7219676971435547, -1.6883859634399414, -1.355366587638855, -1.4961345195770264, -1.6774159669876099, -1.9836738109588623, -1.8204424381256104, -1.6768863201141357, -1.5860340595245361, 0.4256221652030945, -1.9900296926498413, -2.060673952102661, -1.487168788909912, -1.653613567352295, -0.49618664383888245, -1.0318562984466553, -1.2956619262695312, -2.130068778991699, -2.124798536300659, -1.6073938608169556, -1.4884546995162964, -1.7450541257858276, -1.508810043334961, -1.4361188411712646, -1.4151768684387207, -1.6134501695632935, -1.9257988929748535, -1.8976153135299683, -1.6919738054275513, -1.7137935161590576, -0.9487504363059998, -0.7779767513275146, -2.0696449279785156, -0.4453120529651642, -0.8720207214355469, -2.00007963180542, -1.6582602262496948, -0.6423311233520508, -1.3238186836242676, -1.8345296382904053, -1.4237842559814453, -0.6334408521652222, -1.3415791988372803, -1.5188286304473877, -1.5377963781356812, -1.4456733465194702, -1.7134979963302612, -1.762224793434143, -1.760365605354309, -1.7037813663482666, -1.612302541732788, -1.613434910774231, -1.8743529319763184, -1.6047550439834595, -1.9443285465240479, -1.041770577430725, 0.48393940925598145, -1.487646460533142, -2.1693429946899414, -1.207763671875, -0.9444307684898376, -1.1276359558105469}; +{-0.1444406658411026, -0.9969395995140076, -0.6437257528305054, -0.5090100169181824, -0.4562266170978546, -0.7947681546211243, -0.66095370054245, -0.0757993534207344, -0.6305758357048035, -0.6522586345672607, -0.6137698292732239, 0.06795938313007355, -0.5988752841949463, -0.022649021819233894, -0.559893012046814, -0.34122252464294434, 0.21291229128837585, -0.9544443488121033, -0.5839042663574219, -0.3325875997543335, -0.8768086433410645, -0.3371303975582123, -0.804802417755127, -0.7296857833862305, -0.24707458913326263, -0.9100144505500793, -0.7247095704078674, -0.6324146389961243, -0.42117181420326233, -1.2145949602127075, -0.7118635177612305, -0.9112556576728821, -0.21369697153568268, -0.10298735648393631, -0.8274878263473511, -0.6126794219017029, -0.7786099314689636, -0.5083696246147156, -0.38434338569641113, -0.468181848526001, -0.5246707201004028, -0.6266580820083618, -0.3932459354400635, -0.6446056365966797, -0.8690927028656006, -0.7806448936462402, -0.7514670491218567, -0.4992736577987671, -0.4725331962108612, -0.8359085321426392, -0.3995131254196167, -0.701408326625824, 0.13735836744308472, -0.7701425552368164, 0.37747254967689514, -0.8496323227882385, -0.41388845443725586, -0.3626680374145508, -0.4750637412071228, -1.0076007843017578, -0.4247843325138092, -0.8280375599861145, -0.8584521412849426, -0.49181294441223145}; const float output_weights[2][DENSE_NUM] = -{{-0.1246807649731636, -0.08505872637033463, -0.0652783066034317, 0.1350107192993164, 0.1698562055826187, 0.400063693523407, 0.17860691249370575, -0.1349184215068817, 0.20356398820877075, 0.16311302781105042, -0.036207523196935654, 0.7803400754928589, -0.13074463605880737, -0.06796154379844666, 0.20493201911449432, 0.14702282845973969, -0.11247620731592178, 0.22241809964179993, 0.1635751873254776, -0.08345462381839752, -0.2028568834066391, 0.12081773579120636, -0.1835630089044571, 0.1626814305782318, 0.16333818435668945, -0.27365756034851074, 0.13540410995483398, -0.13346917927265167, -0.1633249968290329, 0.17652902007102966, 0.1970495879650116, -0.0996168851852417, 0.1257164627313614, -0.02319495752453804, 0.1254752278327942, 0.004205659963190556, -0.11657992005348206, -0.13747099041938782, -0.12851183116436005, -0.13266359269618988, 0.15070892870426178, 0.18036587536334991, -0.120721235871315, -0.07944180071353912, -0.07511389255523682, -0.14644883573055267, 0.11276227235794067, 0.1335425227880478, -0.12701821327209473, 0.20198681950569153, -0.06599707156419754, -0.14891819655895233, 0.2015286684036255, 0.17373384535312653, 0.1385129988193512, 0.1480085849761963, 0.20751388370990753, -0.127104252576828, -0.5856947302818298, -0.26959943771362305, -0.10330907255411148, 0.14857497811317444, -0.168384850025177, -0.23837287724018097}, {0.05711914226412773, 0.1704198718070984, 0.07292810082435608, -0.1523439884185791, -0.20949530601501465, -0.33654606342315674, -0.23295333981513977, 0.09389320015907288, -0.23792678117752075, -0.17215877771377563, 0.06109726428985596, -0.7076484560966492, 0.0808710902929306, 0.06764110177755356, -0.08750396966934204, -0.12129006534814835, 0.08196759223937988, -0.22181545197963715, -0.10018306225538254, 0.09599480032920837, 0.2410762906074524, -0.16045424342155457, 0.12080714106559753, -0.14531971514225006, -0.14728260040283203, 0.389263778924942, -0.14980417490005493, 0.14908818900585175, 0.1427009552717209, -0.18783621490001678, -0.17802631855010986, 0.10279617458581924, -0.1660611927509308, 0.03492075577378273, -0.0730394646525383, 0.011791321448981762, 0.09671367704868317, 0.10834173858165741, 0.12392941862344742, 0.08413772284984589, -0.18994614481925964, -0.20133660733699799, 0.07802799344062805, 0.06276662647724152, 0.06052928790450096, 0.12486152350902557, -0.10323746502399445, -0.1355014443397522, 0.16498015820980072, -0.2137404978275299, 0.10234697163105011, 0.12195070087909698, -0.15739789605140686, -0.13428226113319397, -0.0960799902677536, -0.1424444168806076, -0.18782544136047363, 0.14121107757091522, 0.6669175624847412, 0.2753967046737671, 0.09798707813024521, -0.16682972013950348, 0.1646665632724762, 0.24278126657009125}}; +{{-0.10164133459329605, -0.06545510143041611, -0.12559004127979279, -0.09770263731479645, 0.020511239767074585, -0.11956804245710373, 0.0725698173046112, 0.09884587675333023, 0.03334106504917145, -0.07531746476888657, -0.04404358193278313, 0.04667624458670616, -0.10733920335769653, 0.11603111028671265, -0.09832630306482315, -0.029710080474615097, 0.6112914681434631, 0.09875980764627457, 0.04528747498989105, 0.04975724592804909, 0.05296019837260246, -0.1494731307029724, 0.06372635811567307, 0.05117323249578476, -0.4960876405239105, 0.08172430098056793, 0.09049712121486664, 0.16494503617286682, 0.12463495880365372, 0.10889994353055954, 0.0901939794421196, -0.07425925135612488, -0.09327994287014008, 0.07225991785526276, 0.0995996817946434, 0.1002214103937149, 0.13605892658233643, -0.2738678455352783, 0.07213583588600159, 0.031051557511091232, -0.09413432329893112, -0.05657240375876427, 0.023954149335622787, -0.11132869869470596, 0.0918613076210022, 0.1731780767440796, -0.048148252069950104, -0.08594620227813721, -0.07079077512025833, 0.028347637504339218, 0.04007003828883171, -0.08521876484155655, -0.13736766576766968, 0.0973486453294754, -0.3953056037425995, -0.09303829818964005, 0.0926792323589325, 0.08662958443164825, 0.07239469885826111, 0.12995171546936035, -0.08624651283025742, -0.13703757524490356, 0.1074426919221878, -0.05400789529085159}, {0.09475231915712357, 0.10763916373252869, 0.10490848124027252, 0.051702577620744705, -0.025973767042160034, 0.1243276372551918, -0.09184729307889938, -0.09110323339700699, -0.10927686840295792, 0.07648954540491104, 0.08314546942710876, -0.054432936012744904, 0.11420167982578278, -0.14501862227916718, 0.07449985295534134, 0.04114171117544174, -0.5540419816970825, -0.11702275276184082, -0.057106584310531616, -0.11389349400997162, -0.04799086973071098, 0.11528362333774567, -0.10561501979827881, -0.06099977344274521, 0.5406088829040527, -0.07843243330717087, -0.07121624052524567, -0.15534670650959015, -0.10739737004041672, -0.10599866509437561, -0.03090781159698963, 0.1024080142378807, 0.11164399981498718, -0.10347762703895569, -0.09762325882911682, -0.044070787727832794, -0.1382112205028534, 0.2635824978351593, -0.013381495140492916, -0.017522230744361877, 0.09075458347797394, 0.08058229833841324, -0.03840004280209541, 0.08596818149089813, -0.10802465677261353, -0.17988164722919464, 0.08185803890228271, 0.09076226502656937, 0.042497776448726654, -0.0991385206580162, -0.03188726678490639, 0.0789727196097374, 0.12080144137144089, -0.12002957612276077, 0.3941708207130432, 0.07739747315645218, -0.04954647645354271, -0.10626203566789627, -0.054530855268239975, -0.19077910482883453, 0.07939524203538895, 0.10724455863237381, -0.09315766394138336, 0.07806982845067978}}; const float output_bias[2] = -{0.5831990242004395, 0.4281694293022156}; +{0.3762611150741577, 0.6172211170196533}; diff --git a/include/weights.h b/include/weights.h index c4e0c3c..7a37ed9 100644 --- a/include/weights.h +++ b/include/weights.h @@ -15,10 +15,9 @@ along with ct. If not, see <https://www.gnu.org/licenses/>. */ -#define INP_NUM 3 + 5*5 +#define INP_NUM 3 + 5 * 5 #define DENSE_NUM 64 - extern const float dense1_weights[DENSE_NUM][INP_NUM]; extern const float dense1_biases[DENSE_NUM]; extern const float output_weights[2][DENSE_NUM]; diff --git a/include/xorshift64.h b/include/xorshift64.h index b9ba97a..c3542c6 100644 --- a/include/xorshift64.h +++ b/include/xorshift64.h @@ -22,13 +22,14 @@ extern uint64_t xors; -#define XORSHIFT64 { \ - xors ^= xors >> 12; \ - xors ^= xors << 25; \ - xors ^= xors >> 27; \ +#define XORSHIFT64 \ + { \ + xors ^= xors >> 12; \ + xors ^= xors << 25; \ + xors ^= xors >> 27; \ } -#define RANDOM64 (xors*0x2545F4914F6CDD1D) +#define RANDOM64 (xors * 0x2545F4914F6CDD1D) #define RANDOM32 ((uint32_t)RANDOM64) #endif diff --git a/include/zobrist.c b/include/zobrist.c index 1fdd8a9..d8d1856 100644 --- a/include/zobrist.c +++ b/include/zobrist.c @@ -27,13 +27,14 @@ static uint64_t *zobrist; // Exported method implementations // =================================================================== -int zobrist_init(void) { - if (zobrist != NULL) return EXIT_FAILURE; +int zobrist_init(const uint8_t board_size) { + if (zobrist != NULL) + return EXIT_FAILURE; - zobrist = malloc(sizeof(uint64_t)*board_size*board_size*(15*2*3)); + zobrist = malloc(sizeof(uint64_t) * board_size * board_size * (15 * 2 * 3)); // TODO: trap errno - for (int k=0; k<board_size*board_size*(15*2*3); k++) { + for (int k = 0; k < board_size * board_size * (15 * 2 * 3); k++) { XORSHIFT64; zobrist[k] = RANDOM64; } @@ -48,14 +49,14 @@ void zobrist_free(void) { } } -uint64_t zobrist_compute(void) { +uint64_t zobrist_compute(tak_state_p state) { uint64_t hash = 0; - for (uint8_t l=0; l<board_size*board_size; l++) { - colour_stack_t c = colours[l]; - const uint8_t count = COUNT_AT(l); - enum STONE_VARIANT s = STONE_AT(l); - for (uint8_t h=0; h<count; h++, c >>= 1) - hash ^= zobrist[l*(15*2*3)+h*2*3+(c&1)*3+s]; + for (uint8_t l = 0; l < state->board_size * state->board_size; l++) { + colour_stack_t c = state->colours[l]; + const uint8_t count = COUNT_AT(state, l); + enum STONE_VARIANT s = STONE_AT(state, l); + for (uint8_t h = 0; h < count; h++, c >>= 1) + hash ^= zobrist[l * (15 * 2 * 3) + h * 2 * 3 + (c & 1) * 3 + s]; } return hash; } diff --git a/include/zobrist.h b/include/zobrist.h index be93910..6a1de4f 100644 --- a/include/zobrist.h +++ b/include/zobrist.h @@ -15,12 +15,12 @@ along with ct. If not, see <https://www.gnu.org/licenses/>. */ -#include <xorshift64.h> -#include <tak.h> #include <actions.h> +#include <tak.h> +#include <xorshift64.h> void zobrist_free(void); -int zobrist_init(void); +int zobrist_init(const uint8_t board_size); -uint64_t zobrist_compute(void); +uint64_t zobrist_compute(tak_state_p state); diff --git a/resources/extract.sh b/resources/extract.sh index d475a1d..695656e 100755 --- a/resources/extract.sh +++ b/resources/extract.sh @@ -2,7 +2,8 @@ db_file=games_anon.db -chosen_players="AaaarghBot Tiltak_Bot TakticianBot" +#chosen_players="AaaarghBot Tiltak_Bot TakticianBot" +chosen_players="" query() { query="(size == $1) and (result != '1-0') and (result != '0-1') and (result != '0-0') and (result != '1/2-1/2')" diff --git a/src/ct1986.c b/src/ct1986.c index f9046ce..8a49ec1 100644 --- a/src/ct1986.c +++ b/src/ct1986.c @@ -23,47 +23,46 @@ #include <ncurses.h> -#include <tak.h> -#include <negamax.h> #include <lcdlib.h> - +#include <negamax.h> +#include <tak.h> static int human; static char *gamelog = 0; -static void -new_game(uint8_t size) { - reset_state(size); - lcd_printf_line(L_SCROLL, "New 5s game @ D%d", - negamax_search_depth); - if (gamelog) gamelog = realloc(gamelog, sizeof(char)); - else gamelog = malloc(sizeof(char)); +tak_state_p state; + +static void new_game(uint8_t size) { + reset_state(state, size); + lcd_printf_line(L_SCROLL, "New 5s game @ D%d", negamax_search_depth); + if (gamelog) + gamelog = realloc(gamelog, sizeof(char)); + else + gamelog = malloc(sizeof(char)); gamelog[0] = 0; } -static int -append_to_gamelog(const char *line, const uint8_t win_line) { +static int append_to_gamelog(const char *line, const uint8_t win_line) { // I _could_ dynamically compute the size but ... don't let // `perfect' be the enemy of `good' ? - if (gamelog == NULL) return EXIT_FAILURE; + if (gamelog == NULL) + return EXIT_FAILURE; char prepend[8]; if (win_line) { prepend[0] = '\n'; prepend[1] = 0; - } else if (ply & 1) { - snprintf(prepend, 7, "%s%d. ", - (ply == 1) ? "" : "\n", ply/2+1); + } else if (state->ply & 1) { + snprintf(prepend, 7, "%s%d. ", (state->ply == 1) ? "" : "\n", + state->ply / 2 + 1); } else { strcpy(prepend, " "); } // Make room for this line - gamelog = realloc(gamelog, - strlen(gamelog) - + strlen(prepend) - + strlen(line) + 1); + gamelog = + realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); // TODO: trap errno strcat(gamelog, prepend); strcat(gamelog, line); @@ -71,127 +70,151 @@ append_to_gamelog(const char *line, const uint8_t win_line) { return EXIT_SUCCESS; } -static void -end_game(char *line, char *win) { +static void end_game(char *line, char *win) { append_to_gamelog(line, 0); append_to_gamelog(win, 1); lcd_printf_line(L_SCROLL, "Game over: %s", win); } -static int -handle_turn(char *line) { +static int handle_turn(char *line) { // Track win state - uint8_t new_win = (won == 0xFF); - switch (do_ptn(line)) { - // Errors - case ACT_INVALID_PTN: { - lcd_put_line(L_SCROLL, "Invalid PTN."); - break; - } - case ACT_ILLEGAL: { - lcd_put_line(L_SCROLL, "Illegal ply."); - break; } - case ACT_OVERFLOW: { - lcd_put_line(L_SCROLL, "Overflow."); - break; - } - // Game has ended - case GAME_END: { - // Did it end this turn? - if (new_win) { - switch (won) { - case WIN_DRAW: { end_game(line,"1/2-1/2"); break; } - case WIN_FLAT_BLACK: { end_game(line,"0-F"); break; } - case WIN_FLAT_WHITE: { end_game(line,"F-0"); break; } - case WIN_ROAD_BLACK: { end_game(line,"0-R"); break; } - case WIN_ROAD_WHITE: { end_game(line,"R-0"); break; } - } - return EXIT_SUCCESS; - } else { - lcd_put_line(L_SCROLL, "Game over."); - break; + uint8_t new_win = (state->won == 0xFF); + switch (do_ptn(state, line)) { + // Errors + case ACT_INVALID_PTN: { + lcd_put_line(L_SCROLL, "Invalid PTN."); + break; + } + case ACT_ILLEGAL: { + lcd_put_line(L_SCROLL, "Illegal state->ply."); + break; + } + case ACT_OVERFLOW: { + lcd_put_line(L_SCROLL, "Overflow."); + break; + } + // Game has ended + case GAME_END: { + // Did it end this turn? + if (new_win) { + switch (state->won) { + case WIN_DRAW: { + end_game(line, "1/2-1/2"); + break; + } + case WIN_FLAT_BLACK: { + end_game(line, "0-F"); + break; + } + case WIN_FLAT_WHITE: { + end_game(line, "F-0"); + break; + } + case WIN_ROAD_BLACK: { + end_game(line, "0-R"); + break; + } + case WIN_ROAD_WHITE: { + end_game(line, "R-0"); + break; + } } - } - // Valid, append to game log - default: { - append_to_gamelog(line, 0); return EXIT_SUCCESS; + } else { + lcd_put_line(L_SCROLL, "Game over."); + break; } } + // Valid, append to game log + default: { + append_to_gamelog(line, 0); + return EXIT_SUCCESS; + } + } return EXIT_FAILURE; } - // Set up output function for negamax static uint32_t perc; -inline void -negamax_display_progress(const uint8_t depth, const uint32_t length) { - if (depth == negamax_search_depth) { - lcd_printf_line(L_OVERWRITE, "Computing: %d%%", - (++perc*100)/length); +inline void negamax_display_progress(const uint8_t cur_depth, + const uint8_t init_depth, + const uint32_t length) { + (void)init_depth; + if (cur_depth == negamax_search_depth) { + lcd_printf_line(L_OVERWRITE, "Computing: %d%%", (++perc * 100) / length); } } -static int -negamax_turn() { +static int negamax_turn() { // Prepare progress bar perc = 0; lcd_put_line(L_SCROLL, "Computing: 0%"); // Run the minimax - float minimax = negamax_generate(); + float minimax = negamax_generate(state); // Failed to find a move? if (minimax < -infty) { lcd_printf_line(L_SCROLL, "%s concedes!", - (ply & 1) ? "Black" : "White"); + (state->ply & 1) ? "Black" : "White"); return EXIT_FAILURE; } else { - lcd_printf_line(L_SCROLL, "%s: %s", - (ply & 1) ? "Black" : "White", - negamax_ptn); + lcd_printf_line(L_SCROLL, "%s: %s", (state->ply & 1) ? "Black" : "White", + negamax_ptn); return handle_turn(negamax_ptn); } } -static void -do_game_log(void) { - lcd_put_line(L_SCROLL, "TODO!"); -} +static void do_game_log(void) { lcd_put_line(L_SCROLL, "TODO!"); } -static int -input_is_not_turn(const char *line) { +static int input_is_not_turn(const char *line) { switch (line[0]) { - case 'l': { do_game_log(); break; } - case 'n': { new_game(5); break; } - case 'D': { - negamax_search_depth = line[1] - '0'; - lcd_printf_line(L_SCROLL, "Search depth: %d", - negamax_search_depth); - break; - } - case 'B': { human = 1; new_game(5); break; } - case 'W': { human = 0; new_game(5); break; } - default: return EXIT_FAILURE; + case 'l': { + do_game_log(); + break; + } + case 'n': { + new_game(5); + break; + } + case 'D': { + negamax_search_depth = line[1] - '0'; + lcd_printf_line(L_SCROLL, "Search depth: %d", negamax_search_depth); + break; + } + case 'B': { + human = 1; + new_game(5); + break; + } + case 'W': { + human = 0; + new_game(5); + break; + } + default: + return EXIT_FAILURE; } return EXIT_SUCCESS; } -const char* license = "ct1986, an interface to the ct library designed to be embedded on a Raspberry Pi Zero\n\ +const char *license = + "ct1986, an interface to the ct library designed to be embedded on a Raspberry Pi Zero\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"; #define LINE_BUFF_LEN 9 -static char line[LINE_BUFF_LEN+1]; +static char line[LINE_BUFF_LEN + 1]; -static int -poll_input(void) { +static int poll_input(void) { char c, *prompt; int idx = 0, polling = 1; - if (ply & 1) prompt = "Black: "; - else prompt = "White: "; + if (state->ply & 1) + prompt = "Black: "; + else + prompt = "White: "; lcd_put_line(L_SCROLL, prompt); @@ -200,24 +223,25 @@ poll_input(void) { lcd_printf_line(L_OVERWRITE, "%s%s", prompt, line); c = getchar(); switch (c) { - case 0x7F: { - if (idx>0) idx--; - line[idx] = 0; - break; - } - case 0xFF: // fall-through - case '\r': // fall-through - case '\n': { - polling = 0; - break; - } - default: { - if (idx+1<LINE_BUFF_LEN) { - line[idx] = c; - line[++idx] = 0; - } - break; + case 0x7F: { + if (idx > 0) + idx--; + line[idx] = 0; + break; + } + case 0xFF: // fall-through + case '\r': // fall-through + case '\n': { + polling = 0; + break; + } + default: { + if (idx + 1 < LINE_BUFF_LEN) { + line[idx] = c; + line[++idx] = 0; } + break; + } } } return idx; @@ -243,15 +267,15 @@ int main(int argc, char **argv) { while (human == 0) { lcd_set_blink(); if (poll_input() > 0) { - if (input_is_not_turn(line)) { - int r = handle_turn(line); - if (r == EXIT_SUCCESS && won == 0xFF) { - human = 1; - } - } + if (input_is_not_turn(line)) { + int r = handle_turn(line); + if (r == EXIT_SUCCESS && state->won == 0xFF) { + human = 1; + } + } } else { - playing = 0; - human = 1; + playing = 0; + human = 1; } } lcd_stop_blink(); @@ -17,6 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#include "actions.h" #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -47,13 +48,13 @@ static void put_stone(const enum STONE_VARIANT stone, const enum COLOUR colour, } if (top) { switch (stone) { - case STONE_FLAT: + case STONE_FLAT: putchar(CHAR_FLT); break; - case STONE_STANDING: + case STONE_STANDING: putchar(CHAR_STN); break; - case STONE_CAPSTONE: + case STONE_CAPSTONE: putchar(CHAR_CAP); break; } @@ -63,11 +64,11 @@ static void put_stone(const enum STONE_VARIANT stone, const enum COLOUR colour, fputs(rst, stdout); } -static void print_cell_line(const uint8_t line, const uint8_t col, - const uint8_t row) { +static void print_cell_line(tak_state_p state, const uint8_t line, + const uint8_t col, const uint8_t row) { - const uint8_t location = THE_COORDS(col, row), - stack_size = COUNT_AT(location); + const uint8_t location = THE_COORDS(state->board_size, col, row), + stack_size = COUNT_AT(state, location); uint8_t idx; for (uint8_t k = 0; k < SQUARE_W; k++) { @@ -85,9 +86,9 @@ static void print_cell_line(const uint8_t line, const uint8_t col, } } if (idx < stack_size) { - put_stone(STONE_AT(location), - (colours[location] & (1 << idx)) ? C_BLACK : C_WHITE, idx == 0, - idx >= board_size); + put_stone(STONE_AT(state, location), + (state->colours[location] & (1 << idx)) ? C_BLACK : C_WHITE, + idx == 0, idx >= state->board_size); } else { putchar(' '); } @@ -96,9 +97,9 @@ static void print_cell_line(const uint8_t line, const uint8_t col, // It takes board_size*(SQUARE_H+1)+1 lines to print the board, they // may be requested in any order and at any time -static void print_board_line(const uint8_t line) { +static void print_board_line(tak_state_p state, const uint8_t line) { const uint8_t mod = line % (SQUARE_H + 1), - row = board_size - line / (SQUARE_H + 1) - 1; + row = state->board_size - line / (SQUARE_H + 1) - 1; // Print leader, either row number if half-way through square or // padding spaces otherwise @@ -109,7 +110,7 @@ static void print_board_line(const uint8_t line) { // Top and bottom of squares receive borders if (mod == 0) { - for (uint8_t x = 0; x < board_size; x++) { + for (uint8_t x = 0; x < state->board_size; x++) { putchar('+'); for (uint8_t k = 0; k < SQUARE_W; k++) putchar('-'); @@ -117,15 +118,15 @@ static void print_board_line(const uint8_t line) { puts("+"); } else { // Interior of board should be filled by borders and pieces - if (line < board_size * (SQUARE_H + 1)) { - for (uint8_t x = 0; x < board_size; x++) { + if (line < state->board_size * (SQUARE_H + 1)) { + for (uint8_t x = 0; x < state->board_size; x++) { putchar('|'); - print_cell_line(mod - 1, x, row); + print_cell_line(state, mod - 1, x, row); } puts("|"); } else { // Bottom of board has column markers - for (uint8_t x = 0; x < board_size; x++) { + for (uint8_t x = 0; x < state->board_size; x++) { for (uint8_t k = 0; k <= SQUARE_W / 2; k++) putchar(' '); printf("%c.", x + 'a'); @@ -138,47 +139,54 @@ static void print_board_line(const uint8_t line) { } // Simple wrapper to print the whole board in one go -static void print_board(void) { - for (uint8_t k = 0; k < board_size * (SQUARE_H + 1) + 2; k++) { - print_board_line(k); +static void print_board(tak_state_p state) { + for (uint8_t k = 0; k < state->board_size * (SQUARE_H + 1) + 2; k++) { + print_board_line(state, k); } } // Print the contents of a single square -static void print_square(const uint8_t col, const uint8_t row) { - if (row < board_size && col < board_size) { +static void print_square(tak_state_p state, const uint8_t col, + const uint8_t row) { + if (row < state->board_size && col < state->board_size) { printf("%c%c: ", 'a' + col, '1' + row); - const uint8_t stack_size = COUNT_AT(THE_COORDS(col, row)); + const uint8_t stack_size = + COUNT_AT(state, THE_COORDS(state->board_size, col, row)); if (stack_size > 0) { uint8_t mask = 1 << (stack_size - 1); for (uint8_t k = 0; k < stack_size; k++, mask >>= 1) { - put_stone(STONE_AT(THE_COORDS(col, row)), - (colours[THE_COORDS(col, row)] & mask) ? C_BLACK : C_WHITE, - k + 1 == stack_size, stack_size - k - 1 >= board_size); + put_stone( + STONE_AT(state, THE_COORDS(state->board_size, col, row)), + (state->colours[THE_COORDS(state->board_size, col, row)] & mask) + ? C_BLACK + : C_WHITE, + k + 1 == stack_size, stack_size - k - 1 >= state->board_size); } puts(" <-- top"); } else { puts("(empty)"); } } else { - printf("Requested square not on board (%dx%d).\n", board_size, board_size); + printf("Requested square not on board (%dx%d).\n", state->board_size, + state->board_size); } } -static void print_info(void) { - printf("Turn: %2d, %s%s%s%s\n", ply / 2 + 1, (ply & 1) ? blk : wht, - (ply & 1) ? "Black" : "White", rst, - (ply < 2) ? " (counter-play start)" : ""); +static void print_info(tak_state_p state) { + printf("Turn: %2d, %s%s%s%s\n", state->ply / 2 + 1, + (state->ply & 1) ? blk : wht, (state->ply & 1) ? "Black" : "White", + rst, (state->ply < 2) ? " (counter-play start)" : ""); printf("Flats/Caps remaining: %s%02d/%d%s, %s%02d/%d%s\n", wht, - white_count & 127, white_count >> 7, rst, blk, black_count & 127, - black_count >> 7, rst); + state->white_count & 127, state->white_count >> 7, rst, blk, + state->black_count & 127, state->black_count >> 7, rst); } static int human; static char *gamelog = NULL; static uint8_t auto_board = 0xFF, auto_info = 0xFF; -static int append_to_gamelog(const char *line, const uint8_t win_line) { +static int append_to_gamelog(tak_state_p state, const char *line, + const uint8_t win_line) { // I _could_ dynamically compute the size but ... don't let // `perfect' be the enemy of `good' ? @@ -190,14 +198,15 @@ static int append_to_gamelog(const char *line, const uint8_t win_line) { if (win_line) { prepend[0] = '\n'; prepend[1] = 0; - } else if (ply & 1) { - snprintf(prepend, 7, "%s%d. ", (ply == 1) ? "" : "\n", ply / 2 + 1); + } else if (state->ply & 1) { + snprintf(prepend, 7, "%s%d. ", (state->ply == 1) ? "" : "\n", + state->ply / 2 + 1); } else { strcpy(prepend, " "); } // Make room for this line gamelog = - realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); + realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); // TODO: trap errno strcat(gamelog, prepend); strcat(gamelog, line); @@ -205,79 +214,79 @@ static int append_to_gamelog(const char *line, const uint8_t win_line) { return EXIT_SUCCESS; } -static void end_game(char *line, char *win) { - append_to_gamelog(line, 0); - append_to_gamelog(win, 1); - print_board(); +static void end_game(tak_state_p state, char *line, char *win) { + append_to_gamelog(state, line, 0); + append_to_gamelog(state, win, 1); + print_board(state); puts("Game over:"); puts(gamelog); putchar('\n'); } -static int handle_turn(char *line) { +static int handle_turn(tak_state_p state, char *line) { // Track win state - uint8_t new_win = (won == 0xFF); - switch (do_ptn(line)) { - // Errors - case ACT_INVALID_PTN: { - puts("Invalid PTN."); - return EXIT_FAILURE; - } - case ACT_ILLEGAL: { - puts("Illegal action."); - return EXIT_FAILURE; - } - case ACT_OVERFLOW: { - puts("Move would cause internal overflow, select another."); - return EXIT_FAILURE; - } - // Game has ended - case GAME_END: { - // Did it end this turn? - if (new_win) { - switch (won) { + uint8_t new_win = (state->won == 0xFF); + switch (do_ptn(state, line)) { + // Errors + case ACT_INVALID_PTN: { + puts("Invalid PTN."); + return EXIT_FAILURE; + } + case ACT_ILLEGAL: { + puts("Illegal action."); + return EXIT_FAILURE; + } + case ACT_OVERFLOW: { + puts("Move would cause internal overflow, select another."); + return EXIT_FAILURE; + } + // Game has ended + case GAME_END: { + // Did it end this turn? + if (new_win) { + switch (state->won) { case WIN_DRAW: { - end_game(line, "1/2-1/2"); + end_game(state, line, "1/2-1/2"); break; } case WIN_FLAT_BLACK: { - end_game(line, "0-F"); + end_game(state, line, "0-F"); break; } case WIN_FLAT_WHITE: { - end_game(line, "F-0"); + end_game(state, line, "F-0"); break; } case WIN_ROAD_BLACK: { - end_game(line, "0-R"); + end_game(state, line, "0-R"); break; } case WIN_ROAD_WHITE: { - end_game(line, "R-0"); + end_game(state, line, "R-0"); break; } - } } - puts("Enter `new' to play again."); - if (!new_win) - return EXIT_FAILURE; - break; - } - // Valid, append to game log - case ACT_OK: { - append_to_gamelog(line, 0); - if (auto_board) - print_board(); - if (auto_info) - print_info(); - break; } + puts("Enter `new' to play again."); + if (!new_win) + return EXIT_FAILURE; + break; + } + // Valid, append to game log + case ACT_OK: { + append_to_gamelog(state, line, 0); + if (auto_board) + print_board(state); + if (auto_info) + print_info(state); + break; + } } return EXIT_SUCCESS; } -static void new_game(uint8_t size) { - reset_state(size); +static void new_game(tak_state_p state, uint8_t size) { + reset_state(state, size); printf("New %dx%d game! negamax at search depth %d.\n", size, size, negamax_search_depth); if (gamelog) @@ -287,7 +296,7 @@ static void new_game(uint8_t size) { gamelog[0] = 0; } -static int load_ptn(const char *fn) { +static int load_ptn(tak_state_p state, const char *fn) { FILE *fh = NULL; fh = fopen(fn, "r"); @@ -316,14 +325,14 @@ static int load_ptn(const char *fn) { space2++; line[space2] = 0; // Try the first piece we found - r = handle_turn(line + space1); + r = handle_turn(state, line + space1); if (r) { printf("Error on: %s\n", line + space1); break; } // If there's a second piece, try it if (space2 + 1 < read) { - r = handle_turn(line + space2 + 1); + r = handle_turn(state, line + space2 + 1); if (r) { printf("Error on: %s", line + space2 + 1); break; @@ -362,37 +371,37 @@ inline void negamax_display_progress(const uint8_t cur_depth, } } -static int negamax_turn(void) { - if (won == 0xFF) { +static int negamax_turn(tak_state_p state) { + if (state->won == 0xFF) { // Run the minimax num_check = 0; progress = 0; old_depth = 0; - float minimax = negamax_generate(); + float minimax = negamax_generate(state); putchar('\n'); // Failed to find a non-losing move? if (minimax <= -infty) puts("Opponent concedes!"); printf("Result: %s (%.2f, checked %.1e)\n", negamax_ptn, minimax * 100.0, num_check); - return handle_turn(negamax_ptn); + return handle_turn(state, negamax_ptn); } else { return EXIT_FAILURE; } } -static int input_is_not_turn(const char *line) { +static int input_is_not_turn(tak_state_p state, const char *line) { if (!strcmp(line, "help")) { puts("Valid commands: auto (board|info), board, depth [0-9], eval, \ help, info, load <file.ptn>, log, new, play (b|w), self-play, square\ <col><row>, tps, <PTN>."); } else if (!strcmp(line, "board")) { - print_board(); + print_board(state); } else if (!strcmp(line, "info")) { - print_info(); + print_info(state); } else if (!strcmp(line, "eval")) { - float eval = nn1986_evaluate_black_win() * 100; - if (ply & 1) { + float eval = nn1986_evaluate_black_win(state) * 100; + if (state->ply & 1) { printf("Black heuristic chance: %s%.2f%s\n", blk, eval, rst); } else { printf("White heruistic chance: %s%.2f%s\n", wht, -eval, rst); @@ -400,13 +409,13 @@ help, info, load <file.ptn>, log, new, play (b|w), self-play, square\ } else if (!strcmp(line, "log")) { puts(gamelog); } else if (!strcmp(line, "new")) { - new_game(5); + new_game(state, 5); } else if (!strcmp(line, "tps")) { char buf[1000]; - generate_tps(buf); + generate_tps(state, buf); puts(buf); } else if (!strcmp(line, "self-play")) { - while (negamax_turn() == 0) + while (negamax_turn(state) == 0) ; } else if (!strncmp(line, "depth", 5)) { if (strnlen(line, 7) == 7 && line[6] >= '0' && line[6] <= '9') { @@ -417,7 +426,7 @@ help, info, load <file.ptn>, log, new, play (b|w), self-play, square\ } } else if (!strncmp(line, "load", 4)) { if (strnlen(line, 6) >= 6) { - if (load_ptn(line + 5)) { + if (load_ptn(state, line + 5)) { printf("Errors in file %s\n", line); } } else { @@ -437,19 +446,19 @@ help, info, load <file.ptn>, log, new, play (b|w), self-play, square\ } } else if (!strncmp(line, "square", 6)) { if (strnlen(line, 10) == 9 && line[7] >= 'a' && - line[7] <= '`' + board_size && line[8] >= '1' && - line[8] <= '0' + board_size) { - print_square(line[7] - 'a', line[8] - '1'); + line[7] <= '`' + state->board_size && line[8] >= '1' && + line[8] <= '0' + state->board_size) { + print_square(state, line[7] - 'a', line[8] - '1'); } else { - printf("Usage: square [a-%c][1-%c].\n", '`' + board_size, - '0' + board_size); + printf("Usage: square [a-%c][1-%c].\n", '`' + state->board_size, + '0' + state->board_size); } } else if (!strncmp(line, "play", 4)) { if (strnlen(line, 7) == 6 && ((line[5] == 'b' || line[5] == 'B') || (line[5] == 'w' || line[5] == 'W'))) { // 'b' is even :) human = 1 - (line[5] & 1); - new_game(5); + new_game(state, 5); } else { puts("Usage: play (b|w)."); } @@ -471,19 +480,12 @@ int main(int argc, char **argv) { puts(license); + tak_state_p state = new_tak_state(5); + negamax_search_depth = 5; - new_game(5); + new_game(state, 5); negamax_init(5); - // Test harness - if (argc > 1) { - negamax_search_depth = 7; - load_ptn("data/0.ptn"); - negamax_turn(); - return 0; - } - // Test harness - char *line = NULL; ssize_t read = -1; size_t alloc_size; @@ -496,9 +498,9 @@ int main(int argc, char **argv) { read = getline(&line, &alloc_size, stdin); if (read > 0) { line[read - 1] = 0; - if (input_is_not_turn(line)) { - int r = handle_turn(line); - if (r == EXIT_SUCCESS && won == 0xFF) { + if (input_is_not_turn(state, line)) { + int r = handle_turn(state, line); + if (r == EXIT_SUCCESS && state->won == 0xFF) { human = 1; } } @@ -510,7 +512,7 @@ int main(int argc, char **argv) { } } if (playing) { - negamax_turn(); + negamax_turn(state); human = 0; } } diff --git a/src/cttei.c b/src/cttei.c index 534faef..f7fafa6 100644 --- a/src/cttei.c +++ b/src/cttei.c @@ -17,19 +17,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <negamax.h> #include <tak.h> #include <tps.h> -#include <negamax.h> // Set up output function for negamax -inline void -negamax_display_progress(const uint8_t cur_depth, - const uint8_t init_depth, - const uint32_t length) { +inline void negamax_display_progress(const uint8_t cur_depth, + const uint8_t init_depth, + const uint32_t length) { (void)(cur_depth); (void)(init_depth); (void)(length); @@ -38,68 +37,71 @@ negamax_display_progress(const uint8_t cur_depth, enum TEI_RETURN { TEI_QUIT, TEI_OK, TEI_FAILURE }; // expects ``(startpos|tps <tps>) moves <ptn>'' -static enum TEI_RETURN -parse_position_string(char *line) { +static enum TEI_RETURN parse_position_string(tak_state_p state, char *line) { // Find the word ``moves'' char *beg = strstr(line, "moves"); if (!strncasecmp(line, "tps", 3)) { // Split the string on the space before moves - if (beg) *(beg-1) = 0; + if (beg) + *(beg - 1) = 0; // so that we can load it as a TPS description - load_tps(line + 4); + load_tps(state, line + 4); } else if (!strncasecmp(line, "startpos", 8)) { - reset_state(board_size); + reset_state(state, 5); } else { return TEI_FAILURE; } - if (beg == NULL) return TEI_OK; + if (beg == NULL) + return TEI_OK; // parse the PTN sequence strtok(beg, " "); char *ptn = strtok(NULL, " "); while (ptn != NULL) { - if (do_ptn(ptn) != ACT_OK) return TEI_FAILURE; + if (do_ptn(state, ptn) != ACT_OK) + return TEI_FAILURE; ptn = strtok(NULL, " "); } return TEI_OK; } -static enum TEI_RETURN -handle_tei(char *line) { +static enum TEI_RETURN handle_tei(tak_state_p state, char *line) { if (!strcmp(line, "quit")) { return TEI_QUIT; - } if (!strcmp(line, "isready")) { + } + if (!strcmp(line, "isready")) { puts("readyok"); } else if (!strncmp(line, "setoption Depth value ", 22)) { negamax_search_depth = atoi(line + 23); } else if (!strncmp(line, "go", 2)) { // TODO: for now we ignore all of the parameters - float minimax = negamax_generate(); - enum ACT_RESULT r = do_ptn(negamax_ptn); - if (r != ACT_OK && r != GAME_END) return TEI_FAILURE; - printf("info score cp %f pv %s\nbestmove %s\n", - minimax, negamax_ptn, negamax_ptn); + float minimax = negamax_generate(state); + enum ACT_RESULT r = do_ptn(state, negamax_ptn); + if (r != ACT_OK && r != GAME_END) + return TEI_FAILURE; + printf("info score cp %f pv %s\nbestmove %s\n", minimax, negamax_ptn, + negamax_ptn); } else if (!strncmp(line, "position", 8)) { - return parse_position_string(line + 9); + return parse_position_string(state, line + 9); } else if (!strncmp(line, "teinewgame", 10)) { - if (line[11] != '5') return TEI_FAILURE; + if (line[11] != '5') + return TEI_FAILURE; const uint8_t size = atoi(line + 11); - if (size != board_size) { - negamax_free(); - reset_state(size); - negamax_init(size); + if (size != 5) { + return TEI_FAILURE; } else { - reset_state(size); + reset_state(state, 5); } } fflush(stdout); return TEI_OK; } -const char* license = "cttei, a TEI interface to the ct library & its computer opponent\n\ +const char *license = + "cttei, a TEI interface to the ct library & its computer opponent\n\ \n\ Copyright (C) 2021, tslil clingman\n\ \n\ @@ -119,44 +121,50 @@ int main(int argc, char **argv) { while ((read = getline(&line, &alloc_size, stdin))) { if (read > 0 && !strncmp("tei", line, 3)) { break; - } else return EXIT_FAILURE; + } else + return EXIT_FAILURE; } - if (line) free(line); + if (line) + free(line); line = NULL; // Identify ourselves, and send the options - puts("id name cttei_dense"); + puts("id name cttei"); puts("id author tslil clingman"); puts("option name Depth type spin default 4 min 2 max 6"); puts("teiok"); fflush(stdout); // Set default option + tak_state_p state = new_tak_state(5); negamax_search_depth = 4; negamax_init(5); - reset_state(5); + reset_state(state, 5); for (int playing = 1; playing;) { if ((read = getline(&line, &alloc_size, stdin)) > 0) { - line[read-1] = 0; - switch (handle_tei(line)) { - case TEI_FAILURE: return EXIT_FAILURE; - case TEI_QUIT: playing = 0; // fall-through - case TEI_OK: { - if (line) { - free(line); - line = NULL; + line[read - 1] = 0; + switch (handle_tei(state, line)) { + case TEI_FAILURE: + return EXIT_FAILURE; + case TEI_QUIT: + playing = 0; // fall-through + case TEI_OK: { + if (line) { + free(line); + line = NULL; + } + break; } - break; - } } } else { break; } } - if (line) free(line); + if (line) + free(line); negamax_free(); return EXIT_SUCCESS; diff --git a/src/geminict.c b/src/geminict.c index 387c219..6f2d04b 100644 --- a/src/geminict.c +++ b/src/geminict.c @@ -39,6 +39,8 @@ #define STR_CHF_BLK "b" #define STR_CHF_WHT "w" +static tak_state_p state; + static void put_stone(const enum STONE_VARIANT stone, const enum COLOUR colour, const uint8_t top, const uint8_t beyond_carry_limit) { if (beyond_carry_limit) { @@ -46,18 +48,18 @@ static void put_stone(const enum STONE_VARIANT stone, const enum COLOUR colour, } else { if (top) { switch (stone) { - case STONE_FLAT: { - fputs((colour == C_BLACK) ? STR_FLT_BLK : STR_FLT_WHT, stdout); - break; - } - case STONE_STANDING: { - fputs((colour == C_BLACK) ? STR_STN_BLK : STR_STN_WHT, stdout); - break; - } - case STONE_CAPSTONE: { - fputs((colour == C_BLACK) ? STR_CAP_BLK : STR_CAP_WHT, stdout); - break; - } + case STONE_FLAT: { + fputs((colour == C_BLACK) ? STR_FLT_BLK : STR_FLT_WHT, stdout); + break; + } + case STONE_STANDING: { + fputs((colour == C_BLACK) ? STR_STN_BLK : STR_STN_WHT, stdout); + break; + } + case STONE_CAPSTONE: { + fputs((colour == C_BLACK) ? STR_CAP_BLK : STR_CAP_WHT, stdout); + break; + } } } else { fputs((colour == C_BLACK) ? STR_HFL_BLK : STR_HFL_WHT, stdout); @@ -68,8 +70,8 @@ static void put_stone(const enum STONE_VARIANT stone, const enum COLOUR colour, static void print_cell_line(const uint8_t line, const uint8_t col, const uint8_t row) { - const uint8_t location = THE_COORDS(col, row), - stack_size = COUNT_AT(location); + const uint8_t location = THE_COORDS(5, col, row), + stack_size = COUNT_AT(state, location); uint8_t idx; for (uint8_t k = 0; k < SQUARE_W; k++) { @@ -87,20 +89,20 @@ static void print_cell_line(const uint8_t line, const uint8_t col, } } if (idx < stack_size) { - put_stone(STONE_AT(location), - (colours[location] & (1 << idx)) ? C_BLACK : C_WHITE, idx == 0, - idx >= board_size); + put_stone(STONE_AT(state, location), + (state->colours[location] & (1 << idx)) ? C_BLACK : C_WHITE, + idx == 0, idx >= 5); } else { putchar(' '); } } } -// It takes board_size*(SQUARE_H+1)+1 lines to print the board, they +// It takes 5*(SQUARE_H+1)+1 lines to print the board, they // may be requested in any order and at any time static void print_board_line(const uint8_t line) { const uint8_t mod = line % (SQUARE_H + 1), - row = board_size - line / (SQUARE_H + 1) - 1; + row = 5 - line / (SQUARE_H + 1) - 1; // Print leader, either row number if half-way through square or // padding spaces otherwise @@ -111,7 +113,7 @@ static void print_board_line(const uint8_t line) { // Top and bottom of squares receive borders if (mod == 0) { - for (uint8_t x = 0; x < board_size; x++) { + for (uint8_t x = 0; x < 5; x++) { putchar('+'); for (uint8_t k = 0; k < SQUARE_W; k++) putchar('-'); @@ -119,15 +121,15 @@ static void print_board_line(const uint8_t line) { puts("+"); } else { // Interior of board should be filled by borders and pieces - if (line < board_size * (SQUARE_H + 1)) { - for (uint8_t x = 0; x < board_size; x++) { + if (line < 5 * (SQUARE_H + 1)) { + for (uint8_t x = 0; x < 5; x++) { putchar('|'); print_cell_line(mod - 1, x, row); } puts("|"); } else { // Bottom of board has column markers - for (uint8_t x = 0; x < board_size; x++) { + for (uint8_t x = 0; x < 5; x++) { for (uint8_t k = 0; k <= SQUARE_W / 2; k++) putchar(' '); printf("%c.", x + 'a'); @@ -141,19 +143,19 @@ static void print_board_line(const uint8_t line) { // Simple wrapper to print the whole board in one go static void print_board(void) { - for (uint8_t k = 0; k < board_size * (SQUARE_H + 1) + 2; k++) { + for (uint8_t k = 0; k < 5 * (SQUARE_H + 1) + 2; k++) { print_board_line(k); } putchar('\n'); } static void print_info(void) { - printf("Turn: %2d, %s%s\n", ply / 2 + 1, - (ply & 1) ? "Black" : "White", - (ply < 2) ? " (counter-play start)" : ""); - printf("Flats/Caps remaining: %02d/%d, %02d/%d\n", - white_count & 127, white_count >> 7, black_count & 127, - black_count >> 7); + printf("Turn: %2d, %s%s\n", state->ply / 2 + 1, + (state->ply & 1) ? "Black" : "White", + (state->ply < 2) ? " (counter-play start)" : ""); + printf("Flats/Caps remaining: %02d/%d, %02d/%d\n", state->white_count & 127, + state->white_count >> 7, state->black_count & 127, + state->black_count >> 7); } static char *gamelog = NULL; @@ -176,14 +178,15 @@ static int append_to_gamelog(const char *line, const uint8_t win_line) { if (win_line) { prepend[0] = '\n'; prepend[1] = 0; - } else if (ply & 1) { - snprintf(prepend, 7, "%s%d. ", (ply == 1) ? "" : "\n", ply / 2 + 1); + } else if (state->ply & 1) { + snprintf(prepend, 7, "%s%d. ", (state->ply == 1) ? "" : "\n", + state->ply / 2 + 1); } else { strcpy(prepend, " "); } // Make room for this line gamelog = - realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); + realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); // TODO: trap errno strcat(gamelog, prepend); strcat(gamelog, line); @@ -203,64 +206,64 @@ static void end_game(char *line, char *win) { enum TURN_RESULT { T_ERR, T_OK, T_WIN }; static enum TURN_RESULT handle_turn(char *line) { // Track win state - uint8_t new_win = (won == 0xFF); - switch (do_ptn(line)) { - // Errors - case ACT_INVALID_PTN: { - puts("Invalid PTN."); - return T_ERR; - } - case ACT_ILLEGAL: { - puts("Illegal action."); - return T_ERR; - } - case ACT_OVERFLOW: { - puts("Move would cause internal overflow, select another."); - return T_ERR; - } - // Game has ended - case GAME_END: { - // Did it end this turn? - if (new_win) { - switch (won) { - case WIN_DRAW: { - end_game(line, "1/2-1/2"); - break; - } - case WIN_FLAT_BLACK: { - end_game(line, "0-F"); - break; - } - case WIN_FLAT_WHITE: { - end_game(line, "F-0"); - break; - } - case WIN_ROAD_BLACK: { - end_game(line, "0-R"); - break; - } - case WIN_ROAD_WHITE: { - end_game(line, "R-0"); - break; - } - } - return T_WIN; + uint8_t new_win = (state->won == 0xFF); + switch (do_ptn(state, line)) { + // Errors + case ACT_INVALID_PTN: { + puts("Invalid PTN."); + return T_ERR; + } + case ACT_ILLEGAL: { + puts("Illegal action."); + return T_ERR; + } + case ACT_OVERFLOW: { + puts("Move would cause internal overflow, select another."); + return T_ERR; + } + // Game has ended + case GAME_END: { + // Did it end this turn? + if (new_win) { + switch (state->won) { + case WIN_DRAW: { + end_game(line, "1/2-1/2"); + break; } - if (!new_win) - return T_ERR; - break; - } - // Valid, append to game log - case ACT_OK: { - append_to_gamelog(line, 0); - break; + case WIN_FLAT_BLACK: { + end_game(line, "0-F"); + break; + } + case WIN_FLAT_WHITE: { + end_game(line, "F-0"); + break; + } + case WIN_ROAD_BLACK: { + end_game(line, "0-R"); + break; + } + case WIN_ROAD_WHITE: { + end_game(line, "R-0"); + break; + } + } + return T_WIN; } + if (!new_win) + return T_ERR; + break; + } + // Valid, append to game log + case ACT_OK: { + append_to_gamelog(line, 0); + break; + } } return T_OK; } static void new_game(uint8_t size) { - reset_state(size); + reset_state(state, size); if (gamelog) gamelog = realloc(gamelog, sizeof(char)); else @@ -281,16 +284,16 @@ inline void negamax_display_progress(const uint8_t cur_depth, } static enum TURN_RESULT negamax_turn(void) { - if (won == 0xFF) { + if (state->won == 0xFF) { // Run the minimax num_check = 0; - float minimax = negamax_generate(); + float minimax = negamax_generate(state); putchar('\n'); // Failed to find a non-losing move? if (minimax <= -infty) puts("Opponent concedes!"); - printf("ct1986 says: %s (minmax %.2f, checked %.1e)\n\n", negamax_ptn, minimax * 100.0, - num_check); + printf("ct1986 says: %s (minmax %.2f, checked %.1e)\n\n", negamax_ptn, + minimax * 100.0, num_check); return handle_turn(negamax_ptn); } else { return T_ERR; @@ -303,13 +306,14 @@ int main(int argc, char **argv) { return EXIT_FAILURE; }; + state = new_tak_state(5); negamax_search_depth = 5; new_game(5); negamax_init(5); enum TURN_RESULT tr; - char* line = argv[1]; + char *line = argv[1]; // Some maximum length we're willing to parse uint32_t len = strnlen(line, 65535); if (!line || len < 2 || len == 65535) { @@ -318,7 +322,7 @@ int main(int argc, char **argv) { } // strip quotes - if (line[0]=='\'') { + if (line[0] == '\'') { line++; len--; } else { @@ -326,8 +330,8 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - if (line[len-1]=='\'') { - line[len-1]=0; + if (line[len - 1] == '\'') { + line[len - 1] = 0; len--; } else { puts("Malformed input."); @@ -337,7 +341,8 @@ int main(int argc, char **argv) { uint32_t start = 0, end = 0; while (start < len) { // Find first separator - while (end < len && line[end] != '.') end++; + while (end < len && line[end] != '.') + end++; // If still on line if (end < len) { // Mark the split @@ -345,10 +350,11 @@ int main(int argc, char **argv) { // Try the first piece we found tr = handle_turn(line + start); if (tr == T_ERR) { - printf("Error on: %s\n", line + start); - print_everything(); - return EXIT_FAILURE; - } else if (tr == T_WIN) return EXIT_SUCCESS; + printf("Error on: %s\n", line + start); + print_everything(); + return EXIT_FAILURE; + } else if (tr == T_WIN) + return EXIT_SUCCESS; start = ++end; } else { puts("Malformed input."); @@ -362,7 +368,8 @@ int main(int argc, char **argv) { puts("This shouldn't happen, ct1986 encountered an error."); print_everything(); return EXIT_FAILURE; - } else if (tr == T_WIN) return EXIT_SUCCESS; + } else if (tr == T_WIN) + return EXIT_SUCCESS; print_everything(); diff --git a/src/nn_train.py b/src/nn_train.py index 12ce868..f2550b4 100644 --- a/src/nn_train.py +++ b/src/nn_train.py @@ -56,10 +56,10 @@ def train(size, model, data, iterations=1, epochs=10, batch=None): tra_res = model.evaluate(tra_input, tra_outcome, verbose=False) results.append((tra_res, val_res)) print(val_res) - write_weights(model, i+1, (tra_res, val_res)) + write_weights(model, str(i+1).zfill(len(str(iterations))), (tra_res, val_res)) print("\nScores") for i, data in enumerate(results): - print(f"Iteration {i}: {data}") + print(f"Iteration {i+1}: {data}") return results @@ -84,12 +84,12 @@ def write_weights(model, iteration, performance): output_weights = transpose(model.trainable_variables[2], perm=[1, 0]) output_bias = model.trainable_variables[3] # Prepare output - to_output = [("dense1_weights[DENSE_NUM][INP_NUM]",dense1_weights) + to_output = [("dense1_weights[DENSE_NUM][INP_NUM]", dense1_weights), ("dense1_biases[DENSE_NUM]", dense1_biases), ("output_weights[2][DENSE_NUM]", output_weights), ("output_bias[2]", output_bias)] # Write to file - f = open("weights-"+str(iteration)+".txt", "w") + f = open("weights-"+iteration+".txt", "w") f.write("/*\n") model.summary(print_fn=lambda l: f.write(" * "+l+"\n")) f.write(" * "+str(performance)+"\n*/\n\n") @@ -103,4 +103,4 @@ data = load_data(5) model = make_model(5, 64) print("Before training", model.evaluate(data[1][0], data[1][1], verbose=False, batch_size=16)) -results = train(5, model, data, iterations=1, epochs=10, batch=None) +results = train(5, model, data, iterations=5, epochs=10, batch=128) diff --git a/src/pptdb.c b/src/pptdb.c index 42e8706..cdc0004 100644 --- a/src/pptdb.c +++ b/src/pptdb.c @@ -30,210 +30,242 @@ 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); +tak_state_p state; + +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,", state->ply & 1 ? 1 : -1, + (float)(state->white_count & 127) / max_flats, + (float)(state->black_count & 127) / max_flats); + + // Write the board layers + float val; + int col, row; + row = (dy > 0) ? -1 : state->board_size; + for (int i = 0; i < state->board_size; i++) { + row += dy; + col = (dx > 0) ? -1 : state->board_size; + for (int j = 0; j < state->board_size; j++) { + col += dx; + const uint8_t k = (swap) ? THE_COORDS(state->board_size, row, col) + : THE_COORDS(state->board_size, col, row); + val = 0; + if (COUNT_AT(state, k) > 0) { + // Top layer of stacks is handled differently to indicate + // stone type + if (STONE_AT(state, k) == STONE_STANDING) { + val = (state->colours[k] & 1) ? +0.25 : -0.25; + } else if (STONE_AT(state, k) == STONE_CAPSTONE) { + val = (state->colours[k] & 1) ? +1.00 : -1.00; + } else { + val = (state->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); + } + 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<read;idx++) { - if (pt[idx]==',') total_plies++; - } - for(idx=0;;) { - if (pt[idx] == 'P') { - // P [A-F][1-6] [CF]?, - idx+=2; - enum STONE_VARIANT stone; - const uint8_t col = pt[idx]-'A', row = pt[idx+1]-'1'; - - if (idx + 3 < read) { - switch (pt[idx+3]) { - case 'W': { stone = STONE_STANDING; break; } - case 'C': { stone = STONE_CAPSTONE; break; } - default: { stone = STONE_FLAT; break; } - } - } else { - stone = STONE_FLAT; - } - - r = try_place(THE_COORDS(col,row), current_colour, stone); - if (r != ACT_OK) return r; - } else if (pt[idx] == 'M') { - // M [A-F][1-6] [A-F][1-6]( [1-6])+, - idx+=2; - uint8_t drops[board_size]; - const uint8_t s_col =pt[idx]-'A', s_row=pt[idx+1]-'1', - d_col=pt[idx+3]-'A', d_row=pt[idx+4]-'1'; - idx+=4; - - enum MOVE_DIRECTION dir = M_RIGHT; - if (s_col < d_col) dir=M_RIGHT; - else if (s_col > 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+2<read && pt[idx+1] != ','); - - r = try_move(THE_COORDS(s_col, s_row), dir, steps, drops); - - if (r != ACT_OK) return r; - - if (generate == 0) { - // Measure height of stacks exceeding 1 - for (int k = 0; k < board_size * board_size; k++) { - if (COUNT_AT(k)>1) heights[COUNT_AT(k)]+=1; - } - } +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 < read; idx++) { + if (pt[idx] == ',') + total_plies++; + } + for (idx = 0;;) { + if (pt[idx] == 'P') { + // P [A-F][1-6] [CF]?, + idx += 2; + enum STONE_VARIANT stone; + const uint8_t col = pt[idx] - 'A', row = pt[idx + 1] - '1'; + + if (idx + 3 < read) { + switch (pt[idx + 3]) { + case 'W': { + stone = STONE_STANDING; + break; + } + case 'C': { + stone = STONE_CAPSTONE; + break; } - // 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); + default: { + stone = STONE_FLAT; + break; } - // Parse next action - while (idx<read && pt[idx++]!=','); - if (idx>=read) return ACT_OK; - next_ply(); + } + } else { + stone = STONE_FLAT; + } + + r = try_place(state, THE_COORDS(state->board_size, col, row), + state->current_colour, stone); + if (r != ACT_OK) + return r; + } else if (pt[idx] == 'M') { + // M [A-F][1-6] [A-F][1-6]( [1-6])+, + idx += 2; + uint8_t drops[state->board_size]; + const uint8_t s_col = pt[idx] - 'A', s_row = pt[idx + 1] - '1', + d_col = pt[idx + 3] - 'A', d_row = pt[idx + 4] - '1'; + idx += 4; + + enum MOVE_DIRECTION dir = M_RIGHT; + if (s_col < d_col) + dir = M_RIGHT; + else if (s_col > 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 + 2 < read && pt[idx + 1] != ','); + + r = try_move(state, THE_COORDS(state->board_size, s_col, s_row), dir, + steps, drops); + + if (r != ACT_OK) + return r; + + if (generate == 0) { + // Measure height of stacks exceeding 1 + for (int k = 0; k < state->board_size * state->board_size; k++) { + if (COUNT_AT(state, k) > 1) + heights[COUNT_AT(state, 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 && state->ply > 7 && state->ply < total_plies && + state->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); } - return ACT_OK; + // Parse next action + while (idx < read && pt[idx++] != ',') + ; + if (idx >= read) + return ACT_OK; + next_ply(state); + } + return ACT_OK; } -const char* license = "pptdb, generate neural network training data from a playtak.com database dump\n\ +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++; - } + (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; + + state = new_tak_state(size); + while ((read = getline(&line, &len, playtak_fh)) != -1) { + // Reset everything + reset_state(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(state); + if (win == WIN_FLAT_BLACK || win == WIN_FLAT_WHITE || win == WIN_DRAW) { + flat_wins++; + flat_turns += state->ply / 2 + 1; + } else { + road_wins++; + road_turns += state->ply / 2 + 1; } - games++; + 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); + fclose(playtak_fh); + if (generate) + fclose(training_fh); + if (line) + free(line); - if (illegal || overflow) putchar('\n'); - printf("Read %d games\n",games); + if (illegal || overflow) + putchar('\n'); + printf("Read %d games\n", games); - if (generate==0) { - printf("Illegals: %d\nOverflows: %d\n\ + 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]); - } + 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); + exit(EXIT_SUCCESS); } |
