Game Development (iii)--WIN32 black and White Chess (a)--the design of chess logic

Source: Internet
Author: User

Today, taking Othello as an example, I began to design a small game of Win32,

We're going to introduce 3 parts here.

1, chess board, the reality of chess

2, player, AI Reality (and listen to tell)

3, the reality of the game screen (and listen to the Tell)


The first of these is the main logic of Othello games:

1, the chess board, and the chess piece on the Board storage form. The bitmap is used here.

2, whether can lazi judgment (Othello is only you lazi position, in the vertical and horizontal oblique eight direction in any direction, can eat each other's son, you can fall in the position, eight directions are not able to eat each other's position can not be under), as well as eating the logic of the child (eating the logic is also eight directions, The opponent's pieces, which are clamped between the two pieces, can be eaten and flipped to their own pieces. In order to make the code brief, a function pointer is used (the change of coordinates in different directions is not the same logic).

3, a party under a sub-judgment of the exchange hand (black and white chess in the existence of possible, one side under a son, and eat each other's son, then the other side can not be under, there is no place can make the other side can eat their own pieces, so black and white chess is not always a one-step, it may exist on one side

4, record the player every step of chess step, make can undo (only regret the player, not regret AI).

5, the game whether the end of the judgment (because there is no child can be under the situation, there may be no children can be under, that is, one side will eat all the other party, so black and white chess is not necessarily under the board to distinguish the outcome).


The second part is mainly to write AI:

Black and white chess ai is actually quite complex, there is a special study of black and white chess AI algorithm article, here is only a brief introduction, but also involves a few concepts: stabilizer, line power, etc., specific in the second part of the introduction.


The third part is the display of the game screen, involving Windows message mechanism, mouse events, keyboard events, menu events, timer events, as well as simple graphics, text painting, involving brushes, brush fill, drawing layer hdc, draw line, circle, display text, double buffered bitmap copy.

Before reading the third part, readers can first read the book "Windows Programming" to play a foundation.

You can also read the blog post, then the related graphics API, message mechanism and other Windows programming involved in the points brought back to the book to learn more.


PS: Only see 1, 3 parts, also can achieve a black and white chess, but no AI, you can only people with people under


Black and white chess game in the design of a few points to note:

1, the Convention, the first is to define the coordinates of the board, defined as the upper left corner of the lattice is (0,0), right x positive direction, downward for the y positive direction, the black and white chess board is a 8*8 chessboard, so the definition of two constants is indicated:

const int reversi_max_row = 8;const int reversi_max_column = 8;

2, the Chess board on the type of three kinds: sunspots, white, blank No child, enumeration means

Enum Enumreversipiecestype{enum_reversipieces_null = 0x00,enum_reversipieces_black = 0x01,enum_reversipieces_white = 0x02,};

These three cases, in fact, with 2-bit 2 binary can be expressed, a line of 8 positions is 16-bit 2, is a word is enough, so:

3, the representation of the chessboard, bitmap

Tarray1<word, reversi_max_row> M_map;

The bitmap is 8 rows, each line is a word, and this TArray1 is directly used by the previously implemented one-dimensional array template

4, the design of a position on the board, because here involves the position (that is, coordinates) of the eight direction of the movement of logic, so the coordinates of the position is abstracted out, to achieve the coordinates of the top and bottom of the coordinate changes in the four direction, and then redefine it as a function pointer, so that the back in the coordinate changes, do not Case eight, you can use directions as parameters.

typedef void (Reversipoint::* Reversipointforward) ();

5, a piece of a party, in a coordinate position, to a certain direction, whether it can eat the other's pieces of the judgment

BOOL Reversicheck (enumreversipiecestype type, char row_y, Char column_x, Reversipointforward forward);
Whether you can eat the pseudo-code of the Child:

Define a coordinate object point, the initial value is the current dot row_y, Column_x records the number of searches in that direction search, the initial value is 0point to forward direction to move the number of searches Search++while (point is a valid coordinate, You can't move out of the board. {The type of pawn at the current position of the point (which is already the position after the forward has been moved once, not row_y, column_x) if (the current position has a pawn) {if (the pawn type at the current position equals the passed-in parameter, Type is the kind of pawn to be next) {if (search more than 1 times) {indicates that the same color found in the same piece and the current piece coordinates the difference more than 1,point at least 2 times, the two children sandwiched between the different colors of the pieces match the flip rule, return true}else{ Description find the same color pieces and the current pieces, two children are next to each other in the direction of the two children can not flip the rules, return false}}else{description found is a different color of the pieces, continue to the next position to search the point to forward direction of mobile searches ++}}else{has been found vacant and not found, the direction is not the same color pieces, cannot flip}} out of the checkerboard range did not find the same color pieces, the direction is not the same color pieces, cannot be flipped

6, a piece of a party, in a coordinate position, to a certain direction, eat each other's pieces

void Doreversi (enumreversipiecestype type, char row_y, Char column_x, Reversipointforward forward);

Pseudo-code implementation

Define a coordinate object point, the initial value is the current dot row_y, the column_xpoint moves to the forward direction while (point is a valid coordinate and cannot be moved out of the board) { The type of pawn that takes the current position of point (which is already the position after the forward has been moved once, not row_y, column_x) if (the pawn type at the current position is not equal to the incoming parameter type,type is the pawn type below) { Flip the position of the pawn type to type one side of the piece point to move in the direction of forward because of the reversicheck before flipping the judgment that this direction is definitely in line with the flip rule, there are children to eat so here no longer determine the current position of the pawn type is empty}}

With the above two basic functions

7, determine whether a location can be Lazi

BOOL Reversicheck (enumreversipiecestype type, char row_y, char column_x);

is to call the Reversicheck above, and then forward to pass in different directions.

8, judge whether a party can Lazi

BOOL CanPlay (enumreversipiecestype type);
That is, you can traverse each position of the chessboard, and any position may be lazi, then the party can Lazi

9. Eat a child after falling

void Doreversi (enumreversipiecestype type, char row_y, char column_x);
is to call the Doreversi above, and then forward to pass in different directions.

10, the steps of chess, in order to be able to undo

typedef struct REVERSISTEP{REVERSIBITBOARD M_lastmap; Enumreversipiecestype M_currtype; reversistep& operator= (const reversistep& temp) {M_currtype = Temp.m_currtype;m_lastmap = Temp.m_LastMap; return *this;}} Reversistep;

Here directly to record the Lazi before the board state, and the current step is who the son can be, Undo is the time to restore the board state to the person before Lazi state, and then still by the player re-lazi

Lazi time, fill in the Reversistep, save the list, Undo, from the end of the chain to exit a node, and the board state to restore the state of the tail node, that is, the realization of the Undo

A total of 60 steps to full, here with a pool of objects, a one-time application of 60 steps required memory, so as to avoid frequent lazi undo process, frequent application of memory

11, finally, to determine whether the game is the logic of the end, that both sides have no child to play, then the game is over


Let's give it a game.


The first part of the code is first posted below

ReversiCommon.h

#ifndef _reversicommon_h_#define _reversicommon_h_//Checkerboard Size const int reversi_max_row = 8;const int reversi_max_column = 8; Enum Enumreversipiecestype{enum_reversipieces_null = 0x00,enum_reversipieces_black = 0x01,enum_reversipieces_white = 0x02,};enum enumreversiresult{enum_reversi_playing = 0,enum_reversi_draw,enum_reversi_win_black,enum_reversi_win_ White,}; #endif

ReversiPoint.h

 #ifndef _ Reversipoint_h_#define _reversipoint_h_#include "ReversiCommon.h" typedef struct REVERSIPOINT{CHAR M_row_y;char m_ column_x; reversipoint& operator= (const reversipoint& temp) {m_row_y = temp.m_row_y;m_column_x = Temp.m_column_x;return * this;} BOOL operator!= (const reversipoint& temp) {if (m_row_y = = temp.m_row_y &&m_column_x = = temp.m_column_x) { return false;} Else{return true;}} BOOL IsValid () {if (0 <= m_row_y &&0 <= m_column_x &&m_row_y < Reversi_max_row &&m_column _x < Reversi_max_column) {return true;} Else{return false;}} void UL () {m_row_y--;m_column_x--;} void U () {m_row_y--;} void UR () {m_row_y--;m_column_x++;} void L () {m_column_x--;} void R () {m_column_x++;} void DL () {m_row_y++;m_column_x--;} void D () {m_row_y++;} void DR () {m_row_y++;m_column_x++;}} reversipoint;typedef void (reversipoint::* Reversipointforward) (); #endif 

ReversiBitBoard.h

#ifndef _reversibitboard_h_#define _reversibitboard_h_#include <Windows.h> #include "TArray.h" #include " ReversiCommon.h "Class Reversibitboard{public:reversibitboard (); ~reversibitboard (); reversibitboard& operator= (const reversibitboard& temp); void setpieces (Enumreversipiecestype type, char row_y , Char column_x); Enumreversipiecestype getpieces (Char row_y, char column_x); BYTE Getblackcount (); BYTE getwhitecount ();p Rivate:tarray1<word, reversi_max_row> m_map; BYTE M_blackcount; BYTE M_whitecount;}; #endif

ReversiBitBoard.cpp

#include "ReversiBitBoard.h" Reversibitboard::reversibitboard () {for (int i = 0; i < Reversi_max_row; i++) {m_map[i] = 0; }m_blackcount = 0;m_whitecount = 0;} Reversibitboard::~reversibitboard () {}reversibitboard& reversibitboard::operator= (const ReversiBitBoard& Temp) {M_map = Temp.m_map;m_blackcount = Temp.m_blackcount;m_whitecount = Temp.m_whitecount;return *this;} void Reversibitboard::setpieces (enumreversipiecestype type, char row_y, char column_x) {WORD Oldtype = (m_map[row_y] & (0x0003 << (column_x * 2)) >> (column_x * 2); if (enum_reversipieces_black = = Oldtype) {m_blackcount--;} else if (Enum_reversipieces_white = = Oldtype) {m_whitecount--;} M_map[row_y] = m_map[row_y] & (~ (0x0003 << (column_x * 2))); m_map[row_y] = m_map[row_y] | (Type << (column_x * 2)); if (enum_reversipieces_black = = type) {m_blackcount++;} else if (enum_reversipieces_white = = type) {m_whitecount++;}} Enumreversipiecestype reversibitboard::getpieces (Char row_y, char column_x) {WORD VAlue = m_map[row_y] & (0x0003 << (column_x * 2)); value = value >> (column_x * 2); Enumreversipiecestype type = static_cast<enumreversipiecestype> (value); return type;} BYTE Reversibitboard::getblackcount () {return m_blackcount;} BYTE Reversibitboard::getwhitecount () {return m_whitecount;}

Reversi.h

#ifndef _reversi_#define _reversi_#include "TBDLinkList.h" #include "TObjectPool.h" #include "ReversiCommon.h" # Include "ReversiBitBoard.h" #include "ReversiPoint.h" typedef struct REVERSISTEP{REVERSIBITBOARD m_lastmap; Enumreversipiecestype M_currtype; reversistep& operator= (const reversistep& temp) {M_currtype = Temp.m_currtype;m_lastmap = Temp.m_LastMap; return *this;}} Reversistep;class Reversi{public:reversi (); ~reversi (); void Init (); bool CanPlay (enumreversipiecestype type); bool CanPlay (enumreversipiecestype type, char row_y, char column_x), void Doreversi (enumreversipiecestype type, char row_y, char column_x); bool Reversicheck (enumreversipiecestype type, char row_y, char column_x); void Addreversistep (); void Cancel (); void Swapplayer (); Enumreversiresult Isgameover (); Enumreversipiecestype Getcurrtype (); reversibitboard& getmap ();p rivate:void doreversi (enumreversipiecestype type, char row_y, Char column_x, Reversipointforward forward); bool Reversicheck (enumreversipiecestype type, chaR Row_y, Char Column_x, Reversipointforward forward); Enumreversipiecestype M_currtype; Reversibitboard M_reversimap; Tbdlinklist<reversistep> m_reversisteplist; Tobjectpool<tbdlinker<reversistep>> M_reversisteppool;}; #endif

Reversi.cpp

#include "Reversi.h" Reversi::reversi () {}reversi::~reversi () {}void reversi::init () {m_currtype = Enum_reversipieces_ black;//rules Black First m_reversisteplist.init (Enum_disablelock); M_reversisteppool.init (Reversi_max_row * REVERSI_MAX_COLUMN , 0,enum_disablelock_objpool,enum_disableassign_objpool); for (int i = 0; i < Reversi_max_row; i++) {for (int j = 0; J &lt ; Reversi_max_column; J + +) {m_reversimap.setpieces (Enum_reversipieces_null, I, j);}} M_reversimap.setpieces (Enum_reversipieces_black, 3, 3); M_reversimap.setpieces (Enum_reversipieces_white, 3, 4); m_ Reversimap.setpieces (Enum_reversipieces_white, 4, 3); M_reversimap.setpieces (Enum_reversipieces_black, 4, 4);} BOOL Reversi::canplay (Enumreversipiecestype type) {for (int i = 0; i < Reversi_max_row; i++) {for (int j = 0; J < REVE Rsi_max_column; J + +) {if (CanPlay (type, I, j)) {return true;}}} return false;} BOOL Reversi::canplay (enumreversipiecestype type, char row_y, char column_x) {if (Enum_reversipieces_null = = M_ Reversimap.getpieces (row_y, column_x)) {if (Reversicheck (Type, row_y, column_x)) {return true;}} return false;} BOOL Reversi::reversicheck (enumreversipiecestype type, char row_y, char column_x) {if (Reversicheck (type, row_y, Column_ X, &reversipoint::ul) | | Reversicheck (Type, row_y, column_x, &reversipoint::u) | | Reversicheck (Type, row_y, column_x, &reversipoint::ur) | | Reversicheck (Type, row_y, column_x, &reversipoint::l) | | Reversicheck (Type, row_y, column_x, &reversipoint::r) | | Reversicheck (Type, row_y, column_x, &reversipoint::D l) | | Reversicheck (Type, row_y, column_x, &reversipoint::D) | | Reversicheck (Type, row_y, column_x, &reversipoint::D R)) {return true;} return false;} BOOL Reversi::reversicheck (enumreversipiecestype type, char row_y, Char column_x, Reversipointforward forward) { Reversipoint point = {row_y, column_x}; Enumreversipiecestype Currtype;int search = 0; (point.*forward) ();//Search for Search++;while (point) in a direction. IsValid ()) {Currtype = M_reversimap.getpieces (point.m_row_y, point.m_column_x); if (enum_reversIpieces_null! = Currtype) {if (type = = Currtype) {if (Search > 1) {//finds the same color piece as the current piece coordinates with a difference of more than 1, then a piece with a different color between the two children return true;} else{//otherwise the two children are next to each other, the direction between the two children can flip return false;}} else{//found is a different color of the pieces, continue (Point.*forward) (); search++;}} else{//always found the vacancy and did not find, the direction is not the same color pieces, can not flip return false;}} The same color piece is not found in the range of the checkerboard, there is no same color piece in the direction, cannot flip return false;} void Reversi::D oreversi (enumreversipiecestype type, char row_y, char column_x) {if (Reversicheck (type, row_y, column_x, & Amp Reversipoint::ul)) {Doreversi (type, row_y, column_x, &reversipoint::ul);} if (Reversicheck (type, row_y, column_x, &reversipoint::u)) {Doreversi (type, row_y, column_x, &reversipoint::u) ;} if (Reversicheck (type, row_y, column_x, &reversipoint::ur)) {Doreversi (type, row_y, column_x, &reversipoint:: UR);} if (Reversicheck (type, row_y, column_x, &reversipoint::l)) {Doreversi (type, row_y, column_x, &reversipoint::l) ;} if (Reversicheck (type, row_y, column_x, &reversipoint::r)) {Doreversi (type, row_y, column_x, &reversipoint::r) ;} if (Reversicheck (TypE, row_y, column_x, &reversipoint::D l)) {Doreversi (type, row_y, column_x, &reversipoint::D l);} if (Reversicheck (type, row_y, column_x, &reversipoint::D)) {Doreversi (type, row_y, column_x, &reversipoint::D) ;} if (Reversicheck (type, row_y, column_x, &reversipoint::D r)) {Doreversi (type, row_y, column_x, &reversipoint::D R);}} void Reversi::D oreversi (enumreversipiecestype type, char row_y, char Column_x,reversipointforward forward) { Reversipoint point = {row_y, column_x};(p Oint.*forward) (); IsValid ()) {if (Type! = M_reversimap.getpieces (point.m_row_y, point.m_column_x)) {m_reversimap.setpieces (type, Point.m_row_y, point.m_column_x);(p Oint.*forward) ();} Else{break;}}} void Reversi::addreversistep () {tbdlinker<reversistep> *plinker = M_reversisteppool.malloc (); if (NULL! = PLinker ) {Plinker->m_value.m_lastmap = M_reversimap;plinker->m_value.m_currtype = M_currtype;plinker->m_plinklist = Null;m_reversisteplist.pushtail (Plinker);}} void Reversi::cancel () {Tbdlinker<reversistep> *plinker = M_reversisteplist.poptail (); if (NULL! = plinker) {M_reversimap = PLinker->m_ Value.m_lastmap;m_currtype = Plinker->m_value.m_currtype;m_reversisteppool.free (PLinker);}} void Reversi::swapplayer () {Enumreversipiecestype nexttype;if (enum_reversipieces_black = = m_CurrType) {Nexttype = enum _reversipieces_white;} Else{nexttype = Enum_reversipieces_black;} if (CanPlay (Nexttype)) {m_currtype = Nexttype;}} Enumreversiresult Reversi::isgameover () {if (! CanPlay (enum_reversipieces_black) &&! CanPlay (Enum_reversipieces_white)) {BYTE black = M_reversimap.getblackcount (); BYTE white = M_reversimap.getwhitecount (), if (Black > White) {return enum_reversi_win_black;} else if (Black < white) {return enum_reversi_win_white;} Else{return Enum_reversi_draw;}} Else{return enum_reversi_playing;}} Enumreversipiecestype Reversi::getcurrtype () {return m_currtype;} reversibitboard& Reversi::getmap () {return m_reversimap;}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.