• No results found

Heuristics in MCTS-based Computer Go Can heuristics improve the performance of MCTS-based computer go?

N/A
N/A
Protected

Academic year: 2021

Share "Heuristics in MCTS-based Computer Go Can heuristics improve the performance of MCTS-based computer go?"

Copied!
44
0
0

Loading.... (view fulltext now)

Full text

(1)

Heuristics in MCTS-based Computer Go

Can heuristics improve the performance of MCTS-based computer go?

FABIAN BERGMARK & JOHAN STENBERG

Stockholm 2014

Bachelor’s thesis DD143X

School of Computer Science and Communication

Kungliga Tekniska H¨ ogskolan

Mentor: Michael Minock

Authors contact: fbermark@kth.se, jostenbe@kth.se

(2)

Abstract

The subject of computer Go is an active field under AI and has achieved much attention in research. The current state of the art computer Go im- plementations uses a game tree search approach rather than advanced heuristics. This thesis aims to bridge these two approaches and combine Monte Carlo Tree Search with heuristics to deduce if any general results can be found. The results of the thesis indicate that the performance of a combined MCTS-heuristic approach correlates strongly with performance of the heuristic. Furthermore, MCTS can be used with any heuristic to improve its performance.

(3)

Contents

1 Introduction 3

2 Background 3

2.1 Go . . . 4

2.2 Computer Go . . . 4

2.3 Tree Search and Game Trees . . . 4

2.4 Monte Carlo . . . 5

2.5 Monte Carlo Tree Search . . . 5

3 Methods 6 3.1 Framework Technical Details . . . 6

3.2 Endgame . . . 6

3.3 Heuristic Implementations . . . 7

3.4 MCTS Implementation Details . . . 7

3.5 Evaluation . . . 8

4 Results 9 4.1 Time Dependency Graph . . . 9

4.2 Comparison Result Tables . . . 9

4.3 Correlation Graph . . . 10

5 Conclusion 11 6 Discussion 11 6.1 Comparison Limitations . . . 11

6.2 Performance against humans . . . 11

6.3 Implementation Weaknesses . . . 12

6.4 Choosing of Heuristics . . . 12

7 References 12

8 Appendix A 14

(4)

1 Introduction

Go is a board game originating in China and first invented over 2,500 years ago1. Computer Go is a field under computer AI trying to implement a com- puter program that plays Go. To date, there is still considered to be a large gap between the best human players and the best AI playing the traditional 19x19 professional board2.

The subject of computer Go has received much attention in late years. During the 1990s research focused on implementing human expert knowledge and deci- sion making combined with local search. This method have several drawbacks and today much research is focused on Monte Carlo algorithms3. These algo- rithms use randomness to prune the search space, only evaluating a limited set of plays. They are, in a sense, in the other end of the spectra using large search trees and randomness to find optimal moves4.

There exist much research about both methods, and a relevant question is thus if they can be combined in a constructive way.

Go differs from many other board game in the sense that it’s search space is seldom reduced when a player places another stone on the board1. Smart heuristics such as modeling an expert player or advanced local search simply requires, to be effective enough, a too large domain space. Instead, researchers are using Monte Carlo Tree Search4(MCTS). MCTS is described more exhaus- tive in the background section but can be shortly summarized as follows; MCTS focuses on evaluating the most promising moves, basing the expansion of the game tree on random sampling of the current search space5. Since MCTS can be regarded as the opposite of using intelligent heuristics, our thesis researches, analyses and concludes if the two different approaches can be merged into a more successful one. Researchers have already visited this topic, and popular Computer Go implementations such as GNUGo also uses, in addition to MCTS, some hand-tuned heuristics6.

This thesis aims to bridge these two approaches and combine Monte Carlo Tree Search with heuristics to see if any general results can be found.

Many advocates for the Monte Carlo Tree Search points out that one of the algorithm’s strongest traits are that it is game-independent5. This thesis hopes to further enhance the MCTS for a domain specific usage, i.e. the field of com- puter Go. If the results are promising they could be correlated to other fields of usage for the MCTS.

2 Background

These sections shortly describe the key components of our background research.

(5)

2.1 Go

Go is played by two players which each places white and black stones on a grid1. Official games are played on a 19x19 board, but smaller dimensions are often used by beginners. Played stones can’t be moved but are captured if they are surrounded and are then removed from the board. The game is ended when neither player wants to make another move. The game of Go has multiple ways of deciding which player won a game, and this thesis uses stone scoring. In stone scoring, the player which the most stones and the end of the game is declared the winner.

One aspect of Go is the concept of Ko-rules. Ko rules dictates that a play is illegal if it would have the effect, after all steps of the play have been com- pleted, of creating a position that has occurred previously in the game1. The consequence of this rule is that a player cannot recreate the board position from the player’s previous move.

2.2 Computer Go

Computer Go has been a a research subject since the 1960s3. Early research focused on translating human expert knowledge into rules, thus implementing a tactical player. This approach suffers from the additive nature of Go resulting in a large search space. Algorithms were able to perform well in one, or several local areas but were unable to do board-spanning strategies7.

Recent research focuses on search trees, using statistical approximations and randomness to reduce the search space. Implementations using these methods have had some success against human players even on 19x19 boards7.

2.3 Tree Search and Game Trees

Tree search is a broad term when used within the field of computer science.

The only tree search used in Monte Carlo Tree Search is when beginning from a specific root node and therefore only tree searches with these characteristics will be mentioned here. The two most common tree search algorithms are the breadth-first search algorithm and the depth-first search algorithm. Breath-first search visits all of the current nodes neighbors in order and then proceeds to the neighbor’s neighbors. Depth-first search visits one of the neighbors and then proceeds to that neighbors first neighbor directly8.

In the field of Artificial Intelligence a simple tree structure for combinatorial games with two players is the Game Tree, where each depth-level either rep- resents the first or the second player’s moves. An example of tree-searching a game tree can be to compute which probability the player has to win for the next move, and then pick that move. If an artificial player is playing a regular player, the root node will represent the current game state, and each of the root node’s children will represent a possible move for the artificial player. The arti- ficial player simulates all possible moves (or some subset of all possible moves) and decides which move is most likely to win the game9.

(6)

2.4 Monte Carlo

A Monte Carlo algorithm is a randomized algorithm that runs in polynomial time, but might return an invalid or non-optimal result. This differs from de- terministic algorithms that always returns the same correct answer, but might require super-polynomial time8.

2.5 Monte Carlo Tree Search

Monte Carlo Tree Search is an algorithm for making approximately optimal decisions in artificial intelligence problems, foremost planning the next move in combinatorial games. Examples of such games are Go, Chess and Connect Four.

It uses the combination of random simulations and the precision of tree search10. The MCTS algorithm iterates X times. Each time four events occur:

1. Selection - Selects, from the root node, an optimal new leaf node.

2. Expansion - Expands the leaf node with a new leaf.

3. Simulation - Simulates an outcome for the combinatorial game in question.

4. Back propagation - Returns to the root node and updates the nodes it passed through in step one with new values.

With applied to Go, the AI sets the root node to the current Go board.

Then Y new moves are chosen at random. This is called pure random MCTS

10. Then each node represents a new move, either black or white. Here is an image picturing the scenario described above:

Figure 1: Monte Carlo Search Tree

The key benefit of MCTS over a regular search tree is that this MCTS uses weighted selections and randomness. This assuring that nodes which are irrele- vant gets visited less often. This leads to an unbalanced tree. 10

Selection for each node from a parent is decided through the maximal Upper Confidence Bounds10, or UCB as denoted from here on:

(7)

U CBi= vi+ Cq

lnN ni

U CBi is the value for the current node being inspected, vi is the estimated value of the node i, C is a tuned constant, N is the current path count for all nodes summed and finally niis the current node’s path count.

There is another approach to select the best node among a parent node’s chil- dren. This is called the Upper Confidence Bound for Trees10(UCT). This is gen- erally the more favored approach compared to UCB regarding Go computing10. The formula is much similar to UCB and will not be listed here.

Since every iteration requires a traversal to a leaf and then a fully simulated game, the time complexity is, somewhat approximated, only depending on the time needed to simulate a game. The complexity could be written O(nk), where n is the number of iterations and k is the average time for each game to complete.

3 Methods

As the thesis is fundamentally comparative, we have implemented a framework for AI-performance comparisons. It’s main use is to simulate large number of games between different kind of heuristics. This allows us to quickly gather a statistical basis for the results.

3.1 Framework Technical Details

The framework is written in C++ using C++11 with GCC 4.8.2, and includes a Go implementation which allows two players to play against each other.

The Go game rules implemented in the framework is simplified. Ko - situa- tions are solved by never allowing the player to play two consecutive moves at the same board position. This was implemented since the Ko - rules are rather complex.

The board uses stone scoring which is defined by that the player who has the most stones on the board when the game has ended wins. Go has many different scoring systems but stone scoring was the easiest to implement and therefore it was used. Also the artificial players require more intelligence if another scoring system is used, i.e. area scoring or territory scoring.

3.2 Endgame

The endgame in Go is defined as when the board is mostly covered with stones.

The endgame in Go is difficult for artificial players since when stone scoring is used, the players will do irrational moves since they can still place stones at the board. To avoid strange behaviour at endgame situations each heuristic player utilizes the following endgame-heuristic:

e = emptyCells − 2

(8)

p = P layerStones o = OpponenetStones op = OpponentLastM ove d = p − o

M ove =

 P ass e < d ∨ op = P ass HeuristicM ove else

This allows the beneficial branches of the Monte Carlo Search Tree to win in most cases, but not all. The subtraction by two is because a board with two free cells are generally not beneficial for the player with the most stones and should in general never be achieved.

3.3 Heuristic Implementations

To test our thesis, the framework contains implementations of the following heuristics:

• All-Random: An all random heuristic.

• Free: A heuristic who never plays a move which gives one of it’s compo- nents a liberty degree of one.

• Spread: A heuristic who plays a move as far as it can from the opponent’s latest move.

• Close: A heuristic who plays a move as close as it can from the opponent’s latest move.

• Mirror: A heuristic who plays a move as in the opposing diagonal from the opponent’s latest move. If that position is not valid the heuristic uses a breath first search to find the closest moves to the desired move.

All heuristics implement the endgame logic listed above and if each heuristic cannot place a move they pass.

3.4 MCTS Implementation Details

The Monte Carlo Tree Search algorithm is implemented as creating a single node with a specified heuristic for the player and it’s opponent. All MCTS players uses only their own heuristic as their own and the all-random heuristic as the opponent’s heuristic. So when each branching sequence is completed and the game simulation occurs the partial game is played between the heuristic and all-random. The MCTS node is then branched X times, and the more branches created, the better the result.

(9)

Figure 2: Go Framework Design Diagram With Two MCTS Players The game class handles two components, the players and the board. The board implements all Go rules and each player move has to be verified by the board before being actually played, to assert that the move is valid. The Go board is stored in a two dimensional matrix. The matrix size is defined by a template variable. Each player is represented by an interface, this lets the player implementation either be an MCTS AI player, a regular heuristic AI player or an human player. The regular heuristic AI player plays the move suggested by the heuristic.

The design diagram shows the implementation with two MCTS players. When asked for the next move, each player creates a new T reeN ode, which represents the root of the tree. Then the tree expands X times and finally the best move is returned.

3.5 Evaluation

The framework enables us to simulate a large number of games between different kind of players. Analyzing the win-ratios gives a statistical foundation to draw results from. We choose to let each pair of opponents play 1000 games against each other and noted the win-ratios. Opponents are composed in three different

(10)

ways, heuristic against heuristic, heuristic against MCTS with heuristic and MCTS with heuristic against MCTS with heuristic. For each pair of heuristic, the ratios in the different compositions are correlated. This correlation relates the general performance of the heuristic with its performance impact on MCTS.

4 Results

4.1 Time Dependency Graph

As MCTS is an iterative algorithm which performance depends on the number of visited board states.

0 1 2 3 4 5 6

0 20 40 60 80 100

Running time (ms) in log2- base

Winrate

Win rate of pure MCTS vs. all-random

4.2 Comparison Result Tables

Win-ratios between heuristics. The column players plays white and the row players play the color black. White makes the first move. The ratios in each cell describes the the column players win rate divided by the row players win rate. They do not always add up to one since some games are tied.

Plain/Plain All-Random Free Mirror Close Spread

All-Random 0.481/0.4589 0.4664/0.475 0.0675/0.7846 0.6287/0.3285 0.2413/0.6782 Free 0.4659/0.472 0.4784/0.4579 0.0744/0.7819 0.6435/0.315 0.2398/0.6768 Mirror 0.8252/0.0163 0.8244/0.0207 0.4388/0.3045 0.8112/0.08 0.5262/0.028 Close 0.3292/0.6323 0.3246/0.6349 0.136/0.7645 0.4886/0.4734 0.1396/0.8258 Spread 0.7047/0.2189 0.6952/0.2269 0.0921/0.4961 0.8271/0.141 0.4309/0.3883

Table 1: Heuristics without Monte Carlo tree search comparison.

(11)

The results listed above shows that the heuristics applied without MCTS has the following ranking:

1. Close

2. Free and All-Random 3. Spread

4. Mirror

MCTS/Plain All-Random Free Mirror Close Spread

All-Random 0.97/0.02 0.96/0.02 0.24/0.61 1/0 0.9/0.09

Free 0.99/0.01 0.99/0.01 0.14/0.71 1/0 0.81/0.14

Mirror 0.95/0.02 0.97/0.01 0.29/0.52 0.98/0.01 0.88/0.01

Close 0.96/0.04 0.98/0.02 0.19/0.7 1/0 0.71/0.27

Spread 1/0 1/0 0.14/0.47 1/0 1/0

Table 2: MCTS with heuristics versus plain heuristics comparison.

MCTS/MCTS All-Random Free Mirror Close Spread

All-Random 0.52/0.46 0.67/0.33 0.05/0.9 0.81/0.19 0.04/0.96

Free 0.61/0.39 0.53/0.45 0.08/0.89 0.8/0.2 0.06/0.94

Mirror 0.94/0.02 0.92/0.01 0.34/0.08 0.99/0 0.82/0.03

Close 0.37/0.63 0.35/0.65 0.04/0.94 0.53/0.47 0/1

Spread 0.96/0.04 0.94/0.05 0.11/0.78 0.97/0.03 0.65/0.35 Table 3: MCTS with heuristic versus MCTS with heuristic.

The results listed above shows that the heuristics applied with MCTS has the following ranking:

1. Close

2. Free and All-Random 3. Spread

4. Mirror

4.3 Correlation Graph

In the following diagram x is the win ratio between a pair of plain heuristics and y is the win ratio for the same heuristics using MCTS.

(12)

0 0.13 0.25 0.38 0.5 0.63 0.75 0.88 1 0

0.2 0.4 0.6 0.8 1

Plain Heuristics win ratio

MCTSHeuristicswinratio

Correlation between plain heuristics and MCTS heuristics performance, r2= 0.9167 Results

1.3692x − 0.993

5 Conclusion

The time dependency graph and table 2 shows some expected result of MCTS.

Performance increases with running time and improves the performance com- pared with using the plain heuristic.

From table 1 and 3 two strong statements can be made. Firstly MCTS always improves the performance of an heuristic, as expected. Secondly the perfor- mance between a heuristics performance and its MCTS version correlates. A positive correlation between win rate in plain heuristics and MCTS would in- dicate that heuristics can improve performance. The above correlation graph indicates a strong positive correlation between the heuristics performance and the impact on MCTS and thus a positive answer of our thesis.

6 Discussion

6.1 Comparison Limitations

These comparisons are limited by the fact that they only involve heuristics. As stated, heuristics approaches has some well-known problems with Go against human players. It’s therefore unknown if the observed correlation would extend to MCTS versus human games. As the heuristics implements simple rules, humans are likely to learn and exploit them. The important observation from our result is therefore the general correlation between heuristics and MCTS: If someone implements a heuristic that plays well against human players, it can be used with MCTS and will then exhibit greatly improved performance.

6.2 Performance against humans

Ideally one would like to correlate the performance improvements over other heuristics with performance against human players. This is however maimed by our end-game simplification and more advanced game play exhibited by humans.

(13)

On small boards these effects are limited and our implementation thus performs well. Larger boards also exponentially increases the running time of the MCTS algorithm, leading to worse performance.

6.3 Implementation Weaknesses

The implementation has some weaknesses which should be taken into account when studying the results and the conclusion of the thesis. Foremost there are three issues which need to be emphasized, that the endgame logic of the Go implementation is rather simplified, that the scoring method used is stone scoring and finally that the Ko-rules are simplified. The endgame logic is very hard to implement correctly and as mentioned before it was decided to simplify this logic to be able to focus on other implementation-related details. The stone scoring method is used professionally but there are other scoring methods which are more common. These are however more advanced and it was decided to implement the simplest of scoring methods. The Ko-rules are in general very difficult to understand and even though these rules could be implemented in the board it was decided to use a simplified version of them. These three weaknesses result in a simplified Go implementation which could have an delusional effect on the results. If the thesis method is replicated, results could differ if the board was more elaborately implemented.

6.4 Choosing of Heuristics

It should be mentioned that there are most certainly many more successful heuristics which could be applied to the testing framework and that the thesis has only chosen a handful of the possible heuristics available. However, the heuristics chosen are rather simple and intuitive which strengthens the readers faith in the thesis results.

7 References

1. The Way To Go, Karl Baker, American Go Association

2. Martin M¨uller, Computer Go, Artificial Intelligence 134 (2002), University of Alberta, Edmonton

3. Robin Upton. Dynamic Stochastic Control: A New Approach to Tree Search & Game-Playing, University of Warwick, UK 23 April 1998 4. Guillaume Chaslot, Sander Bakkes, Istvan Szita and Pieter Spronck, Monte-

Carlo Proceedings of the Fourth Artificial Intelligence and Interactive Dig- ital Entertainment Conference - Tree Search: A New Framework for Game AI

5. Peter Drake and Steve Uurtamo. Heuristics in Monte Carlo Go. In Pro- ceedings of the 2007 International Conference on Artificial Intelligence.

CSREA Press, 2007

6. Christopher Fellows, Yuri Malitsky, Gregory Wojtaszczyk, Exploring GnuGo’s Evaluation Function with a SVM, American Association for Artificial In- telligence (2006)

(14)

7. Jay Burmeister and Janet Wiles, AI Techniques Used in Computer Go, Schools of Information Technology and Psychology, The University of Queensland, Australia

8. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein.

Introduction to Algorithms, Third Edition. MIT Press, 2009.

9. Victor Allis (1994). Searching for Solutions in Games and Artificial Intelli- gence. Ph.D. Thesis, University of Limburg, Maastricht, The Netherlands.

ISBN 90-900748-8-0.

10. Cameron Browne, Edward Powley, Daniel Whitehouse, Simon Lucas, Pe- ter I. Cowling, Philipp Rohlfhagen, Stephen Tavener, Diego Perez, Spyri- don Samothrakis and Simon Colton, A Survey of Monte Carlo Tree Search Methods, IEEE transactions on computational intelligence and AI in games, vol. 4, no. 1, March 2012

.

(15)

8 Appendix A

This appendix contains the source code of our project.

Listing 1: MCTS.hpp

#i f n d e f MCTS HPP

#define MCTS HPP

#include <chrono>

#include <memory>

#include ”move . hpp”

#include ” board . hpp”

#include ” t r e e n o d e . hpp”

#include ” p l a y h e u r i s t i c . hpp”

template<long D>

c l a s s MCTS { private :

const Board<D>& board ;

const P l a y H e u r i s t i c <D>& p l a y H e u r i s t i c ; const C o l o r c o l o r ;

public :

MCTS( const Board<D>& board , const P l a y H e u r i s t i c <D>&

p l a y H e u r i s t i c , C o l o r c o l o r ) : board ( board ) ,

p l a y H e u r i s t i c ( p l a y H e u r i s t i c ) , c o l o r ( c o l o r ) { }

Move getMove ( const long t i m e l i m i t ) const {

C o l o r o p p o n e n t C o l o r = g e t O p p o n e n t C o l o r ( c o l o r ) ; P l a y H e u r i s t i c A l l <D> o p p o n e n t P l a y H e u r i s t i c ; auto boardCopy = board . c l o n e ( ) ;

TreeNode<D> ∗ t r e e N o d e = new TreeNode<D>(boardCopy , o p p o n e n t P l a y H e u r i s t i c ,

p l a y H e u r i s t i c ,

o p p o n e n t C o l o r ,

c o l o r , 0 ) ; auto s t a r t = s t d : : c h r o n o : : s t e a d y c l o c k : : now ( ) ; auto end = s t d : : c h r o n o : : s t e a d y c l o c k : : now ( ) ; auto ms = s t d : : c h r o n o : : d u r a t i o n <double , s t d : :

m i l l i >(end−s t a r t ) . c o u n t ( ) ; do {

(16)

treeNode−>s e l e c t A c t i o n ( ) ;

end = s t d : : c h r o n o : : s t e a d y c l o c k : : now ( ) ;

ms = s t d : : c h r o n o : : d u r a t i o n <double , s t d : : m i l l i

>(end−s t a r t ) . c o u n t ( ) ; } while ( ms < t i m e l i m i t ) ;

Move move = treeNode−>getMove ( ) ; delete t r e e N o d e ;

return move ; }

} ;

#endif

Listing 2: MCTSAI.hpp

#i f n d e f MCTSAI HPP

#define MCTSAI HPP

#include ” c o l o r . hpp”

#include ” p l a y e r . hpp”

#include ” board . hpp”

#include ”game . hpp”

#include ”MCTS. hpp”

#include ” p l a y h e u r i s t i c . hpp”

#include ”move . hpp”

template <long D>

c l a s s MCTSAI : public P l a y e r <D> { private :

const C o l o r c o l o r ;

const P l a y H e u r i s t i c <D>& p l a y H e u r i s t i c ; const long t i m e l i m i t ;

public :

MCTSAI( const C o l o r c o l o r ,

const P l a y H e u r i s t i c <D>& p l a y H e u r i s t i c , const long t i m e l i m i t ) :

c o l o r ( c o l o r ) ,

p l a y H e u r i s t i c ( p l a y H e u r i s t i c ) , t i m e l i m i t ( t i m e l i m i t ) {

}

v i r t u a l Move getMove ( const Board<D>& board ) const { MCTS<D> mcts ( board , p l a y H e u r i s t i c , c o l o r ) ;

return mcts . getMove ( t i m e l i m i t ) ; }

v i r t u a l const C o l o r& g e t C o l o r ( ) const { return c o l o r ;

}

(17)

v i r t u a l void gameOver ( const Board<D>& board ) const { }

} ;

#endif

Listing 3: board.hpp

#i f n d e f DEFINE BOARD

#define DEFINE BOARD

#include <s e t >

#include < l i s t >

#include <a r r a y >

#include <memory>

#include <v e c t o r >

#include < u t i l i t y >

#include <i o s t r e a m >

#include <a r r a y >

#include ”game . hpp”

#include ”move . hpp”

#include ” s c o r e . hpp”

#include ” c o l o r . hpp”

#include ” w i n n e r . hpp”

c l a s s P o i n t { public :

enum c l a s s S t a t e { Black , White , Empty } ; public :

P o i n t ( )

: x ( 0 ) , y ( 0 ) , s t a t e ( S t a t e : : Empty ) { }

P o i n t ( const long x , const long y , const S t a t e s t a t e ) : x ( x ) , y ( y ) , s t a t e ( s t a t e ) {

}

bool operator <(const P o i n t& r h s ) const {

return s t d : : t i e ( getX ( ) , getY ( ) , g e t S t a t e ( ) )

< s t d : : t i e ( r h s . getX ( ) , r h s . getY ( ) , r h s . g e t S t a t e ( ) ) ;

}

v i r t u a l ˜ P o i n t ( ) { } ; S t a t e& g e t S t a t e ( ) {

return s t a t e ; }

(18)

const S t a t e& g e t S t a t e ( ) const { return s t a t e ;

}

const long& getX ( ) const { return x ;

}

const long& getY ( ) const { return y ;

} private :

long x ; long y ; S t a t e s t a t e ; } ;

C o l o r p o i n t S t a t e T o C o l o r ( const P o i n t : : S t a t e& s t a t e ) ; P o i n t : : S t a t e c o l o r T o P o i n t S t a t e ( const C o l o r& c o l o r ) ; template<long D>

c l a s s Board { private : public :

using C o o r d i n a t e = s t d : : p a i r <long , long >;

public :

Board ( const C o l o r c o l o r ) : f i n i s h e d ( f a l s e ) ,

l a t e s t M o v e ( g e t O p p o n e n t C o l o r ( c o l o r ) ) , latestKoMove ( c o l o r ) ,

s t a r t e d ( f a l s e ) ,

w i n n e r ( Winner : : T i e ) { }

v i r t u a l ˜ Board ( ) { } ;

v i r t u a l s t d : : s h a r e d p t r <Board> c l o n e ( ) const = 0 ; v i r t u a l P o i n t& g e t P o i n t ( const long x , const long y ) =

0 ;

v i r t u a l const P o i n t& g e t P o i n t ( const long x , const long y ) const = 0 ;

v i r t u a l const P o i n t : : S t a t e& g e t P o i n t S t a t e ( const long x , const long y ) const {

return g e t P o i n t ( x , y ) . g e t S t a t e ( ) ; }

v i r t u a l bool p l a y P o i n t ( const C o l o r c o l o r , const long x , const long y ) {

(19)

i f ( ! s t a r t e d )

s t a r t e d = true ;

i f ( validMove ( c o l o r , x , y ) ) { auto& p o i n t = g e t P o i n t ( x , y ) ;

p o i n t . g e t S t a t e ( ) = c o l o r T o P o i n t S t a t e ( c o l o r ) ; updateBoard ( x , y ) ;

latestKoMove = l a t e s t M o v e ;

l a t e s t M o v e = Move ( c o l o r , p o i n t . getX ( ) , p o i n t . getY ( ) ) ;

return true ; } e l s e {

return f a l s e ; }

}

v i r t u a l void p l a y P a s s ( const C o l o r c o l o r ) { i f ( ! s t a r t e d )

s t a r t e d = true ;

latestKoMove = l a t e s t M o v e ; l a t e s t M o v e = Move ( c o l o r ) ; }

v i r t u a l bool validMove ( const C o l o r c o l o r , const long x , const long y ) const {

const auto& p o i n t = g e t P o i n t ( x , y ) ;

i f ( p o i n t . g e t S t a t e ( ) != P o i n t : : S t a t e : : Empty ) return f a l s e ;

e l s e {

i f ( ! latestKoMove . i s P a s s ( ) ) {

const auto& c o o r d = latestKoMove . getMove ( ) ;

i f ( s t d : : g e t <0>( c o o r d ) == x && s t d : : g e t

<1>( c o o r d ) == y ) { return f a l s e ; }

}

f o r ( const auto& c o o r d : g e t A d j a c e n t ( x , y ) ) { const auto& a d j a c e n t = g e t P o i n t ( c o o r d .

f i r s t , c o o r d . s e c o n d ) ;

i f ( a d j a c e n t . g e t S t a t e ( ) == P o i n t : : S t a t e : : Empty )

return true ; }

f o r ( const auto& c o o r d : g e t A d j a c e n t ( x , y ) ) { const auto& a d j a c e n t = g e t P o i n t ( c o o r d .

f i r s t , c o o r d . s e c o n d ) ;

(20)

i f ( p o i n t S t a t e T o C o l o r ( a d j a c e n t . g e t S t a t e ( ) ) == c o l o r ) {

s t d : : v e c t o r <Point> component ; findComponent ( a d j a c e n t . getX ( ) ,

a d j a c e n t . getY ( ) ,

a d j a c e n t . g e t S t a t e ( ) , component ) ;

s t d : : s e t <Point> f r e e ;

getFreedom ( component , f r e e ) ; i f ( f r e e . s i z e ( ) > 1 ) {

return true ; }

} e l s e {

s t d : : v e c t o r <Point> component ; findComponent ( a d j a c e n t . getX ( ) ,

a d j a c e n t . getY ( ) ,

a d j a c e n t . g e t S t a t e ( ) , component ) ;

s t d : : s e t <Point> f r e e ;

getFreedom ( component , f r e e ) ; i f ( f r e e . s i z e ( ) <= 1 ) {

return true ; }

} } }

return f a l s e ; }

v i r t u a l void gameOver ( ) { f i n i s h e d = true ;

const auto s c o r e = g e t S c o r e ( ) ;

i f ( s c o r e . g e t B l a c k S c o r e ( ) > s c o r e . g e t W h i t e S c o r e ( ) )

w i n n e r = Winner : : B l a c k ;

e l s e i f ( s c o r e . g e t B l a c k S c o r e ( ) < s c o r e . g e t W h i t e S c o r e ( ) )

w i n n e r = Winner : : White ; e l s e

w i n n e r = Winner : : T i e ; }

v i r t u a l bool i s S t a r t e d ( ) const { return s t a r t e d ;

}

v i r t u a l bool i s F i n i s h e d ( ) const { return f i n i s h e d ;

}

(21)

v i r t u a l long g e t C o u n t B l a c k ( ) const {

return g e t C o u n t S t a t e ( P o i n t : : S t a t e : : B l a c k ) ; }

v i r t u a l long getCountEmpty ( ) const {

return g e t C o u n t S t a t e ( P o i n t : : S t a t e : : Empty ) ; }

v i r t u a l long getCountWhite ( ) const {

return g e t C o u n t S t a t e ( P o i n t : : S t a t e : : White ) ; }

v i r t u a l Winner getWinner ( ) const { i f ( ! i s F i n i s h e d ( ) )

throw s t d : : l o g i c e r r o r ( ”Game i s n o t o v e r ” ) ; e l s e

return w i n n e r ; }

v i r t u a l S c o r e g e t S c o r e ( ) const { return a r e a S c o r e ( ) ;

}

v i r t u a l Move g e t L a t e s t M o v e ( ) const { i f ( ! i s S t a r t e d ( ) )

throw s t d : : l o g i c e r r o r ( ”Game n o t s t a r t e d ” ) ; e l s e

return l a t e s t M o v e ; }

v i r t u a l i n t g e t L i b e r t i e s F o r C o m p o n e n t ( const long x , const long y , const C o l o r

c o l o r ) const {

s t d : : v e c t o r <Point> component ;

P o i n t : : S t a t e s t a t e = c o l o r == C o l o r : : White ? P o i n t : : S t a t e : : White : P o i n t : : S t a t e : : B l a c k ; findComponent ( x , y , s t a t e , component ) ;

i f ( component . empty ( ) ) { return D;

}

s t d : : s e t <Point> f r e e ;

getFreedom ( component , f r e e ) ; return f r e e . s i z e ( ) ;

}

(22)

protected :

v i r t u a l void updateBoard ( const long x , const long y ) {

const auto& p o i n t = g e t P o i n t ( x , y ) ;

C o l o r c o l o r = p o i n t S t a t e T o C o l o r ( p o i n t . g e t S t a t e ( ) )

;

auto a d j a c e n t = g e t A d j a c e n t ( x , y ) ; f o r ( const auto& c o o r d : a d j a c e n t ) {

const auto& p o i n t = g e t P o i n t ( c o o r d . f i r s t , c o o r d . s e c o n d ) ;

i f ( p o i n t . g e t S t a t e ( ) == c o l o r T o P o i n t S t a t e ( g e t L a t e s t M o v e ( ) . g e t C o l o r ( ) ) ) {

updateComponent ( c o o r d . f i r s t , c o o r d . s e c o n d ) ;

} }

f o r ( const auto& c o o r d : a d j a c e n t ) {

const auto& p o i n t = g e t P o i n t ( c o o r d . f i r s t , c o o r d . s e c o n d ) ;

i f ( p o i n t . g e t S t a t e ( ) != P o i n t : : S t a t e : : Empty ) {

updateComponent ( c o o r d . f i r s t , c o o r d . s e c o n d ) ;

} } }

v i r t u a l long g e t C o u n t S t a t e ( const P o i n t : : S t a t e s t a t e ) const {

long c o u n t = 0 ;

f o r ( long y = 0 ; y < D; ++y ) { f o r ( long x = 0 ; x < D; ++x ) {

i f ( g e t P o i n t ( x , y ) . g e t S t a t e ( ) == s t a t e ) ++c o u n t ;

} }

return c o u n t ; }

v i r t u a l S c o r e a r e a S c o r e ( ) const { S c o r e s c o r e ;

f o r ( long y = 0 ; y < D; ++y ) { f o r ( long x = 0 ; x < D; ++x ) {

const auto& p o i n t = g e t P o i n t ( x , y ) ; i f ( p o i n t . g e t S t a t e ( ) == P o i n t : : S t a t e : :

White )

++s c o r e . g e t W h i t e S c o r e ( ) ;

(23)

e l s e i f ( p o i n t . g e t S t a t e ( ) == P o i n t : : S t a t e : : B l a c k )

++s c o r e . g e t B l a c k S c o r e ( ) ; }

}

return s c o r e ; }

private :

void updateComponent ( const long x , const long y ) { const auto& p o i n t = g e t P o i n t ( x , y ) ;

s t d : : v e c t o r <Point> component ;

i f ( p o i n t . g e t S t a t e ( ) != P o i n t : : S t a t e : : Empty ) findComponent ( x , y , p o i n t . g e t S t a t e ( ) ,

component ) ; s t d : : s e t <Point> f r e e ;

getFreedom ( component , f r e e ) ; i f ( f r e e . empty ( ) ) {

f o r ( const auto& p o i n t : component ) { g e t P o i n t ( p o i n t . getX ( ) , p o i n t . getY ( ) ) .

g e t S t a t e ( ) =

P o i n t : : S t a t e : : Empty ; }

} }

void getFreedom ( const s t d : : v e c t o r <Point>& component , s t d : : s e t <Point>& f r e e ) const {

f o r ( const auto& p o i n t : component ) {

f o r ( const auto& a d j a c e n t : g e t A d j a c e n t ( p o i n t . getX ( ) , p o i n t . getY ( ) ) ) {

const auto& p o i n t = g e t P o i n t ( a d j a c e n t . f i r s t , a d j a c e n t . s e c o n d ) ;

i f ( p o i n t . g e t S t a t e ( ) == P o i n t : : S t a t e : : Empty )

f r e e . i n s e r t ( p o i n t ) ; }

} }

void findComponent ( const long x , const long y , const P o i n t : : S t a t e s t a t e ,

s t d : : v e c t o r <Point>& component ) const {

(24)

s t d : : a r r a y <s t d : : a r r a y <bool , D>, D> v i s i t e d ; f o r ( long y = 0 ; y < D; ++y )

f o r ( long x = 0 ; x < D; ++x ) v i s i t e d [ y ] [ x ] = f a l s e ;

return findComponent ( x , y , s t a t e , v i s i t e d , component ) ;

}

s t a t i c s t d : : v e c t o r <C o o r d i n a t e > g e t A d j a c e n t ( const long x , const long y ) {

s t d : : v e c t o r <C o o r d i n a t e > a d j a c e n t ; i f ( x+1 < D)

a d j a c e n t . e m p l a c e b a c k ( s t d : : m a k e p a i r ( x + 1 , y ) ) ;

i f ( x−1 >= 0 )

a d j a c e n t . e m p l a c e b a c k ( s t d : : m a k e p a i r ( x − 1 , y ) ) ;

i f ( y+1 < D)

a d j a c e n t . e m p l a c e b a c k ( s t d : : m a k e p a i r ( x , y + 1 ) ) ;

i f ( y−1 >= 0 )

a d j a c e n t . e m p l a c e b a c k ( s t d : : m a k e p a i r ( x , y−1) )

;

return a d j a c e n t ; }

private :

void findComponent ( const long x , const long y , const P o i n t : : S t a t e s t a t e ,

s t d : : a r r a y <s t d : : a r r a y <bool , D>, D

>& v i s i t e d ,

s t d : : v e c t o r <Point>& component ) const {

i f ( v i s i t e d [ y ] [ x ] ) { return ;

} e l s e {

v i s i t e d [ y ] [ x ] = true ;

const auto& p o i n t = g e t P o i n t ( x , y ) ; i f ( p o i n t . g e t S t a t e ( ) == s t a t e ) {

component . e m p l a c e b a c k ( p o i n t ) ;

f o r ( const auto& c o o r d : g e t A d j a c e n t ( x , y ) ) {

findComponent ( c o o r d . f i r s t , c o o r d . sec ond , s t a t e ,

v i s i t e d , component ) ;

(25)

} } } }

bool s t a r t e d ; bool f i n i s h e d ; Move l a t e s t M o v e ; Move latestKoMove ; Winner w i n n e r ; } ;

C o l o r p o i n t S t a t e T o C o l o r ( const P o i n t : : S t a t e& s t a t e ) { return s t a t e == P o i n t : : S t a t e : : White ? C o l o r : : White :

C o l o r : : B l a c k ; }

P o i n t : : S t a t e c o l o r T o P o i n t S t a t e ( const C o l o r& c o l o r ) { return c o l o r == C o l o r : : White ? P o i n t : : S t a t e : : White :

P o i n t : : S t a t e : : B l a c k ; }

#endif

Listing 4: color.hpp

#i f n d e f DEFINE COLOR

#define DEFINE COLOR

#include <i o s t r e a m >

enum c l a s s C o l o r { Black , White } ;

C o l o r g e t O p p o n e n t C o l o r ( const C o l o r c o l o r ) {

return c o l o r == C o l o r : : White ? C o l o r : : B l a c k : C o l o r : : White ;

}

s t d : : o s t r e a m& operator << ( s t d : : o s t r e a m& os , const C o l o r&

c o l o r ) {

o s << ( c o l o r == C o l o r : : B l a c k ? ” b l a c k ” : ” w h i t e ” ) ; return o s ;

}

#endif

Listing 5: endgame.hpp

#i f n d e f DEFINE ENDGAME

#define DEFINE ENDGAME

(26)

#include ”game . hpp”

template<long D>

c l a s s EndGame : public Game<D> { public :

EndGame( const P l a y e r <D>& f i r s t , const P l a y e r <D>&

s e c o n d )

: Game<D>( f i r s t , s e c o n d ) { }

v i r t u a l void s t a r t ( Board<D>& board ) { bool f i r s t P a s s e d = f a l s e ;

bool s e c o n d P a s s e d = f a l s e ;

auto& f i r s t = Game<D> : : g e t F i r s t P l a y e r ( ) ; auto& s e c o n d = Game<D> : : g e t S e c o n d P l a y e r ( ) ; while ( ! f i r s t P a s s e d | | ! s e c o n d P a s s e d ) {

{

hookTurn ( board ) ; i f ( ! f i r s t P a s s e d ) {

const auto move = f i r s t . getMove ( board ) ;

i f ( ! move . i s P a s s ( ) ) {

const auto& c o o r d = move . getMove ( ) ;

i f ( ! board . p l a y P o i n t ( f i r s t . g e t C o l o r ( ) ,

s t d : : g e t <0>(

c o o r d ) , s t d : : g e t <1>(

c o o r d ) ) ) {

throw s t d : : l o g i c e r r o r ( ” F i r s t p l a y e r made an i n v a l i d move” ) ;

}

hookMove ( board ) ; } e l s e {

hookPass ( board ) ; f i r s t P a s s e d = true ; }

} } {

i f ( ! s e c o n d P a s s e d ) {

const auto move = s e c o n d . getMove ( board ) ;

i f ( ! move . i s P a s s ( ) ) {

(27)

const auto& c o o r d = move . getMove ( ) ;

i f ( ! board . p l a y P o i n t ( s e c o n d . g e t C o l o r ( ) ,

s t d : : g e t <0>(

c o o r d ) , s t d : : g e t <1>(

c o o r d ) ) ) {

throw s t d : : l o g i c e r r o r ( ” Second p l a y e r made an i n v a l i d move” ) ;

}

hookMove ( board ) ; } e l s e {

hookPass ( board ) ; s e c o n d P a s s e d = true ; }

} } }

gameOver ( board ) ; }

} ;

#endif

Listing 6: game.hpp

#i f n d e f DEFINE GAME

#define DEFINE GAME

#include ” board . hpp”

#include ” p l a y e r . hpp”

template<long D>

c l a s s Game { public :

Game( const P l a y e r <D>& f i r s t , const P l a y e r <D>& s e c o n d ) : f i r s t ( f i r s t ) , s e c o n d ( s e c o n d ) {

}

v i r t u a l void s t a r t ( Board<D>& board ) { bool p a s s = f a l s e ;

f o r ( long i = 0 ; i < 2∗D∗D; ++i ) { {

hookTurn ( board ) ;

const auto move = f i r s t . getMove ( board ) ; i f ( ! move . i s P a s s ( ) ) {

p a s s = f a l s e ;

(28)

const auto& c o o r d = move . getMove ( ) ; i f ( ! board . p l a y P o i n t ( f i r s t . g e t C o l o r ( )

,

s t d : : g e t <0>(

c o o r d ) , s t d : : g e t <1>(

c o o r d ) ) ) { throw s t d : : l o g i c e r r o r ( ” F i r s t

p l a y e r made an i n v a l i d move” ) ; }

hookMove ( board ) ; } e l s e {

board . p l a y P a s s ( f i r s t . g e t C o l o r ( ) ) ; i f ( p a s s ) {

break ; }

hookPass ( board ) ; p a s s = true ; }

} {

const auto move = s e c o n d . getMove ( board ) ; i f ( ! move . i s P a s s ( ) ) {

p a s s = f a l s e ;

const auto& c o o r d = move . getMove ( ) ; i f ( ! board . p l a y P o i n t ( s e c o n d . g e t C o l o r

( ) ,

s t d : : g e t <0>(

c o o r d ) , s t d : : g e t <1>(

c o o r d ) ) ) { throw s t d : : l o g i c e r r o r ( ” Second

p l a y e r made an i n v a l i d move” ) ; }

hookMove ( board ) ; } e l s e {

board . p l a y P a s s ( s e c o n d . g e t C o l o r ( ) ) ; i f ( p a s s ) {

break ; }

hookPass ( board ) ; p a s s = true ; }

} }

gameOver ( board ) ; }

protected :

(29)

v i r t u a l const P l a y e r <D>& g e t F i r s t P l a y e r ( ) { return f i r s t ;

}

v i r t u a l const P l a y e r <D>& g e t S e c o n d P l a y e r ( ) { return s e c o n d ;

}

v i r t u a l void gameOver ( Board<D>& board ) { board . gameOver ( ) ;

f i r s t . gameOver ( board ) ; s e c o n d . gameOver ( board ) ; hookGameOver ( board ) ; }

v i r t u a l void hookTurn ( const Board<D>& board ) const { }

v i r t u a l void hookMove ( const Board<D>& board ) const { }

v i r t u a l void hookPass ( const Board<D>& board ) const { }

v i r t u a l void hookGameOver ( const Board<D>& board ) const {

}

private :

const P l a y e r <D>& f i r s t ; const P l a y e r <D>& s e c o n d ; } ;

#endif

Listing 7: heuristicplayer.hpp

#i f n d e f HEURISTIC PLAYER

#define HEURISTIC PLAYER

#include <t u p l e >

#include <a l g o r i t h m >

#include < i t e r a t o r >

#include <random>

#include <chrono>

(30)

#include ” p l a y e r . hpp”

#include ” p l a y h e u r i s t i c . hpp”

#include ”random . hpp”

template <long D>

c l a s s H e u r i s t i c P l a y e r : public P l a y e r <D> { private :

const C o l o r c o l o r ;

const P l a y H e u r i s t i c <D>& p l a y H e u r i s t i c ; public :

H e u r i s t i c P l a y e r ( const C o l o r c o l o r , const P l a y H e u r i s t i c <D>& p l a y H e u r i s t i c ) :

c o l o r ( c o l o r ) , p l a y H e u r i s t i c ( p l a y H e u r i s t i c ) { } v i r t u a l Move getMove ( const Board<D>& board ) const {

auto moves = p l a y H e u r i s t i c . getMoves ( board , c o l o r )

;

s t d : : s h u f f l e ( moves . b e g i n ( ) , moves . end ( ) , g e n e r a t o r ) ;

auto& move = moves [ 0 ] ; long x = s t d : : g e t <0>(move ) ; long y = s t d : : g e t <1>(move ) ;

return ( x == −1 && y == −1 ? Move ( c o l o r ) : Move ( c o l o r , x , y ) ) ;

}

v i r t u a l const C o l o r& g e t C o l o r ( ) const { return c o l o r ;

}

v i r t u a l void gameOver ( const Board<D>& board ) const { }

} ;

#endif

Listing 8: main.cpp

#include ” t e x t /game . hpp”

#include ” t e x t / p l a y e r . hpp”

#include ” m a t r i x b o a r d . hpp”

#include ” h e u r i s t i c p l a y e r . hpp”

#include ” p l a y h e u r i s t i c a l l . hpp”

#include ” p l a y h e u r i s t i c c l o s e . hpp”

#include ” p l a y h e u r i s t i c s p r e a d . hpp”

#include ” p l a y h e u r i s t i c m i r r o r . hpp”

#include ” p l a y h e u r i s t i c f r e e d o m . hpp”

(31)

#include ”MCTSAI . hpp”

s t a t i c const long D = 6 ;

s t a t i c const long r o u n d s = 1 0 0 ; i n t main ( ) {

P l a y H e u r i s t i c A l l <D> r a n d o m H e u r i s t i c ; P l a y H e u r i s t i c F r e e d o m <D> f r e e H e u r i s t i c ; P l a y H e u r i s t i c M i r r o r <D> m i r r o r H e u r i s t i c ; P l a y H e u r i s t i c C l o s e <D> c l o s e H e u r i s t i c ; P l a y H e u r i s t i c S p r e a d <D> s p r e a d H e u r i s t i c ;

s t d : : a r r a y <P l a y H e u r i s t i c <D>∗ , 5> h e u r i s t i c s = { &r a n d o m H e u r i s t i c ,

&f r e e H e u r i s t i c ,

&m i r r o r H e u r i s t i c ,

&c l o s e H e u r i s t i c ,

&s p r e a d H e u r i s t i c } ;

t e x t : : P l a y e r <D> f a b i a n ( C o l o r : : White ) ;

MCTSAI<D> a i ( C o l o r : : Black , c l o s e H e u r i s t i c , 1 0 0 0 ) ; MatrixBoard<D> board ( f a b i a n . g e t C o l o r ( ) ) ;

Game<D> game ( f a b i a n , a i ) ; game . s t a r t ( board ) ;

/∗ l o n g i = 0 ;

f o r ( c o n s t a u t o& w h i t e : h e u r i s t i c s ) { l o n g j = 0 ;

f o r ( c o n s t a u t o& b l a c k : h e u r i s t i c s ) {

MCTSAI<D> b l a c k P l a y e r ( C o l o r : : Black , ∗ b l a c k , 6 4 ) ;

MCTSAI<D> w h i t e P l a y e r ( C o l o r : : White , ∗ w h i t e , 6 4 ) ;

Game<D> game ( w h i t e P l a y e r , b l a c k P l a y e r ) ; l o n g b l a c k W i n s = 0 ;

l o n g whiteWins = 0 ; t r y {

f o r ( l o n g i = 0 ; i < r o u n d s ; ++i ) { MatrixBoard<D> b o a r d ( w h i t e P l a y e r .

g e t C o l o r ( ) ) ; game . s t a r t ( b o a r d ) ;

i f ( b o a r d . getWinner ( ) == Winner : : B l a c k )

++b l a c k W i n s ;

e l s e i f ( b o a r d . getWinner ( ) == Winner : : White )

(32)

++whiteWins ; }

} c a t c h ( c o n s t c h a r ∗ e r r o r ) {

s t d : : c o u t << ” E r r o r : ” << e r r o r << s t d : : e n d l ;

}

s t d : : c o u t << i << ” v s ” << j << ” : ”

<< whiteWins / ( d o u b l e ) r o u n d s <<

”/”

<< b l a c k W i n s / ( d o u b l e ) r o u n d s <<

s t d : : e n d l ; ++j ;

} ++i ; } ∗/

}

Listing 9: matrixboard.hpp

#i f n d e f DEFINE MATRIXBOARD

#define DEFINE MATRIXBOARD

#include ” board . hpp”

template<long D>

c l a s s MatrixBoard : public Board<D> { public :

MatrixBoard ( const C o l o r c o l o r ) : Board<D>( c o l o r ) , m a t r i x ( ) {

f o r ( long y = 0 ; y < D; ++y ) f o r ( long x = 0 ; x < D; ++x )

m a t r i x [ y ] [ x ] = P o i n t ( x , y , P o i n t : : S t a t e : : Empty ) ;

}

v i r t u a l ˜ MatrixBoard ( ) { } ;

v i r t u a l s t d : : s h a r e d p t r <Board<D>> c l o n e ( ) const { return s t d : : s h a r e d p t r <MatrixBoard<D>>(new

MatrixBoard ( ∗ t h i s ) ) ; }

v i r t u a l P o i n t& g e t P o i n t ( const long x , const long y ) { i f ( x < 0 | | y < 0 | | x >= D | | y >= D)

throw s t d : : o u t o f r a n g e ( f u n c ) ; return m a t r i x [ y ] [ x ] ;

}

(33)

v i r t u a l const P o i n t& g e t P o i n t ( const long x , const long y ) const {

i f ( x < 0 | | y < 0 | | x >= D | | y >= D) throw s t d : : o u t o f r a n g e ( f u n c ) ; return m a t r i x [ y ] [ x ] ;

} private :

P o i n t m a t r i x [D ] [ D ] ; } ;

#endif

Listing 10: move.hpp

#i f n d e f DEFINE MOVE

#define DEFINE MOVE

#include <t u p l e >

#include ” c o l o r . hpp”

c l a s s Move { public :

using C o o r d i n a t e = s t d : : t u p l e <long , long >;

public :

Move ( const C o l o r c o l o r )

: p a s s ( true ) , c o l o r ( c o l o r ) , c o o r d i n a t e ( s t d : : m a k e t u p l e ( 0 , 0 ) ) {

}

Move ( const C o l o r c o l o r , const long x , const long y ) : p a s s ( f a l s e ) , c o l o r ( c o l o r ) , c o o r d i n a t e ( s t d : :

m a k e t u p l e ( x , y ) ) { }

bool i s P a s s ( ) const { return p a s s ; }

C o l o r g e t C o l o r ( ) const { return c o l o r ;

}

C o o r d i n a t e getMove ( ) const { i f ( p a s s )

throw ” P l a y e r p a s s e d ” ; e l s e

return c o o r d i n a t e ;

(34)

} private :

bool p a s s ; C o l o r c o l o r ;

C o o r d i n a t e c o o r d i n a t e ; } ;

#endif

Listing 11: player.hpp

#i f n d e f PLAYER HPP

#define PLAYER HPP

#include <t u p l e >

#include ”move . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y e r { public :

v i r t u a l ˜ P l a y e r ( ) {}

v i r t u a l const C o l o r& g e t C o l o r ( ) const = 0 ;

v i r t u a l Move getMove ( const Board<D>& board ) const = 0 ;

v i r t u a l void gameOver ( const Board<D>& board ) const = 0 ;

} ;

#endif

Listing 12: playheuristic.hpp

#i f n d e f PLAY HEURISTIC HPP

#define PLAY HEURISTIC HPP

#include <t u p l e >

#include <v e c t o r >

#include <cmath>

#include ” board . hpp”

#include ” c o l o r . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c { public :

v i r t u a l ˜ P l a y H e u r i s t i c ( ) { }

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const = 0 ;

s t a t i c double g e t D i s t a n c e ( s t d : : t u p l e <long , long>&

f i r s t , s t d : : t u p l e <long , long>& s e c o n d ) {

(35)

long x D i f f = s t d : : g e t <0>( f i r s t ) − s t d : : g e t <0>(

s e c o n d ) ;

long y D i f f = s t d : : g e t <1>( f i r s t ) − s t d : : g e t <1>(

s e c o n d ) ;

return s q r t ( x D i f f ∗ x D i f f + y D i f f ∗ y D i f f ) ; }

} ;

#endif

Listing 13: playheuristicall.hpp

#i f n d e f PLAY HEURISTIC ALL HPP

#define PLAY HEURISTIC ALL HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include ” p l a y h e u r i s t i c . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c A l l : public P l a y H e u r i s t i c <D> { public :

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const {

i n t e = board . getCountEmpty ( ) − 2 ; i n t b = board . g e t C o u n t B l a c k ( ) ; i n t w = board . getCountWhite ( ) ;

i n t my = c o l o r == C o l o r : : White ? w : b ; i n t opponent = my == w ? b : w ;

i n t d i f f = my − opponent ;

s t d : : v e c t o r <s t d : : t u p l e <long , long> > moves ; i f ( e < d i f f ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e i f ( d i f f > 0 && board . g e t L a t e s t M o v e ( ) .

i s P a s s ( ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e {

f o r ( long x = 0 ; x < D; ++x ) { f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y ) ) { moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x

, y ) ) ;

(36)

} } }

i f ( moves . s i z e ( ) == 0 ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; }

}

return moves ; }

} ;

#endif

Listing 14: playheuristicclose.hpp

#i f n d e f PLAY HEURISTIC CLOSE HPP

#define PLAY HEURISTIC CLOSE HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include <a l g o r i t h m >

#include ” p l a y h e u r i s t i c . hpp”

#include ” p l a y h e u r i s t i c d i s t a n c e . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c C l o s e : public P l a y H e u r i s t i c D i s t a n c e <D

> { public :

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const {

return P l a y H e u r i s t i c D i s t a n c e <D> : : getMoves ( board , c o l o r , f a l s e ) ;

} } ;

#endif

Listing 15: playheuristicdistance.hpp

#i f n d e f PLAY HEURISTIC DISTANCE HPP

#define PLAY HEURISTIC DISTANCE HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include <a l g o r i t h m >

(37)

#include ” p l a y h e u r i s t i c . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c D i s t a n c e : public P l a y H e u r i s t i c <D> { public :

s t a t i c const i n t MAGIC = 5 ;

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const = 0 ;

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r , bool s p r e a d ) const {

i n t e = board . getCountEmpty ( ) − 2 ; i n t b = board . g e t C o u n t B l a c k ( ) ; i n t w = board . getCountWhite ( ) ;

i n t my = c o l o r == C o l o r : : White ? w : b ; i n t opponent = my == w ? b : w ;

i n t d i f f = my − opponent ;

s t d : : v e c t o r <s t d : : t u p l e <long , long> > moves ; i f ( e < d i f f ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e i f ( ! board . i s S t a r t e d ( ) | | board .

g e t L a t e s t M o v e ( ) . i s P a s s ( ) ) { f o r ( long x = 0 ; x < D; ++x ) {

f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y ) ) { moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x

, y ) ) ; }

} }

} e l s e i f ( d i f f > 0 && board . g e t L a t e s t M o v e ( ) . i s P a s s ( ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e {

i f ( board . g e t L a t e s t M o v e ( ) . i s P a s s ( ) | | ! board . i s S t a r t e d ( ) ) {

f o r ( long x = 0 ; x < D; ++x ) { f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x , y ) ) ;

(38)

} } } } e l s e {

auto c o o r d s = board . g e t L a t e s t M o v e ( ) . getMove ( ) ;

s t d : : v e c t o r <s t d : : t u p l e <double , s t d : : t u p l e

<long , long> > > p o s s i b l e M o v e s ; f o r ( long x = 0 ; x < D; ++x ) {

f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y ) ) {

auto move = s t d : : m a k e t u p l e ( x , y ) ;

p o s s i b l e M o v e s . p u s h b a c k ( s t d : : m a k e t u p l e ( P l a y H e u r i s t i c <D

> : : g e t D i s t a n c e ( c o o r d s , move ) , move ) ) ;

} } }

s t d : : s o r t ( s t d : : b e g i n ( p o s s i b l e M o v e s ) , s t d : : end ( p o s s i b l e M o v e s ) ,

[& s p r e a d ] ( const s t d : : t u p l e <

double , s t d : : t u p l e <long , long> >& S ,

const s t d : : t u p l e <

double , s t d : : t u p l e

<long , long> >& R) {

i f ( s p r e a d ) {

return s t d : : g e t <0>(S ) >

s t d : : g e t <0>(R) ; } e l s e {

return s t d : : g e t <0>(S ) <

s t d : : g e t <0>(R) ; }

} ) ;

s t d : : v e c t o r <s t d : : t u p l e <long , long> >

c a n d i d a t e s ;

f o r ( long i = 0 ; i < MAGIC && i <

p o s s i b l e M o v e s . s i z e ( ) ; ++i ) { moves . p u s h b a c k ( s t d : : g e t <1>(

p o s s i b l e M o v e s [ i ] ) ) ; }

} }

(39)

i f ( moves . s i z e ( ) == 0 ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; }

return moves ; }

} ;

#endif

Listing 16: playheuristicfreedom.hpp

#i f n d e f PLAY HEURISTIC FREEDOM HPP

#define PLAY HEURISTIC FREEDOM HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include ” p l a y h e u r i s t i c . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c F r e e d o m : public P l a y H e u r i s t i c <D> { public :

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const {

i n t e = board . getCountEmpty ( ) − 2 ; i n t b = board . g e t C o u n t B l a c k ( ) ; i n t w = board . getCountWhite ( ) ;

i n t my = c o l o r == C o l o r : : White ? w : b ; i n t opponent = my == w ? b : w ;

i n t d i f f = my − opponent ;

s t d : : v e c t o r <s t d : : t u p l e <long , long> > moves ; i f ( e < d i f f ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e i f ( d i f f > 0 && board . g e t L a t e s t M o v e ( ) .

i s P a s s ( ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e {

f o r ( long x = 0 ; x < D; ++x ) { f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y )

(40)

&& board . g e t L i b e r t i e s F o r C o m p o n e n t ( x , y , c o l o r ) > 1 ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x , y ) ) ;

} } }

i f ( moves . s i z e ( ) == 0 ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; }

}

return moves ; }

} ;

#endif

Listing 17: playheuristicmirror.hpp

#i f n d e f PLAY HEURISTIC MIRROR HPP

#define PLAY HEURISTIC MIRROR HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include <a r r a y >

#include <queue>

#include ” p l a y h e u r i s t i c . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c M i r r o r : public P l a y H e u r i s t i c <D> { public :

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const {

i n t e = board . getCountEmpty ( ) − 2 ; i n t b = board . g e t C o u n t B l a c k ( ) ; i n t w = board . getCountWhite ( ) ;

i n t my = c o l o r == C o l o r : : White ? w : b ; i n t opponent = my == w ? b : w ;

i n t d i f f = my − opponent ;

s t d : : v e c t o r <s t d : : t u p l e <long , long> > moves ;

(41)

i f ( e < d i f f ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e i f ( ! board . i s S t a r t e d ( ) | | board .

g e t L a t e s t M o v e ( ) . i s P a s s ( ) ) { f o r ( long x = 0 ; x < D; ++x ) {

f o r ( long y = 0 ; y < D; ++y ) {

i f ( board . validMove ( c o l o r , x , y ) ) { moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x

, y ) ) ; }

} }

} e l s e i f ( d i f f > 0 && board . g e t L a t e s t M o v e ( ) . i s P a s s ( ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; } e l s e {

auto c o o r d s = board . g e t L a t e s t M o v e ( ) . getMove ( )

;

s t d : : queue<s t d : : t u p l e <long , long> > queue ; long mirrorX = D − s t d : : g e t <0>( c o o r d s ) − 1 ; long mirrorY = D − s t d : : g e t <1>( c o o r d s ) − 1 ; queue . push ( s t d : : m a k e t u p l e ( mirrorX , mirrorY ) )

;

s t d : : a r r a y <bool , D ∗ D> v i s i t e d ; while ( ! queue . empty ( ) ) {

auto& c u r r e n t = queue . f r o n t ( ) ; queue . pop ( ) ;

long x = s t d : : g e t <0>( c u r r e n t ) ; long y = s t d : : g e t <1>( c u r r e n t ) ; i f ( board . validMove ( c o l o r , x , y ) ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( x , y ) ) ;

} e l s e i f ( moves . empty ( ) ) {

i f ( x != 0 && ! v i s i t e d [ y ∗ D + ( x − 1 ) ] ) {

queue . push ( s t d : : m a k e t u p l e ( x −1 , y ) ) ;

v i s i t e d [ y ∗ D + ( x − 1 ) ] = true ; }

i f ( x != D−1 && ! v i s i t e d [ y ∗ D + ( x + 1 ) ] ) {

queue . push ( s t d : : m a k e t u p l e ( x+1 , y ) ) ;

(42)

v i s i t e d [ y ∗ D + ( x + 1 ) ] = true ; }

i f ( y != 0 && ! v i s i t e d [ ( y − 1 ) ∗ D + x ] ) {

queue . push ( s t d : : m a k e t u p l e ( x , y

−1) ) ;

v i s i t e d [ ( y − 1 ) ∗ D + x ] = true ; }

i f ( y != D−1 && ! v i s i t e d [ ( y + 1 ) ∗ D + x ] ) {

queue . push ( s t d : : m a k e t u p l e ( x , y +1) ) ;

v i s i t e d [ ( y + 1 ) ∗ D + x ] = true ; }

} } }

i f ( moves . s i z e ( ) == 0 ) {

moves . p u s h b a c k ( s t d : : m a k e t u p l e ( −1 , −1) ) ; }

return moves ; }

} ;

#endif

Listing 18: playheuristicspread.hpp

#i f n d e f PLAY HEURISTIC SPREAD HPP

#define PLAY HEURISTIC SPREAD HPP

#include <v e c t o r >

#include <t u p l e >

#include <cmath>

#include <a l g o r i t h m >

#include ” p l a y h e u r i s t i c . hpp”

#include ” p l a y h e u r i s t i c d i s t a n c e . hpp”

#include ” board . hpp”

template <long D>

c l a s s P l a y H e u r i s t i c S p r e a d : public P l a y H e u r i s t i c D i s t a n c e <

D> { public :

v i r t u a l s t d : : v e c t o r <s t d : : t u p l e <long , long> >

getMoves ( const Board<D>& board , const C o l o r c o l o r ) const {

(43)

return P l a y H e u r i s t i c D i s t a n c e <D> : : getMoves ( board , c o l o r , true ) ;

} } ;

#endif

Listing 19: random.hpp

#i f n d e f RANDOM HPP

#define RANDOM HPP

#include <random>

s t a t i c s t d : : r a n d o m d e v i c e rd ;

s t a t i c s t d : : mt19937 g e n e r a t o r ( rd ( ) ) ;

#endif

Listing 20: score.hpp

#i f n d e f DEFINE SCORE

#define DEFINE SCORE c l a s s S c o r e {

public : S c o r e ( )

: b l a c k S c o r e ( 0 ) , w h i t e S c o r e ( 0 ) { }

S c o r e ( const long b l a c k S c o r e , const long w h i t e S c o r e ) : b l a c k S c o r e ( b l a c k S c o r e ) , w h i t e S c o r e ( w h i t e S c o r e )

{ }

v i r t u a l long& g e t B l a c k S c o r e ( ) { return b l a c k S c o r e ;

}

v i r t u a l const long& g e t B l a c k S c o r e ( ) const { return b l a c k S c o r e ;

}

v i r t u a l long& g e t W h i t e S c o r e ( ) { return w h i t e S c o r e ;

}

v i r t u a l const long& g e t W h i t e S c o r e ( ) const { return w h i t e S c o r e ;

}

(44)

private :

long b l a c k S c o r e ; long w h i t e S c o r e ; } ;

#endif

References

Related documents

Not so much a limitation but a caveat, I wish to say something about the paper’s lack of any conceptualization and problematization of place and space, it also does not

The results show a clear correlation between level of prediction and the average number of cleared rows, as well as an increase in the average number of cleared rows when

The results from the coding in study 2 were replicated as the largest proportion, 41,7% of the participants reported verbal protocols describing the ratio rule, 16%

We derive properties of the RWS which are known to hold for finite-state space models of adaptive play, such as the convergence to and existence of a unique invariant distribution

Figure 2: Hand postures controlling a prototype scenario: (a) a hand with three open.. ngers toggles the TV on or o , (b) a hand with two open ngers and the index

When the lorry types and allowed trains have been determined for all demand occurrences, they are put on a list and sorted according to the potential cost savings in the road

I Figur 23 visas de olika driftsfallen; normal drift, befuktat bränsle, lägre rökgastemperatur samt kombinationen av lägre rökgastemperatur och befuktat bränsle För att

International Graduate School of Management and Engineering, IMIE Dissertation No.. Den här avhandlingens syfte är att beskriva och analysera vilken påverkan samarbete i