development of a chess engine

37
Registration number 4692306 2015 Development of a Chess Engine Supervised by Dr Gavin Cawley University of East Anglia Faculty of Science School of Computing Sciences

Upload: others

Post on 10-Jan-2022

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Development of a Chess Engine

Registration number 4692306

2015

Development of a Chess Engine

Supervised by Dr Gavin Cawley

University of East Anglia

Faculty of Science

School of Computing Sciences

Page 2: Development of a Chess Engine

Abstract

The majority of chess engines are designed to play the most popular version of chess,

Western chess. While these engines can technically play several variants, there is rarely

any specific tactical implementations to adapt them to playing with more obscure rule-

sets and consequently the ability of said engines can be diminished. The purpose of

the project is to explore and examine the core components of a chess engine in order

to create an engine that specialises in a relatively unknown chess variant called Horde

Chess. Data is collected by testing different adaptations of the pieces used by Horde

chess and several specific tactical improvements. The analysis of the collected data

produce a set of interesting results and possible improvements to the original board set-

up. A final analysis on the efficiency of the engine is performed leading to improvements

to engine performance.

Acknowledgements

I would firstly like to thank my project supervisor, Dr Gavin Cawley, for his support and

feedback through the duration of this project. I would also like to acknowledge both

Dr. Pierre Chardaire and Dr. Richard Harvey for the support and organisation of the

module.

Page 3: Development of a Chess Engine

CMPC3P2Y

Contents

1. Introduction 6

1.1. Selecting a Chess Variant . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2. Horde Chess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2. Principles of a Chess Engine 10

2.1. Board Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.1.1. Piece Centric . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.1.2. Square Centric . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.2. Search Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

2.2.1. Shannon’s Types . . . . . . . . . . . . . . . . . . . . . . . . . 12

2.2.2. Minimax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.2.3. Alpha-Beta Pruning . . . . . . . . . . . . . . . . . . . . . . . . 13

2.2.4. Further Optimisation . . . . . . . . . . . . . . . . . . . . . . . 13

2.3. Evaluation Philosophies . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.3.1. Performance Balance . . . . . . . . . . . . . . . . . . . . . . . 14

2.3.2. Game Phase . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.3.3. Shannon’s Evaluation . . . . . . . . . . . . . . . . . . . . . . . 15

3. Analysis of Horde Chess Strategy 16

3.1. White Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.2. Black Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4. Engine Development 18

4.1. Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4.2. Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4.3. Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

4.4. Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . . . . 22

5. Evaluating Chess Engine Performace 23

5.1. Build Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5.2. Code Optimisations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

Reg: 4692306 iii

Page 4: Development of a Chess Engine

CMPC3P2Y

5.3. Transposition Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

6. Evaluating Horde Chess Equality 26

6.1. Original Board Set-Up . . . . . . . . . . . . . . . . . . . . . . . . . . 26

6.2. Board Adaptations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

6.2.1. No Extra Pawns . . . . . . . . . . . . . . . . . . . . . . . . . . 27

6.2.2. Two Extra Pawns . . . . . . . . . . . . . . . . . . . . . . . . . 28

6.2.3. White Pawn Handicap . . . . . . . . . . . . . . . . . . . . . . 30

7. Conclusions 31

References 34

A. Minimax Algorithm Pseudocode 35

B. Alpha-Beta Pruning Algorithm Pseudocode 36

C. Claude Shannon’s Evaluation Function 37

Reg: 4692306 iv

Page 5: Development of a Chess Engine

CMPC3P2Y

List of Figures

1. Dusany’s chess initial board set-up. . . . . . . . . . . . . . . . . . . . 7

2. A shortlist of chess variants to be considered for the engine. . . . . . . 8

3. Horde chess initial board set-up. . . . . . . . . . . . . . . . . . . . . . 9

4. Diagram illustrating how bitboards can represent a chessboard. . . . . 11

5. A graph showing the relation between depth and the number of moves

in the search tree. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

6. The default board structure for horde chess as declared in the initialisa-

tion text file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

7. Calculating the evaluation score . . . . . . . . . . . . . . . . . . . . . 21

8. Final Graphical User Interface . . . . . . . . . . . . . . . . . . . . . . 23

9. Visual Studio 2013 Ultimate Build Settings . . . . . . . . . . . . . . . 25

10. Alternative board arrangement with no extra pawns . . . . . . . . . . . 28

11. Alternative board arrangement with two extra pawns . . . . . . . . . . 29

12. Alternative board arrangement with a white pawn handicap . . . . . . . 30

13. Close-up to show moves and times at a depth of 5 . . . . . . . . . . . . 32

Reg: 4692306 5

Page 6: Development of a Chess Engine

CMPC3P2Y

1. Introduction

The objective of this project is to create a chess engine that can play either the stan-

dard ‘Western’, or ‘International’, chess or an alternative variant of chess. Through

research, it is clear that the majority of chess engines specialise in the standard ver-

sion of chess; however, there are many that play other variations such as ‘Xiangqi’ and

‘Shogi’ (commonly referred to as ‘Chinese Chess’ and ‘Japanese Chess’ respectively).

While deciding to pursue the more frequently used and most familiar version of chess

may be preferable due to the volume of literature available on the strategies used, this

decreases potential for experimentation and originality in the more advanced strategic

decisions that the engine makes. For these reasons, the more interesting and informative

way to approach this is to choose a variant of chess that is not as common and thus will

offer greater opportunities to research and study different strategic decisions.

1.1. Selecting a Chess Variant

There are several ways that Western chess can be adapted to create a variant. Often the

variant will use a larger or smaller chessboard than Western chess’ 8x8 tile board, for

example Shogi chess utilises a 9x9 board with 81 individual tiles. In some cases the

geometry of each tile is changed to create boards that differ from the standard square.

Glinski’s Hexagonal Chess uses 91 hexagonal tiles, or hexes, comprised of 3 different

colours that create a hexagonal board where each edge is 6 hexes long.

The standard board set-up can be adapted to create alternative variances by adding or

removing pieces that belong to the standard piece set. This creates a completely different

strategic outlook without editing the board array. Generally, these variants also change

the game objective and the conditions that need to be met for either team to win or a

stalemate to be declared. Figure 1 shows the starting board used in Dusany’s chess, a

good example of a variant that has these properties by adapting one of the piece-sets to

contain purely pawns. A more extreme approach is editing the piece set itself by adding

new unorthodox pieces with different properties. These new pieces are known as ‘fairy

pieces’ and are their properties have no limits. Examples of fairy pieces include the

‘Princess’, an amalgamation of a knight and a bishop that can move in the fashion of a

Reg: 4692306 6

Page 7: Development of a Chess Engine

CMPC3P2Y

Image generated at http://www.jinchess.com/chessboard/composer/

Figure 1: Dusany’s chess initial board set-up.

bishop or a knight. This is exceptionally useful as it means that a princess piece, unlike

a regular bishop, is not restricted to the colour tile that it started on. Another is the

‘Nightrider’ piece, which is displayed as an inverted knight. The nightrider moves like

a knight but can make any number of knight moves in any one direction, so long as none

of them are blocked.

Due to the complexity of traversing a board that uses tiles of a different shape, these

variants should be disregarded while choosing the correct chess variant. Instead, a vari-

ant that either uses fairy pieces or that adapts the standard board set-up with simple

game objective changes should be the main focus when making a selection. Using these

criteria, a shortlist of variants that are suitable for the engine is created and shown in

Figure 2.

Using the shortlist described in Figure 2, a decision needs to be made on which of

the three variants is the most suitable by briefly analysing the scope for experimentation

and the frequency of use in chess engines. Following these principles, it suggests that

the best choice for the project is Horde chess as there is a relatively small amount of

research performed on this variant when compared to the others.

Reg: 4692306 7

Page 8: Development of a Chess Engine

CMPC3P2Y

King’s Corner Chess

The king is placed in the bottom right corner and the rest of the bottom row is

arranged randomly. Each side uses the same random set-up and each of side

must have one bishop on white and one on black. The pieces do not mirror the

opposition in the same way as Western chess.

Horde Chess

The white side is set up in the same way as Western chess and the black side is

comprised of 32 pawns. The black side wins in the standard Western fashion of

checkmating the white king, white wins if all the black pawns are taken and a

stalemate is declared if either side has no valid moves.

Knightmate Chess

Very similar to Western chess, except the knight swap roles with the king. Ef-

fectively this means that each player has two kings and one knight and the player

must attempt to capture, or ‘knightmate’, the opposition knight. The pieces keep

their original movement characteristics and pawns can promote to kings instead

of knights.

Figure 2: A shortlist of chess variants to be considered for the engine.

1.2. Horde Chess

Horde chess is a variation of a more well recognised variation called Dusany’s chess,

in which one side has the standard set-up and the opposition’s ranks are composed of 4

rows of pawns.

The main difference with Horde chess is the placement of the pawns, with the two

central pawns that occupy the spaces where the king and queen would sit on a standard

chessboard set-up are moved to the fifth row, as shown in Figure 3. One of the most

important factors of horde chess is that the board set-up is still being refined, due to

the large weighting towards the white side, which can be seen in Table 1. This enables

the opportunity to examine a range of initial pawn structures in order to create a more

balanced game.

Reg: 4692306 8

Page 9: Development of a Chess Engine

CMPC3P2Y

Image generated at http://www.jinchess.com/chessboard/composer/

Figure 3: Horde chess initial board set-up.

Table 1: Statistics of Horde Chess Resultsa

Winner Number of Wins Win Percentage

White 6351 71.56%

Black 2258 25.44%

Stalemate 266 2.99%

a Statistics collected by Brainking.com over 8875 matches

Furthermore, as Horde chess has not had a large quantity of strategic research per-

formed on the game type, it allows for a more innovative approach to the strategic

decisions that the engine will need to make to improve it’s ability. The variant differs

from Western chess enough to essentially render the majority of the common strategies

used redundant when it comes to Horde chess and provides a compelling challenge.

Reg: 4692306 9

Page 10: Development of a Chess Engine

CMPC3P2Y

2. Principles of a Chess Engine

Upon analysing the game of chess and applying an understanding of software devel-

opment, you can break the game down into 3 core components: board representation,

search functions and move evaluation. For each of these elements there are a variety of

approaches that can be used, which will be outlined and assessed in this section.

2.1. Board Representation

As with any real-world problem that needs to be translated into a form that a computer

can understand, there are different philosophies to represent a chessboard in code. The

two key approaches to this issue are: a system that focuses on storing data for each of

the pieces on the board, piece centric, or a system that stores data for each tile on the

board, square centric.

2.1.1. Piece Centric

A piece centric representation stores information for each piece on the board including,

but not limited to, the location of the piece and colour. The most frequently used im-

plementation of this approach uses bitboards, a finite set of no more than 64 bits, where

each bit represents a certain piece of information about the subject; as illustrated in Fig-

ure 4. The main advantage to using bitboards is that many of the different analytical

techniques used in the search and evaluation stages can be performed a lot faster using

bitwise operations between two bitboards (Rasmussen, 2004). While bitboards defi-

nitely have performance advantages over a square centric approach, their readability is

far lower; thus the amount of bugs introduced during the implementation will be higher.

Because of the importance of having a bug free board representation to build the search

and evaluation on, this may not be the most suitable approach for the engine.

2.1.2. Square Centric

Unlike the piece centric approach, a square centric board representation focuses on em-

ulating the board itself by storing information on a tile by tile basis. A common data

structure used for this is an 8x8 array of integers for random access, which is more

Reg: 4692306 10

Page 11: Development of a Chess Engine

CMPC3P2Y

Source : http://www.onjava.com/pub/a/onjava/2005/02/02/bitsets.html?page=2

Figure 4: Diagram illustrating how bitboards can represent a chessboard.

commonly represented as a one-dimensional array as opposed to a two-dimensional ar-

ray, where each integer represents a specific piece type and colour combination (Hyatt,

1999). This method allows the engine to traverse the board and check each element for

the value of the tile, which will indicate whether that square on the board contains a

specific piece or is an empty square. While this design can make the search and evalu-

ation functions less efficient, it vastly improves readability and will reduce the amount

of errors introduced when implementing the system.

2.2. Search Functions

In any chess engine, the search is the most important part of the system and needs to be

as efficient as possible. This is because the majority of the engine’s power stems from

the amount of moves into the future it can read, otherwise known as the depth or ply of

the search. The search function is going to look at every possible valid move for the side

to move and then for each of those moves check every move that can be made after; this

Reg: 4692306 11

Page 12: Development of a Chess Engine

CMPC3P2Y

would be to a depth of 2. The aim of the chess engine is to be able to search to a depth

of 5 in a reasonable time but, as illustrated in Figure 5, the amount of individual board

evaluations approximately increases as an xn function where x is the number of possible

moves for depth 1 and n is the depth of the search.

Figure 5: A graph showing the relation between depth and the number of moves in the

search tree.

2.2.1. Shannon’s Types

Claude Shannon, one of the pioneers of computer chess, described two types of search:

Type A and Type B (Shannon, 1950). Type A searches, or brute-force searches, look

at every possible variation of the board to a given depth. Type B searches, or selective

searches, use heuristics to only look at branches of the search tree that are promising.

The brute-force searches that Shannon categorised will find the best move possible with

no errors, but will take longer than the Type B searches. Selective searches are much

faster than brute-force searches, but there is the possibility that the best move may be

Reg: 4692306 12

Page 13: Development of a Chess Engine

CMPC3P2Y

discarded for a slightly worse move. These Type B searches were preferred in the earlier

years of chess programming because of the limitations set by the hardware that was

available; however most modern chess engines will use a search algorithm that is much

closer to Type A but will have some aspects of selectivity to increase the efficiency.

2.2.2. Minimax

Minimax is a recursive algorithm used in turn based games in order to find the path

through a tree with the highest value for a certain player (Beal, 1980). In chess it works

by declaring one side, generally white, as the ‘maximising’ player and the other as the

‘minimising’ player. Appendix A shows the pseudocode of one potential implementa-

tion of the minimax algorithm, however it can be split into two separate functions: a

maximising search and a minimising search. Minimax is what is called a depth first

recursive algorithm that will traverse to the furthest node in a branch before evaluating

back up the tree. As there is no heuristics involved in the minimax algorithm, it could

be classed as purely Type A and therefore will not be efficient at higher depths.

2.2.3. Alpha-Beta Pruning

In order to improve the efficiency of the minimax algorithm, some logical analysis or the

search can be applied to reduce the amount of discrete branches that need to be checked.

A common enhancement to the minimax algorithm is called alpha-beta pruning, which

aims to reduce the amount of search paths by excluding certain branches from the search

tree (Edwards and Hart, 1961). As seen in Appendix B, an upper and lower limit (alpha

and beta)are used to prune branches when a move is found with a lower heuristic value

than a previously tested move. This works well as it forces the engine to focus on the

more prosperous routes through the search tree which lowers each total processing time

of the search (Knuth and Moore, 1976).

2.2.4. Further Optimisation

Further optimisations can be made to the algorithm by ordering the moves to be searched

so that the moves that the best move for the each side are searched first, (Fulda, 1985).

Reg: 4692306 13

Page 14: Development of a Chess Engine

CMPC3P2Y

The ordering can be achieved in several ways, one is to use the killer move heuristic

where a list of moves that cause a beta cut-off and do not alter the material on the board

are stored and updated after each iteration; these moves are searched first, followed by

the remaining moves.

2.3. Evaluation Philosophies

The final key component of any chess engine is it’s ability to distinguish the differ-

ence between a good move and a bad move. The evaluation function must be able

to heuristically determine the chances of winning after n moves have occurred. Non-

expert human players perform this by assigning arbitrary values, or material weight, to

the individual pieces and this is also how the chess engine will begin to approach the

problem. To ensure that the engine runs as efficiently as possible, the evaluation needs

to be as lightweight as possible while still providing a meaningful output in relation to

the chances of winning.

2.3.1. Performance Balance

All evaluation functions need to make compromises with the intelligence they possess

as there is a negative correlation between speed and knowledge; as the engines ability to

recognise the difference between a favourable and an unfavourable result, the amount of

time it takes to make the decision increases. This means that attention must be paid to

keeping the execution time of the evaluation to an absolute minimum. Another advan-

tage of using a more lightweight evaluation is that they are far more maintainable when

compared to more complex heavier evaluations, which is important due to the intricate

nature of a chess engine.

2.3.2. Game Phase

Another factor that needs to be taken into account when writing an evaluation is game

phase. Any game of chess will begin in the opening phase, where each side will need

to set up their pieces to enter the middle game in a strong position. The opening phase

typically lasts around 7 or 8 moves for each side and during this time each side will

Reg: 4692306 14

Page 15: Development of a Chess Engine

CMPC3P2Y

want to move pieces into more advanced positions on both edges of the board, develop

the knights and create a defence for their king. As the black side is purely comprised of

pawns, the last two points are not applicable and should be ignored.

Once the opening phase is over, the game moves into what is called the middle phase

or the middle game. This is the largest phase of the game where the majority of the

battle will take place. Players should be looking to limit the mobility of the opponents

pieces while maximising their own and placing pressure on the opponent that will open

up future opportunities to attack. An aggressive play-style during this phase is vital as

the aim is to defeat the other player; however, it is crucial that each player maintains as

many of their key pieces as possible to take into the endgame.

During the final stage of the game, the endgame, there are few pieces left on the board

and the relative value of each type of piece changes. It is often difficult to determine

the exact point where the endgame begins as the transition could occur progressively

or within a matter of a few captures. Throughout the endgame, until a result is found,

pawns become a more valuable piece because the open nature of the board makes pro-

moting a pawn through the highest rank into a more mobile piece far easier. This process

is made less difficult for the side with the largest amount of material value as they can

exchange pieces, whilst retaining the maximum amount of pawns possible, which will

result in a greater chance of winning. Another piece that gains significant attacking

value is the king itself, which can be moved into the central area of the board in order

to use its potential properly. Whilst the king does gain value in an attacking sense and

it is a useful tactic in the endgame, careful consideration must be used because a game

can quickly turn on one mistake.

2.3.3. Shannon’s Evaluation

A journal article written by Claude Shannon (Shannon, 1950) provides a symmetric

evaluation function that takes into account the material value, mobility and information

about the pawns on the board, as can be seen in Appendix C. This evaluation function

is tailored to western chess and it is important to take this into account when developing

an evaluation for Horde chess; however, this is a useful starting point for the function to

be used in the engine.

Reg: 4692306 15

Page 16: Development of a Chess Engine

CMPC3P2Y

3. Analysis of Horde Chess Strategy

Horde chess provides an interesting challenge for the strategic decisions that the chess

engine makes because of the relatively minute amount of content on the subject when

compared to Western chess. While some common tactics could still be used, particu-

larly with white defensive moves, it is clear that fresh concepts need to be examined

(Bourzutschky et al., 2005). In order to analyse which methods could possibly yield a

positive outcome an analysis of the differences in risks for each colour and the strengths

and weaknesses of the pieces that they possess can be performed.

3.1. White Strategy

The white side arguably faces the easiest task, as it has a greater variance in the type

of piece in it’s ranks and thus opens up more strategic options to the engine. An obvi-

ous example of this is that the white side has a multitude of pieces that can move more

than one square in one move, unlike the black side which is composed purely of pawns.

Furthermore, white has two knights which have the ability to jump other pieces which

makes them hard to block. These obvious advantages towards white have been balanced

by the sheer number of opposition pawns, however the pawn has a fundamental weak-

ness that the white side can take advantage of. The movement characteristics of the

pawn dictate that they can only take an enemy piece if it is in a diagonally adjacent tile,

or move one tile forward providing said tile is empty; this is the case unless the pawn

is in the second rank, where it can also move two tiles forward under the same premise

that the tile is empty. The implication of this is that if white can move a piece that can

take opposition pieces in a lateral movement, or in the direction that the black side is

attacking, the piece will be able to continuously take pawns without any risk of being

taken. Therefore a rook, queen, bishop or, less so, a knight behind the opposition pawns

should have a higher value than it would if it were in front.

It is also important to note that if a black pawn reaches the highest rank it can be

promoted to any piece other than a king; generally the pawn will be promoted into a

queen, the most valuable piece available. This suggests that it would be beneficial to

block pawns from advancing to rank 8 and promoting into a piece that could potentially

Reg: 4692306 16

Page 17: Development of a Chess Engine

CMPC3P2Y

swing the game in favour of the black side. This is exceptionally important during the

endgame as promoting pawns becomes much easier and the general attacking potency

of the pawn increases during the final period of the game.

3.2. Black Strategy

Considering the simplicity of the movement characteristics of a pawn, the strategic plan-

ning for the horde of pawns on the black side proposes an interesting challenge. The

clear place to start with developing these strategies is by countering the strategies that

white are going to use by looking to prevent pieces from getting behind or parallel with

the lowest ranked black pawns. This can be achieved by maintaining as many pawns

as possible in the two bordering columns on either side of the board with priority being

given to pawns in columns 1 and 8.

It is crucial that the black side remains attacking in defence which be achieved by

trying to ensure that any pawn is always covered by another. With this tactic in place,

any white piece that takes a pawn can be instantly exchanged. This does not work in

every possible situation, for example if the pawn that is taken is one of the lowest ranked

pawns, but could still increase the chances of winning and the overall skill of the black

side.

In terms of capturing the king during the endgame in order to win the match, the main

aim should be to promote as many pawns as possible into queens. The issue of how to

produce this effect algorithmically in the chess engine is not simple and the limitations

of the engine cause some problems. For example at a depth of 5, the black side can

only forecast the next three moves for its own pieces and a potential promotion could be

out of this visible range. A solution can be achieved by gradually making pawns more

valuable as they increase in rank during the endgame. However, there may need to be

some consideration for the safety of a promoted pawn. If the white side has a rook or

queen on its first rank the newly promoted pawn would be taken in the next move if left

unprotected. Because of this, a pawn that has just been promoted but is protected by

another pawn should be worth more if the promoted pawn is under threat.

Reg: 4692306 17

Page 18: Development of a Chess Engine

CMPC3P2Y

4. Engine Development

The project aim describes the design and implementation of a chess engine, with the

use of a variant being preferred, using any language of choice. When choosing the most

suitable programming language, the desired attributes need to be considered. A suitable

language needs to have a fast execution time, low overhead and good readability. These

properties suggest that C++ would be a good match for the task as, unlike a language

like Java that runs on the Java Virtual Machine, one of the key philosophies of C++ is

that the source code gets compiled directly into assembly code (Stroustrup, 2007). Other

benefits of C++ include it’s efficiency, flexibility and low level memory management.

4.1. Board

With the language decided, the next task is the implementation of the chess board. The

board is declared as a 2-dimensional array of integers where each piece type and colour

combination represents an integer that can also be accessed through an enumeration

of pieces. Using the enumeration gives the programmer an simple way of mapping

a machine-readable format to a human-readable format; for example simply using the

integer 10 as a piece value gives no hint to which piece it is, whereas P_W = 10 helps

to show that the integer 10 is linked to a white pawn. Benefits of using a 2-dimensional

array as the board include random access to the array, allowing for fast access to any

square on the board.

To further improve readability, the code takes advantage of structures, or struct,

which can be used to model and provide simple functions to smaller components of

the engine. An example of this is the use of a structure to simulate a position on the

board and supply a function that returns the string value of said position; for instance

the starting position of the white king, which could be accessed using board[4][0],

would return a string value "e1".

In order to analyse the effects on the bias towards a certain team, a mechanism for

changing the board set-up needs to be created. A basic approach to initialising the board

array would be to hard-code the values into the code itself, which would work well in

circumstances that did not require any changes to the board. To create a more dynamic

Reg: 4692306 18

Page 19: Development of a Chess Engine

CMPC3P2Y

20,30,40,50,60,40,30,20

10,10,10,10,10,10,10,10

-1,-1,-1,-1,-1,-1,-1,-1

-1,-1,-1,11,11,-1,-1,-1

11,11,11,11,11,11,11,11

11,11,11,11,11,11,11,11

11,11,11,11,11,11,11,11

11,11,11,-1,-1,11,11,11

Figure 6: The default board structure for horde chess as declared in the initialisation text

file

system, the engine reads a text document that declares each piece in the board, which

can be seen in Figure 6, converting these values into the correct piece type through the

use of the enumeration previously described and placing them in their respective array

position. With this, several different piece arrangements can be used without the need

to recompile.

4.2. Search

Before being able to search for an optimal move, a method of accessing a list of all avail-

able moves must be created. There are two abstract approaches to this issue: real-time

move generation and a predefined list of possible moves. The problem with producing

the move list at runtime is that, because of the large amount of moves available, it takes

a relatively large amount of processing time which could be spared by using a prede-

fined list. A more suitable approach for the high efficiency requirements of the chess

engine, is to predefine the moves by saving them into files in a format that can be read

into the chess engine when the application is run. A separate application can be written

that works out all possible moves for each piece type, formatting the moves and saving

them to a text file for each piece-colour union. The engine reads each of these files as

part of the initialisation stage and places them into a map structure where the key is the

position of the piece and the value is a vector of all possible moves that the piece can

Reg: 4692306 19

Page 20: Development of a Chess Engine

CMPC3P2Y

make from this square of the board. The disadvantage of using this technique is that

the list of moves generated does not consider any factors that cause certain moves to

become invalid; an example of this is that a pawn, which can only take diagonally, will

not be able to make any of it’s possible moves if there is an enemy directly in front and

the diagonal spaces are either empty or holds an ally piece. This means that some extra

processing must be performed to ensure that each move is valid before considering it

as the best move. This can be done by running each move through a set of specific

algorithms designed to determine the legality of a move for each piece type. While this

extra processing does incur a small amount of overhead, but this addition is far lower

than the load associated with real-time move generation.

With a suitable system for determining all of the valid moves, the implementation of

the search algorithm can begin. The algorithm that the engine uses is a slight variation

on the minimax algorithm, with the difference being that neither team is exclusively

associated as the maximising or minimising player. Instead, all evaluations are worked

out as a relation to the player taking the current turn throughout all depths; effectively

the current turn is always the maximising player. There are three functions that are

defined in the program: findBestMove, minSearch and maxSearch. The initial

call to perform a search at a specific depth is simply, findBestMove(depth);,

which will begin traversing the board tile by tile. For each tile, the engine will find and

check the validity of all moves possible for the piece type of the tile occupant using

the current index as the key to the map of moves. The use of the unordered_map

data type, which has a worst case access of O(log n) and a best case of O(1), provides

excellent access speeds which is important due to the vast number of discrete calls to the

moves vectors. The move is temporarily performed on the board, with the destination

square being saved in case of a capture, before calling maxSearch with a decremented

depth. This function will perform a similar logic to the previous by finding, validating

and making a move then calling minSearch. This will continue until the depth reaches

zero when an evaluation takes place, hence the bottom-up classification of the algorithm.

Appendix B shows that once the evaluation occurs the value is checked against either

alpha or beta, depending on whether a min search or a max search is being performed. If

the beta value falls below the alpha value, the move is certainly worse than a previously

Reg: 4692306 20

Page 21: Development of a Chess Engine

CMPC3P2Y

tested node and can be disregarded. After the value has been established, the move must

be reversed before testing the next move in the vector. Once all tiles on the board have

been tested, the findBestMove function returns the best move and performs it on the

board.

4.3. Evaluation

The evaluation method is loosely based on Claude Shannon’s evaluation function, shown

in Appendix C, and is used to produce a metric on a particular side’s chances of winning.

The engine first calculates a material weight by iterating through the board and summing

the value of each element. The value is generated by accessing an unordered_map

of evaluation scores where the index is the unique piece type and the value is the rela-

tive value of the piece. The pieces may be worth different amounts depending on their

colour; for example, a white pawn is worth 1 point and a black pawn is worth 2 points.

There are some special exceptions to the normal evaluation values that append the more

intricate strategic manipulation described earlier in the report. A white piece that is be-

hind or level with the lowest rank pawn or a black piece that is positioned in either a

border column or at it’s highest rank is worth one more point than the usual piece value.

int r = rand() % 3 - 1;

if (weight == WHITE)

{

int materialScore =

whiteScore * (whiteScore - blackScore);

int mobilityScore =

whiteMobility * (whiteMobility - blackMobility);

return materialScore + mobilityScore + r;

}

Figure 7: Calculating the evaluation score

As well as the material worth, the evaluation function computes the mobility of pieces

by traversing the board and totalling the sum of moves available to each piece on the

Reg: 4692306 21

Page 22: Development of a Chess Engine

CMPC3P2Y

board for each colour. Once each team has a total value, the difference is calculated de-

pending on the current player to move using the method shown in Figure 7. To add some

variance to ‘computer vs computer’ games, a random offset is added to each evaluation

that ranges between -1 and 1 inclusively. This is necessary because the algorithm would

always find the best move possible, which doesn’t ever change and every game would

play exactly the same as the previous. The variance is small enough so that it is highly

improbable to pick a move that is significantly worse than the best possible move.

4.4. Graphical User Interface

A popular method of supplying a chess engine with a GUI is to include support for the

Chess Engine Communication Protocol which allows the engine to be executed by com-

mon chess interfaces, WinBoard (Windows) and XBoard (Linux). This method would

be preferable as the project did not require that an interface be created for the engine;

however, because of the relatively low uptake of the game-type, these interfaces do not

support Horde chess. The consequence of this is that, to be able to effectively use the

chess engine, a graphical user interface must be designed. During the development of

the engine the interface is not hugely important and a simple console GUI was temporar-

ily used. This allowed for the development of the underlying engine with the intention

of implementing a more graphical system after the completion of the engine.

When designing the final GUI, there are two options that were possible: creating a

standalone application that communicates with the engine or building a graphical user

interface directly on top of the engine. Of these options, the most elegant approach

would be to build a separate application that uses the Chess Engine Communication

Protocol to communicate with the engine; however, the complexity of implementing

this would not be a great use of time considering that it is not a requirement for the

project. A more time-manageable approach is to use a C++/CLR Windows Form with an

improvised game-loop, which can be seen in Figure 8. This does not produce a perfect

solution to the problem because the interface will remain unresponsive throughout the

computer player’s thinking time and this approach does seem to add some overhead due

to the mix of managed and unmanaged code.

Reg: 4692306 22

Page 23: Development of a Chess Engine

CMPC3P2Y

Figure 8: Final Graphical User Interface

5. Evaluating Chess Engine Performace

The changes that were made to the overall design of the engine, due to the incompatibil-

ity with the intended GUI (WinBoard), introduced a considerable amount of overhead.

Table 2 states the average move execution times for each depth over a period of twenty

games with a late build of the engine and clearly shows that playing at a depth of 5 is

unacceptable with average move times of over a minute. A system must be implemented

to reduce the amount of work performed in each move.

5.1. Build Optimisation

One method of optimisation is to change the build settings available in Visual Studio

2013 to suit the needs of the program. Visual Studio provides certain automatic optimi-

sations which can be set to improve C++ code efficiency, the final build settings can be

seen in Figure 9. As well as these settings, the options allow the debug information to

Reg: 4692306 23

Page 24: Development of a Chess Engine

CMPC3P2Y

Table 2: Move Execution Times - Late Build (Running on AMD FX-4100 3.6GHz - Single Thread)

Depth White Average (ms) Black Average (ms) Move Average (s)

1 15.1 12.6 0.0139

2 491.7 287.9 0.389

3 6397.9 4635.4 5.56

4 22456 19744.1 21.1

5 64326.8 55987.5 60.2

be taken out completely for release builds which should improve the speed of execution.

These changes improved the times, but only slightly and certainly not to an acceptable

standard.

5.2. Code Optimisations

Re-factoring code is an important part of programming to ensure the maximum effi-

ciency. After parsing the code for potential changes, several instances where code can

be improved become apparent. The use of the Visual Studio Performance Analysis fea-

ture helped identify the individual function calls that are either called the most or the

took the most processing time. From this data, changes were made to simple functions

that were called frequently; for example isEnemyPiece was condensed from 4 sepa-

rate lines of execution to a simple logical function taking advantage of the parity of the

pieces. Changes were also made to larger functions called slightly less often by adapt-

ing the data types used. Again these changes yielded insignificant results and it is clear

that a different approach is necessary.

5.3. Transposition Table

A common way of reducing the load on a search function in position based games is

the use of a transposition table which stores a hash of all previously searched positions

against the value they are worth. This means that any unique position that can be ac-

cessed via more than one combination of moves need only be evaluated once.

Reg: 4692306 24

Page 25: Development of a Chess Engine

CMPC3P2Y

Figure 9: Visual Studio 2013 Ultimate Build Settings

Implementing this in the engine is a relatively simple task by utilising a function

that hashes the 2D board array, the current depth and the current turn. It is impor-

tant to hash the depth and turn data also as the engine would simply perform the

best move sequence after searching once and not search to the correct depth and with

the search wrong score weighting. This integer hash is then used as the key of an

unordered_map<int,int> object and the value is sourced from the best score

at this depth. With the transposition table filling up as moves are searched, positions

that have already been evaluated will begin to rise; for example, when a combination

of moves are performed in a different order they will result in the same final position.

Before searching for the next depth, the engine will check the transposition table for a

value and if found, the branch does not need to be searched again.

The results after the implementation of the transposition table, which can be seen in

Table 3, show a significant decrease in execution time. At a depth of 4, there was a

decrease in the average move time by 20 seconds from 21.1s to 1.19s. At a depth of

Reg: 4692306 25

Page 26: Development of a Chess Engine

CMPC3P2Y

Table 3: Move Execution Times - Final Build (Running on AMD FX-4100 3.6GHz - Single Thread)

Depth White Average (ms) Black Average (ms) Move Average (s)

1 1.1 0.4 0.00075

2 25.7 9.8 0.0178

3 157.2 68.8 0.0802

4 1570.5 800.8 1.19

5 14840.3 7597.4 11.22

5, the average move reduced by over 81% from 60.2 seconds to 11.22 seconds. These

results bring the execution time of the engine down to an acceptable level at the desired

depth of 5.

6. Evaluating Horde Chess Equality

The major issue with Horde chess is the bias between the two sides, with the majority of

games favouring white; a competent player using white would have to make a consid-

erable error to lose with the current standard board set-up. The purpose of building the

engine is to analyse slight variations of the board in order to determine a better balanced

piece arrangement.

A series of tests are conducted, initially on the original board set-up to demonstrate

the bias between the two teams and then moving onto several different adaptations. Each

test consists of 50 matches with depths up to 3 with the result of every match at each

depth being recorded. A limit is set on the depth due to the time constrains of running

such large amount of matches, with 200 matches being played per board set-up.

6.1. Original Board Set-Up

The results of the original board set-up, as shown in Table 4, clearly show a bias towards

white as the intelligence of the engine increases. At depth 0, the black side has a clear

advantage which could likely be attributed to the quantity advantage it holds over white.

Reg: 4692306 26

Page 27: Development of a Chess Engine

CMPC3P2Y

The would happen because when the computer is only considering it’s own move, the

majority of captures will be simple exchanges. Because of these results, this depth will

not be considered in future tests. This advantage is negated once the depth is raised to

1, with white winning 98% of matches. The win percentage for white does decrease

slowly as the depth is raised but the black win percentage does not rise at the same rate,

with the best part of the white wins converting into stalemates caused by black having

no valid moves. From viewing the final board states of each of these games, white were

in the most prosperous position by leaving black with no more than 4 blocked pawns.

Table 4: Original Board Analysis Results

Depth White Black Stalemate White Win % Black Win %

0 0 50 0 0% 100%

1 49 1 0 98% 2%

2 43 2 5 86% 4%

3 40 3 7 80% 6%

6.2. Board Adaptations

With the tests that prove the existence of the bias towards white complete, some board

adaptations can be tested. There are several ways to adapt the board in the attempt

of giving black a better chance of winning. Using the strategic knowledge that has

been gathered and noted earlier in the report, several promising board adaptations are

analysed.

6.2.1. No Extra Pawns

Ideally, a balance can be achieved without adding any extra pieces to black. The first

adaptation, as seen in Figure 10, is based on the premise that black needs to protect the

columns on either side of the board to help prevent a white rook or queen developing

down the edges and positioning behind the lowest ranked pawn.

Reg: 4692306 27

Page 28: Development of a Chess Engine

CMPC3P2Y

Figure 10: Alternative board arrangement with no extra pawns

The results, as shown in Table 5, clearly show that this adaptation is worse than the

original in terms of game balance. At every depth the white win percentage increases

and the black win percentage decreases. This suggests that, while protecting the outer

columns is important to prevent the rooks advancing, the center of the board is of greater

significance than previously thought and the two pawns at D4 and E4 should remain.

Table 5: Alternative Board Arrangement Analysis Results - No Extra Pawns

Depth White Black Stalemate White Win % Black Win %

1 50 0 0 100% 0%

2 44 2 4 88% 4%

3 45 1 4 90% 2%

6.2.2. Two Extra Pawns

From the previous tests, it is evident that simply moving the arrangement of pawns

available will not be enough to affect the balance in the way required. One of the key

weaknesses of the black side is the lowest rank of pawns. In the original set-up, there is

a two tile gap at D8 and E8 where the pawns have been moved to D4 and E4. By placing

Reg: 4692306 28

Page 29: Development of a Chess Engine

CMPC3P2Y

two extra pawns, as seen in Figure 11, in these two tiles the game should become less

biased towards white and a higher black win rate should emerge.

Figure 11: Alternative board arrangement with two extra pawns

Table 6 shows that at a depth of 1, there is an increase in black wins from 2% to 6%

and a decrease of 8% from 49 to 45 wins. At a depth of 2 the black wins increased

from 4% to 10%, while the white wins again decreased from 43 wins to 41. The largest

change can be seen at a depth of 3, with black’s win percentage rising by 10% to 16%,

white’s win percentage falling from 90% to 70% and Whilst this is a positive start, there

is still a considerable bias towards white and further changes to the board seem to be

necessary.

Table 6: Board Alternative Analysis Results - Two Extra Pawns

Depth White Black Stalemate White Win % Black Win %

1 45 3 2 90% 6%

2 41 5 4 82% 10%

3 35 8 7 70% 16%

Reg: 4692306 29

Page 30: Development of a Chess Engine

CMPC3P2Y

6.2.3. White Pawn Handicap

An alternative approach to changing the balance is to handicap the white side by re-

moving a pawn, Chess-Video et al. (2010). As seen in Figure 12, while keeping the

previous change that slightly increased the win percentage of the black team, the white

pawn originally positioned at F2 has been removed, exposing the king. This is the only

viable pawn to remove as it does not increase the initial mobility of white; the pawn had

2 moves initially, the kings mobility increases by 1.

Figure 12: Alternative board arrangement with a white pawn handicap

The final arrangement that was tested shows the most convincing results, which can

be seen in Table 7. At depth 1, there is a slight decrease in the amount of black wins

from 3 wins to 2, while the white wins increase from 45 to 46. This trend does not

continue as the depth increases however, with white wins dropping by 4% from 41 to 39

at a depth of 2. The black wins, at a depth of 2, increase by 2% from 5 wins to 6. It is at

a depth of 3 where the most persuasive evidence materialises. The white win percentage

hits the lowest value during testing at 70% while the black wins peak at 20%.

Reg: 4692306 30

Page 31: Development of a Chess Engine

CMPC3P2Y

Table 7: Alternative Board Arrangement Analysis Results - White Pawn Handicap

Depth White Black Stalemate White Win % Black Win %

1 46 2 2 92% 4%

2 39 6 5 78% 12%

3 35 10 5 70% 20%

7. Conclusions

Horde chess proved to be a proved to be a proficient choice as it not only offered an

interesting concept that has not been greatly researched, but it also granted the oppor-

tunity to analyse a clear bias towards the white team. Using C++ as the language to

implement the chess engine, instead of other common languages Java and C#, was the

correct decision due to the need for efficiency. From the implementation of an array

based board it seems that it would be an interesting study to review the performance

differences between piece centric and square centric board representations by imple-

menting bit-boards into the engine. Due to the experience that was gained from devel-

oping the engine, it would be a more comfortable task to perform again without the need

for the readability benefits. The algorithms that were used as a template for the move

searching function were adapted slightly over the course of the development and in turn

there is likely some further optimisation that could be performed to further improve the

engines efficiency. The evaluation function, based on Shannon’s original evaluation,

demonstrated competent results with a small amount of processing time. The GUI that

was implemented caused an unexpected amount of overhead because of the use of both

unmanaged and managed code. An alternative solution would be to create a separate

application that communicates with the engine running in it’s own process. This would

likely further decrease the times of each move but unfortunately this was not feasible

in the time available. One of the advantages to using the C++/CLR Forms API was the

ease of adding controls, which enabled invisible buttons to be placed in a grid for the

human players moves.

The results of the analysis performed have shown that it is possible to enhance the

Reg: 4692306 31

Page 32: Development of a Chess Engine

CMPC3P2Y

balance of the chess variant, Horde chess. However, the results are not clear enough

to provide a definitive way to create a close to 50:50 bias and more testing of different

board adaptations will need to be performed to achieve this. The best arrangement in

terms of balancing was a combination of filling the void spaces at the back of the pack

with two extra pawns and giving the white team a pawn handicap by removing the piece

at F2. This yielded the results shown in Table 7 that state a 70% win rate for white, a

decrease from 80% for the original board; the black team increased from 6% to 20%.

Figure 13: Close-up to show moves and times at a depth of 5

With regards to efficiency, there were some unexpected barriers that needed to be

acted upon. The original plan was to integrate the engine with the popular GUI Win-

Board to ensure that the engine can run to it’s full potential. This would not work due to

the incompatibility with the variant selected and a GUI would need to be built to work

with the engine. The GUI that was created added a significant amount of overhead and

Reg: 4692306 32

Page 33: Development of a Chess Engine

CMPC3P2Y

increased the execution times of moves due to the mixing on managed and unmanaged

code. A transposition table was implemented to reduce the amount of duplicate eval-

uations and the results can be seen in Table 3. These changes allowed the engine to

perform at a good standard, searching 5 ply moves in an average of 11.22 seconds, as

can be seen in Figure 13.

Reg: 4692306 33

Page 34: Development of a Chess Engine

CMPC3P2Y

References

Beal, D. F. (1980). An analysis of minimax. Advances in computer chess, 2:103–109.

Bourzutschky, M. S., Tamplin, J. A., and Haworth, G. M. (2005). Chess endgames:

6-man data and strategy. Theoretical Computer Science, 349(2):140–157.

Chess-Video, B., Stewart, C. V.-N., and Gulamali, F. (2010). Chess variant.

Edwards, D. J. and Hart, T. (1961). The alpha-beta heuristic.

Fulda, J. S. (1985). Alpha beta pruning.

Hyatt, R. M. (1999). Chess board representations. Online Technical Papers, 49.

Knuth, D. E. and Moore, R. W. (1976). An analysis of alpha-beta pruning. Artificial

intelligence, 6(4):293–326.

Rasmussen, D. (2004). Parallel chess searching and bitboards. PhD thesis, Technical

University of Denmark, DTU, DK-2800 Kgs. Lyngby, Denmark.

Shannon, C. E. (1950). Xxii. programming a computer for playing chess. The

London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science,

41(314):256–275.

Stroustrup, B. (2007). Evolving a language in and for the real world: C++ 1991-2006.

In Proceedings of the third ACM SIGPLAN conference on History of programming

languages, pages 4–1. ACM.

Reg: 4692306 34

Page 35: Development of a Chess Engine

CMPC3P2Y

A. Minimax Algorithm Pseudocode

function minimax(move, depth, isMaximisingPlayer)

if depth = 0 or there are no more possible moves

return evaluation(board)

if isMaximisingPlayer

bestValue := -INFINITY

for each possibleMove in allValidMoves

tempValue := minimax(possibleMove, depth - 1, false)

if tempValue > bestValue

bestValue := tempValue

return bestValue

else

bestValue := +INFINITY

for each possibleMove in allValidMoves

tempValue := minimax(possibleMove, depth - 1, true)

if tempValue < bestValue

bestValue := tempValue

return bestValue

Reg: 4692306 35

Page 36: Development of a Chess Engine

CMPC3P2Y

B. Alpha-Beta Pruning Algorithm Pseudocode

function minimaxAB(move, depth, alpha, beta, isMaximisingPlayer)

if depth = 0 or there are no more possible moves

return evaluation(board)

if isMaximisingPlayer

value := -INFINITY

for each possibleMove in allValidMoves

value := max(value, minimaxAB(move, depth - 1,

alpha, beta, false))

if value > alpha

alpha = value

if beta <= alpha

break

return value

else

value := INFINITY

for each possibleMove in allValidMoves

value := min(value, minimaxAB(move, depth - 1,

alpha, beta, true))

if value < beta

beta = value

if beta <= alpha

break

return value

Reg: 4692306 36

Page 37: Development of a Chess Engine

CMPC3P2Y

C. Claude Shannon’s Evaluation Function

f(p) = 200(K-K’)

+ 9(Q-Q’)

+ 5(R-R’)

+ 3(B-B’ + N-N’)

+ 1(P-P’)

- 0.5(D-D’ + S-S’ + I-I’)

+ 0.1(M-M’) + ...

KQRBNP = number of kings, queens, rooks, bishops, knights and pawns

D,S,I = doubled, blocked and isolated pawns

M = Mobility (the number of legal moves)

Reg: 4692306 37