|
Winglet forum
A chess program that beats most human players
|
Writing a chess program in 99 stepsA step-by-step guide for writing a bitboard chess engine,
winglet |
|||||
01 IntroductionThis is a systematic guide to write a chess engine (connected to the Winboard chess interface). The targeted audience are chess programming enthusiasts. You will only need a PC with Windows installed, because everything else is free. I do assume however that you know how to navigate in Windows, install programs, how to play chess, and how to program (but not necessarily in C++). The program that will be developed is called winglet (because it is loosely derived from wing, my private engine). Winglet is free and open source. You can redistribute it and/or modify it under the terms of the GNU General Public License. All code is going to be built from scratch. You will see code snippets that list complete (but simple) functions. Followed later by code snippets to improve, or enhance, existing functions. In the left side of this page you will see an overview of all code snippets. The functionality of the code will grow 'organically', allowing you to follow my thinking, coding and testing (and hopefully without the bugs). In 99 steps? well, it's going to be slightly more than that, I just thought 99 would be a nice goal. The reason why this is a step-by-step guide is to allow you to go through, and think through, all phases and concepts involved when writing a chess engine from scratch, in a more or less natural and logical order. You will be able to build, run, test and experiment with the program as its functionality increases. Alternatively, you may just want to copy & paste the snippets, ending up with a complete chess program, and skip reading the explanations. That's fine, but you will not learn anything from that. At the other end of the creativity scale, you can treat this as a rough guideline, program your own engine, use some of the idea's, copy code parts, or use nothing at all because you can do it better! Another reason is that, for beginning chess programmers, it's not easy to decide where to start. There is a lot of information on the internet on specific chess programming topics, but not a lot of guidance on where and how to start, what comes next, when to start worrying about the interface (at the end!). As Robert Hyatt has put it (and I fully agree): the evaluation and search functions are the heart & soul of a chess engine, it is mainly from these two components that an engine gets its 'personality', and mainly these two components make one engine stronger than another. Some components of the engine may not be very engine specific, or they may not affect playing strength at all. For instance, you will find fast and similarly looking bitboard move generators in many programs. Winglet will provide you with a basis for experimenting and improving evaluation, search and move sorting in particular. They are the three most underdeveloped functions in winglet, and this is done intentionally, to invite you to improve and develop an engine with its own personality / strength, without having to go through the hassle of writing the backbone from scratch. Once you start adding your own thoughts into the evaluation and search code, it will become your engine, with its own 'personality', and then you should give it it's own name too! Some of you will find my programming style odd, or just plain wrong. I am OK with that. I like to keep things simple, understandable, readable, straightforward. So that ten years from now you will still be able to read and understand the code. If you are looking for compact or advanced C++ programming techniques, you will not find them here (unless required for speed, and then I would just copy whatever is available from the internet, after testing). This engine is going to be sufficiently fast, but relatively simple, providing you a backbone that you can expand upon, change and tweak. The implementation of bitboards should be comprehensible to all. This website will get you to the point that you have written a basic bitboard
chess engine, playing reasonable chess, as a console program, or using the Winboard interface. I learned chess programming from reading internet articles and open source code. Mostly internet articles from Robert Hyatt (author of Crafty) and Bruce Moreland, and of course studying the code of other open source programs. Others invented everything I write in this guide, not me, and in some cases I even do not know who to give credit. Thanks to others, who made their thoughts, research and inventions available through publications, discussion forums, websites, and open source code, I was able to start programming my private chess engine, wing. Check out the list of references if you want to read the same stuff I did.
02 Anatomy of a chess programChess programs determine the best move by traversing down a tree of possible moves and opponent moves, up to a certain depth, and then evaluate the resulting positions at the tree tips (leafs, at the end of the search branches) to see which move will lead to the best result, assuming that the opponent will also play the best moves. Note that this tree of variations is usually shown 'upside-down', i.e. with the root at the top and branches at the bottom:
The chess search tree is very wide (on average there are 35 legal moves for a chess position), and very deep (the average chess game is 40 moves, or 80 half moves or plies). Not all possible variations can be evaluated (note that 3580 is approximately 10123 ; by comparison, the estimated number of atoms in the universe is 1080). The search function is implemented as a recursive function (a function that makes a call to itself); at every chess position (node), the move generator returns a list of moves to make (and unmake, when the search traverses back up to the root of the tree to pass the result of the search to the calling function). The evaluation of chess positions is done by considering many static aspects, starting of course with the material balance, and considering pawn structure, king safety, piece mobility, and many other aspects of the position. The score is usually expressed in centipawns (a pawn equals 100). Speed is important, and there are many techniques to improve the search speed of a chess program (including using bitboards and hash tables). Some chess engines will display their search speed in knods/s (1000 nodes per second). Another important area of optimization is the search algorithm. The main objective here is to minimize the number of moves to search, by skipping moves that are proven to be, or seem to be, 'unattractive'. Techniques to improve and speed up the search include the alpha-beta algorithm, pvs (principal variation search), move ordering, null-move, search extensions, and aspiration windows. There is of course an intrinsic danger in omitting moves that seem unattractive (at small search depths), because some of them could lead to a decisive advantage as the game progresses (at greater search depths). Alpha-beta, pvs and move ordering increase the search speed without affecting accuracy. Other techniques can severely deteriorate accuracy, if not implemented correctly, or when using too aggressive pruning parameters. By far the best investment you can make to produce a strong program is to improve the evaluation function. Speed is still important in the evaluation function. However, if you can improve the evaluation function, at the cost of adding more code lines and hence making your program somewhat slower, go for it! Same is valid for the search algorithm, adding more code lines will make the code slower, but can make the search faster (by visiting less nodes). As a rule of thumb, the strongest chess programs have fast move generators, use data structures that allow them to implement fast makemove and unmakemove algorithms, they search a relatively small number of moves only (using aggressive forward pruning rules, allowing them to search deeper), and have extensive evaluation functions that capture a significant amount of chess knowledge. 03 ChoicesWinglet is written on a platform running Windows 7 Home Premium, SP1 (64-bit), and coding is done with Microsoft Visual C++ 2010 Express, version 4. What if your system is different?If your operating system or software development environment (SDE) is different, that does not automatically mean that you cannot follow this guide. It only means that some steps or implementations might be somewhat different, depending on how your particular system is set up. I suppose you can also follow this guide in case you want to write a UCI engine under Linux (skipping the parts for Winboard and coding the UCI parts yourself). Some coding might be machine and/or OS dependent, I will gladly leave that as a complimentary challenge for you to figure out. I choose to focus on the chess programming part. 04 PreparationsSetting up Microsoft Visual C++ 2010 ExpressDownload and install Microsoft Visual C++ 2010 Express (it is free, but you will need to register to use it). It can be found here, or use a search engine to locate it. There might be additional Service Packs available for installation, or Windows updates related to Visual Studio. Some are required for Microsoft Visual C++ 2010 Express to function properly. After installation of VC++, check your Windows Updater – it will tell you which other updates and/or service packs you might need. Setting up WinboardNote that you do not need Winboard right away, winglet will initially be developed as a console program, with user input from the keyboard. Winboard support and details on setting up Winboard is discussed in section 21. You can download and install the latest Winboard version, from here (version 4.5.2) or use a search engine to locate it.
05 First steps with Visual Studio C++Start Visual studio C++, select New Project..., select
Win32, select
Win32 Console Application…, Now, navigate through the Win32 Application Wizard, select
Win32
console application, make sure to uncheck
precompiled header. Note that, in Visual studio C++, you have complete control over the layout of the working space and position of windows. You might want to spend some time to get familiar with the interface, my working space usually looks like this: Check if you can copy this into your code:
Build the executabe (hit F7). You are ready to go if you've gotten this far. I am not going to explain a lot more than this on working with Visual C++. That is not the intention of this guide; Again, I choose to focus on the chess programming part. My C++ header philosophyC++ programs are usually split up into multiple smaller source code files (suffix .cpp). Splitting up chunks of code into separate files allows programmers to separate certain elements of a program's source code into manageable and reusable files. C++ header files (suffix .h) normally contain declarations of structures, functions, variables, and other identifiers. Identifiers that are declared in a header file can be included in other source files. In my programs, the order of header file inclusion is important
(which is considered bad coding practice). The winglet C++ header files are set
up to contain the following definitions (and you always should #include
them in this particular order to prevent compilation problems): Targeting for 64-Bit PlatformsVisual Studio C++ Express does not come with 64-bit compilers. If you want to build your executable for a 64-bit platform, then I suggest searching the internet for "how to configure Visual C++ Projects to Target 64-Bit Platforms". This will lead you to Microsoft's site with more information. You will have to download and install Microsoft Windows SDK and .NET Framework 4 (which is also free software), define your 64-bit platform in Visual C++, and select Windows7.1SDK as Platform Toolset. In case Microsoft Windows SDK cannot install the X64 or IA64 compilers, then you might have to uninstall Visual Studio 2010 Service Pack 1, and reinstall (not repair) Microsoft Windows SDK. See this link for more info on this known bug. If you're not sure how many CPU's your system has, then you can use following program to find out (this will work in Windows-based systems only):
This will probably get you the right number of processors, but I noticed that my machine thinks it's an Architecture: INTEL - x86 if I compile it for 32-bit, and it thinks it's an Architecture: AMD64 - x64 (AMD or Intel) if I compile it for 64-bit (!)... inscrutable Microsoft logic. |
||||||
|
|
||||||
|
last update: Friday 09 September 2011 |
|||||