File indexing completed on 2024-11-24 03:43:17

0001 /*******************************************************************
0002  *
0003  * Copyright 2009  Pelladi Gabor <pelladigabor@gmail.com>
0004  *
0005  * Bovo is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2, or (at your option)
0008  * any later version.
0009  *
0010  * Bovo is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU General Public License
0016  * along with Bovo; see the file COPYING.  If not, write to
0017  * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  *
0020  ********************************************************************/
0021 
0022 #ifndef BOVO_STANDING_H
0023 #define BOVO_STANDING_H
0024 
0025 #include <QList>
0026 
0027 #include "ai_interface.h"
0028 
0029 #include <list>
0030 
0031 // a mark on the table
0032 using mark_T = unsigned char;
0033 // occurrences of a certain position
0034 using count_T = unsigned char;
0035 // small index for a constant array
0036 using index_T = unsigned char;
0037 
0038 // table symbols indexed with player number
0039 const mark_T mark[] = {'o', 'x', '!', '\0'};
0040 
0041 // the game table
0042 typedef mark_T table_T[max_table_size][max_table_size];
0043 // the value of the fields for the two players for the next step
0044 typedef count_T suggest_T[2][max_table_size][max_table_size];
0045 
0046 // heuristic type
0047 using heur_T = short;
0048 
0049 // type for total number of marks on the table
0050 using stepCount_T = unsigned short;
0051 
0052 // maximal and minimal value of the heuristic function
0053 const heur_T MaxHeur = 10000;
0054 const heur_T MinHeur = -MaxHeur;
0055 // one hundredth of the maximum value
0056 const heur_T HeurPercent = MaxHeur / 100;
0057 // values above WinTreshold mean winning positions
0058 const heur_T WinTreshold = 98 * HeurPercent;
0059 // heuristic value decreases by this amount times the current depth
0060 const heur_T depth_decay = 5;
0061 // if the seed is too big, do not use the hash
0062 const heur_T normal_heur_seed = 2;
0063 
0064 // number of categories used in the heuristic function
0065 const index_T heurLevels = 6;
0066 // occurrence of patterns for the two players
0067 typedef count_T PatternCount[2][heurLevels];
0068 
0069 // a row, column or diagonal of the table
0070 using sample_T = QList<mark_T>;
0071 // interesting fields for the two players for the next step
0072 using suggestions_T = std::list<Field>;
0073 
0074 class Standing;
0075 // callback function to convert a position of the sample into coordinates, and update suggestions accordingly
0076 using posf_T = void (Standing::*)(pos_T, int, count_T, count_T);
0077 
0078 // game state class
0079 class Standing
0080 {
0081 public:
0082     // the current game table
0083     table_T table;
0084     // the size of the table
0085     pos_T table_size_x, table_size_y;
0086     // the heuristic value of the standing
0087     heur_T hval;
0088     // the random seed added to the heuristic value
0089     heur_T heur_seed;
0090     // true if a player has won
0091     bool target;
0092     // total number of marks on the table
0093     stepCount_T stepCount;
0094     // the player on turn
0095     index_T current;
0096     // the move that created this standing
0097     pos_T lastx, lasty;
0098     // following move suggestion values
0099     suggest_T suggest;
0100 
0101     // calculate constant values for refresh
0102     static void initRefresh();
0103 
0104     // new game
0105     Standing(pos_T _table_size_x, pos_T _table_size_y);
0106     // copy a game state
0107     Standing(const Standing &other) = default;
0108     Standing &operator=(const Standing &other) = default;
0109 
0110     // make a step
0111     void step(pos_T x, pos_T y);
0112     // mark a field a "wall", where neither player can step
0113     void step_server(pos_T x, pos_T y);
0114 
0115     // get the interesting fields for the two players for the next step
0116     void getSuggestions(suggestions_T &suggestions);
0117 
0118 private:
0119     // global occurrence of patterns
0120     PatternCount matchCount;
0121     // occurrence of patterns in each row
0122     PatternCount matchCountRow[max_table_size];
0123     // occurrence of patterns in each column
0124     PatternCount matchCountColumn[max_table_size];
0125     // occurrence of patterns in each diagonal, where the sum of coordinates is constant
0126     PatternCount matchCountDiagonalSum[2 * max_table_size - 1];
0127     // occurrence of patterns in each diagonal, where the difference of coordinates is constant
0128     PatternCount matchCountDiagonalDiff[2 * max_table_size - 1];
0129 
0130     // interesting field values coming from row patterns
0131     suggest_T suggestRow;
0132     // interesting field values coming from column patterns
0133     suggest_T suggestColumn;
0134     // interesting field values coming from diagonal patterns, where the sum of coordinates is constant
0135     suggest_T suggestDiagonalSum;
0136     // interesting field values coming from diagonal patterns, where the difference of coordinates is constant
0137     suggest_T suggestDiagonalDiff;
0138 
0139     // callback function to convert a position of the row sample into coordinates, and update suggestions accordingly
0140     void posfRow(pos_T pos, int y, count_T value0, count_T value1);
0141     // callback function to convert a position of the column sample into coordinates, and update suggestions accordingly
0142     void posfColumn(pos_T pos, int x, count_T value0, count_T value1);
0143     // callback function to convert a position of the sum diagonal sample into coordinates, and update suggestions accordingly
0144     void posfDiagonalSum(pos_T pos, int sum, count_T value0, count_T value1);
0145     // callback function to convert a position of the diff diagonal sample into coordinates, and update suggestions accordingly
0146     void posfDiagonalDiff(pos_T pos, int diff, count_T value0, count_T value1);
0147 
0148     // calculate heuristic value
0149     void evaluate();
0150 
0151     // count occurrences of the patterns
0152     void countMatches();
0153     // refresh matchCount and suggest variables after a step
0154     // this function consumes 90% of the thinking time
0155     void refresh(sample_T &sample, PatternCount &local, int inv, posf_T posf);
0156     // process pattern occurrences
0157     void decide();
0158 };
0159 
0160 #endif // BOVO_STANDING_H