00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef GO_BOARD_H
00012 #define GO_BOARD_H
00013
00014 #include <bitset>
00015 #include <cstring>
00016 #include <stdint.h>
00017 #include <boost/static_assert.hpp>
00018 #include "GoPlayerMove.h"
00019 #include "GoRules.h"
00020 #include "GoSetup.h"
00021 #include "SgArray.h"
00022 #include "SgBoardConst.h"
00023 #include "SgBoardColor.h"
00024 #include "SgMarker.h"
00025 #include "SgBWArray.h"
00026 #include "SgBWSet.h"
00027 #include "SgHash.h"
00028 #include "SgNbIterator.h"
00029 #include "SgPoint.h"
00030 #include "SgPointArray.h"
00031 #include "SgPointIterator.h"
00032 #include "SgPointSet.h"
00033 #include "SgSList.h"
00034
00035
00036
00037
00038 const int GO_DEFAULT_SIZE = (SG_MAX_SIZE >= 19 ? 19 : SG_MAX_SIZE);
00039
00040
00041
00042
00043 const int GO_MAX_NUM_MOVES = (3 * SG_MAX_SIZE * SG_MAX_SIZE);
00044
00045
00046
00047
00048 enum GoMoveInfoFlag
00049 {
00050
00051 GO_MOVEFLAG_REPETITION,
00052
00053
00054 GO_MOVEFLAG_SUICIDE,
00055
00056
00057 GO_MOVEFLAG_CAPTURING,
00058
00059
00060
00061
00062 GO_MOVEFLAG_ILLEGAL,
00063
00064 _GO_NU_MOVEFLAG
00065 };
00066
00067 typedef std::bitset<_GO_NU_MOVEFLAG> GoMoveInfo;
00068
00069
00070
00071
00072 typedef SgSList<SgPoint,SG_MAX_ONBOARD + 1> GoPointList;
00073
00074
00075
00076
00077 typedef SgSList<SgPoint,GO_MAX_NUM_MOVES> GoSequence;
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 class GoBoard
00099 {
00100 public:
00101
00102
00103
00104
00105 static const int MAX_KOLEVEL = 3;
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 mutable SgMarker m_userMarker;
00117
00118 explicit GoBoard(int size = GO_DEFAULT_SIZE,
00119 const GoSetup& setup = GoSetup(),
00120 const GoRules& rules = GoRules());
00121
00122 ~GoBoard();
00123
00124 const SgBoardConst& BoardConst() const;
00125
00126
00127 uint64_t CountPlay() const;
00128
00129
00130
00131
00132 void Init(int size, const GoSetup& setup = GoSetup());
00133
00134
00135 void Init(int size, const GoRules& rules,
00136 const GoSetup& setup = GoSetup());
00137
00138
00139
00140
00141
00142
00143
00144
00145 GoRules& Rules();
00146
00147
00148 const GoRules& Rules() const;
00149
00150
00151 SgGrid Size() const;
00152
00153
00154
00155
00156
00157
00158 bool StackOverflowLikely() const;
00159
00160
00161 bool IsFirst(SgPoint p) const;
00162
00163
00164
00165 bool IsNewPosition() const;
00166
00167
00168
00169
00170 bool Occupied(SgPoint p) const;
00171
00172 bool IsEmpty(SgPoint p) const;
00173
00174 bool IsBorder(SgPoint p) const;
00175
00176 bool IsColor(SgPoint p, int c) const;
00177
00178 SgBoardColor GetColor(SgPoint p) const;
00179
00180 SgBlackWhite GetStone(SgPoint p) const;
00181
00182
00183 SgBlackWhite ToPlay() const;
00184
00185
00186 SgBlackWhite Opponent() const;
00187
00188
00189 void SetToPlay(SgBlackWhite player);
00190
00191
00192 SgGrid Line(SgPoint p) const;
00193
00194
00195 SgGrid Pos(SgPoint p) const;
00196
00197
00198
00199
00200
00201 int Up(SgPoint p) const;
00202
00203
00204
00205
00206
00207
00208 int Left(SgPoint p) const;
00209
00210
00211
00212
00213 int Right(SgPoint p) const;
00214
00215
00216 int Side(SgPoint p, int index) const;
00217
00218 bool IsSuicide(SgPoint p, SgBlackWhite toPlay) const;
00219
00220 bool IsValidPoint(SgPoint p) const;
00221
00222 bool HasEmptyNeighbors(SgPoint p) const;
00223
00224 int NumEmptyNeighbors(SgPoint p) const;
00225
00226
00227 int Num8EmptyNeighbors(SgPoint p) const;
00228
00229 bool HasNeighbors(SgPoint p, SgBlackWhite c) const;
00230
00231 int NumNeighbors(SgPoint p, SgBlackWhite c) const;
00232
00233
00234 int Num8Neighbors(SgPoint p, SgBlackWhite c) const;
00235
00236 bool HasDiagonals(SgPoint p, SgBoardColor c) const;
00237
00238 int NumDiagonals(SgPoint p, SgBoardColor c) const;
00239
00240 int NumEmptyDiagonals(SgPoint p) const;
00241
00242 bool HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const;
00243
00244
00245
00246
00247 SgPointSet Occupied() const;
00248
00249 const SgPointSet& All(SgBlackWhite color) const;
00250
00251 const SgPointSet& AllEmpty() const;
00252
00253 const SgPointSet& AllPoints() const;
00254
00255
00256 const SgPointSet& Corners() const;
00257
00258
00259 const SgPointSet& Edges() const;
00260
00261
00262 const SgPointSet& Centers() const;
00263
00264
00265 const SgPointSet& SideExtensions() const;
00266
00267
00268 const SgPointSet& LineSet(SgGrid line) const;
00269
00270
00271
00272 bool InCorner(SgPoint p) const;
00273
00274 bool OnEdge(SgPoint p) const;
00275
00276 bool InCenter(SgPoint p) const;
00277
00278
00279 int FirstBoardPoint() const;
00280
00281
00282 int LastBoardPoint() const;
00283
00284
00285
00286
00287
00288 bool LastMoveInfo(GoMoveInfoFlag flag) const;
00289
00290 GoMoveInfo GetLastMoveInfo() const;
00291
00292 void AllowKoRepetition(bool allowKo);
00293
00294
00295
00296
00297 void AllowAnyRepetition(bool allowAny);
00298
00299
00300
00301
00302
00303
00304
00305 void SetKoModifiesHash(bool modify);
00306
00307 bool KoRepetitionAllowed() const;
00308
00309
00310
00311
00312 bool AnyRepetitionAllowed() const;
00313
00314 bool KoModifiesHash() const;
00315
00316
00317
00318
00319
00320
00321
00322
00323 void Play(SgPoint p, SgBlackWhite player);
00324
00325
00326
00327
00328 void Play(SgPoint p);
00329
00330
00331
00332
00333 void Play(GoPlayerMove move);
00334
00335
00336 void Undo();
00337
00338
00339 bool CanUndo() const;
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 bool IsLegal(int p, SgBlackWhite player) const;
00350
00351
00352
00353
00354 bool IsLegal(int p) const;
00355
00356 bool IsSuicide(SgPoint p) const;
00357
00358
00359 bool CapturingMove() const;
00360
00361
00362
00363
00364
00365
00366 const GoPointList& CapturedStones() const;
00367
00368
00369
00370
00371 int NuCapturedStones() const;
00372
00373
00374
00375 int NumPrisoners(SgBlackWhite color) const;
00376
00377
00378 const GoSetup& Setup() const;
00379
00380
00381 int MoveNumber() const;
00382
00383
00384
00385
00386
00387 GoPlayerMove Move(int i) const;
00388
00389
00390
00391
00392
00393
00394 SgPoint GetLastMove() const;
00395
00396
00397
00398
00399 SgPoint Get2ndLastMove() const;
00400
00401
00402
00403
00404
00405
00406 SgPoint KoPoint() const;
00407
00408
00409
00410
00411
00412 const SgHashCode& GetHashCode() const;
00413
00414
00415
00416
00417
00418
00419 SgHashCode GetHashCodeInclToPlay() const;
00420
00421
00422
00423
00424 int NumStones(SgPoint p) const;
00425
00426
00427 bool IsSingleStone(SgPoint p) const;
00428
00429
00430
00431
00432 bool AreInSameBlock(SgPoint stone1, SgPoint stone2) const;
00433
00434
00435
00436
00437 SgPoint Anchor(SgPoint p) const;
00438
00439
00440
00441
00442
00443 bool IsInBlock(SgPoint p, SgPoint anchor) const;
00444
00445
00446
00447
00448
00449
00450 bool IsLibertyOfBlock(SgPoint p, SgPoint anchor) const;
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 int AdjacentBlocks(SgPoint p, int maxLib, SgPoint anchors[],
00463 int maxAnchors) const;
00464
00465
00466
00467
00468
00469
00470 void NeighborBlocks(SgPoint p, SgBlackWhite c, SgPoint anchors[]) const;
00471
00472
00473
00474
00475
00476
00477 void NeighborBlocks(SgPoint p, SgBlackWhite c, int maxLib,
00478 SgPoint anchors[]) const;
00479
00480
00481 const SgBWArray<int>& TotalNumStones() const;
00482
00483 int TotalNumStones(SgBlackWhite color) const;
00484
00485
00486 int TotalNumEmpty() const;
00487
00488
00489
00490
00491 SgPoint TheLiberty(SgPoint blockInAtari) const;
00492
00493
00494
00495
00496 int NumLiberties(SgPoint p) const;
00497
00498
00499 bool AtMostNumLibs(SgPoint block, int n) const;
00500
00501
00502 bool AtLeastNumLibs(SgPoint block, int n) const;
00503
00504
00505
00506
00507 bool InAtari(SgPoint p) const;
00508
00509
00510
00511
00512
00513 bool OccupiedInAtari(SgPoint p) const;
00514
00515
00516
00517
00518 bool CanCapture(SgPoint p, SgBlackWhite c) const;
00519
00520
00521
00522
00523 SgEmptyBlackWhite KoColor() const;
00524
00525
00526 int KoLevel() const;
00527
00528
00529
00530
00531
00532
00533 SgEmptyBlackWhite KoLoser() const;
00534
00535
00536 void SetKoLoser(SgEmptyBlackWhite color);
00537
00538
00539
00540
00541 void CheckConsistency() const;
00542
00543
00544
00545
00546
00547 void TakeSnapshot();
00548
00549
00550
00551
00552
00553
00554
00555 void RestoreSnapshot();
00556
00557 private:
00558
00559 class Block
00560 {
00561 public:
00562
00563
00564
00565 static const int MAX_LIBERTIES = (SG_MAX_SIZE / 3) * 2 * SG_MAX_SIZE;
00566
00567 typedef SgSList<SgPoint,MAX_LIBERTIES> LibertyList;
00568
00569 typedef LibertyList::Iterator LibertyIterator;
00570
00571 typedef GoPointList::Iterator StoneIterator;
00572
00573 SgPoint Anchor() const { return m_anchor; }
00574
00575 void UpdateAnchor(SgPoint p) { if (p < m_anchor) m_anchor = p; }
00576
00577 void AppendLiberty(SgPoint p) { m_liberties.PushBack(p); }
00578
00579 void AppendStone(SgPoint p) { m_stones.PushBack(p); }
00580
00581 SgBlackWhite Color() const { return m_color; }
00582
00583 void ExcludeLiberty(SgPoint p) { m_liberties.Exclude(p); }
00584
00585 void Init(SgBlackWhite c, SgPoint anchor)
00586 {
00587 SG_ASSERT_BW(c);
00588 m_color = c;
00589 m_anchor = anchor;
00590 m_stones.SetTo(anchor);
00591 m_liberties.Clear();
00592 }
00593
00594 void Init(SgBlackWhite c, SgPoint anchor, GoPointList stones,
00595 LibertyList liberties)
00596 {
00597 SG_ASSERT_BW(c);
00598 SG_ASSERT(stones.Contains(anchor));
00599 m_color = c;
00600 m_anchor = anchor;
00601 m_stones = stones;
00602 m_liberties = liberties;
00603 }
00604
00605 const LibertyList& Liberties() const { return m_liberties; }
00606
00607 int NumLiberties() const { return m_liberties.Length(); }
00608
00609 int NumStones() const { return m_stones.Length(); }
00610
00611 void PopStone() { m_stones.PopBack(); }
00612
00613 void SetAnchor(SgPoint p) { m_anchor = p; }
00614
00615 const GoPointList& Stones() const { return m_stones; }
00616
00617 private:
00618 SgPoint m_anchor;
00619
00620 SgBlackWhite m_color;
00621
00622 LibertyList m_liberties;
00623
00624 GoPointList m_stones;
00625 };
00626
00627
00628
00629
00630 class HashCode
00631 {
00632 public:
00633 void Clear();
00634
00635 const SgHashCode& Get() const;
00636
00637 SgHashCode GetInclToPlay(SgBlackWhite toPlay) const;
00638
00639 void XorCaptured(int moveNumber, SgPoint firstCapturedStone);
00640
00641 void XorStone(SgPoint p, SgBlackWhite c);
00642
00643 void XorWinKo(int level, SgBlackWhite c);
00644
00645 private:
00646
00647 static const int START_INDEX_TOPLAY = 1;
00648 static const int END_INDEX_TOPLAY = 2;
00649 static const int START_INDEX_STONES = 3;
00650 static const int END_INDEX_STONES = 2 * SG_MAXPOINT;
00651 static const int START_INDEX_WINKO = 2 * SG_MAXPOINT + 1;
00652 static const int END_INDEX_WINKO = 2 * SG_MAXPOINT + SG_MAX_SIZE + 1;
00653 static const int START_INDEX_CAPTURES
00654 = 2 * SG_MAXPOINT + SG_MAX_SIZE + 2;
00655 static const int END_INDEX_CAPTURES = 3 * SG_MAXPOINT + 63;
00656
00657
00658
00659 BOOST_STATIC_ASSERT(START_INDEX_TOPLAY >= 0);
00660 BOOST_STATIC_ASSERT(END_INDEX_TOPLAY > START_INDEX_TOPLAY);
00661 BOOST_STATIC_ASSERT(START_INDEX_STONES > END_INDEX_TOPLAY);
00662 BOOST_STATIC_ASSERT(END_INDEX_STONES > START_INDEX_STONES);
00663 BOOST_STATIC_ASSERT(END_INDEX_WINKO > START_INDEX_WINKO);
00664 BOOST_STATIC_ASSERT(START_INDEX_CAPTURES > END_INDEX_WINKO);
00665 BOOST_STATIC_ASSERT(END_INDEX_CAPTURES > START_INDEX_CAPTURES);
00666 BOOST_STATIC_ASSERT(START_INDEX_WINKO + MAX_KOLEVEL * 3 - 1
00667 <= END_INDEX_WINKO);
00668 BOOST_STATIC_ASSERT(END_INDEX_CAPTURES
00669 < SgHashZobristTable::MAX_HASH_INDEX);
00670
00671 SgHashCode m_hash;
00672 };
00673
00674
00675
00676
00677 struct StackEntry
00678 {
00679
00680 SgBlackWhite m_color;
00681
00682
00683 SgPoint m_point;
00684
00685
00686
00687
00688 bool m_isFirst;
00689
00690
00691 bool m_isNewPosition;
00692
00693 Block* m_stoneAddedTo;
00694
00695
00696
00697
00698 SgPoint m_oldAnchor;
00699
00700 SgSList<SgPoint,4> m_newLibs;
00701
00702 SgSList<Block*,4> m_merged;
00703
00704
00705
00706
00707
00708
00709
00710 SgBlackWhite m_toPlay;
00711
00712
00713 HashCode m_hash;
00714
00715
00716 SgPoint m_koPoint;
00717
00718
00719 int m_koLevel;
00720
00721
00722 SgEmptyBlackWhite m_koColor;
00723
00724
00725 SgEmptyBlackWhite m_koLoser;
00726
00727
00728 bool m_koModifiesHash;
00729
00730 Block* m_suicide;
00731
00732 SgSList<Block*,4> m_killed;
00733
00734 };
00735
00736
00737
00738
00739
00740
00741
00742 struct State
00743 {
00744
00745 SgPoint m_koPoint;
00746
00747
00748 SgBlackWhite m_toPlay;
00749
00750
00751 HashCode m_hash;
00752
00753 SgBWSet m_all;
00754
00755 SgPointSet m_empty;
00756
00757 SgArray<Block*,SG_MAXPOINT> m_block;
00758
00759
00760 SgBWArray<int> m_prisoners;
00761
00762
00763 SgBWArray<int> m_numStones;
00764
00765
00766 int m_koLevel;
00767
00768
00769 SgArray<int,SG_MAXPOINT> m_color;
00770
00771
00772 SgArray<int,SG_MAXPOINT> m_nuNeighborsEmpty;
00773
00774
00775 SgBWArray<SgArray<int,SG_MAXPOINT> > m_nuNeighbors;
00776
00777
00778 SgArray<bool,SG_MAXPOINT> m_isFirst;
00779
00780
00781
00782
00783 bool m_isNewPosition;
00784 };
00785
00786 struct Snapshot
00787 {
00788
00789 int m_moveNumber;
00790
00791 int m_blockListSize;
00792
00793 State m_state;
00794
00795
00796 SgPointArray<Block> m_blockArray;
00797 };
00798
00799 State m_state;
00800
00801 std::auto_ptr<Snapshot> m_snapshot;
00802
00803
00804 uint64_t m_countPlay;
00805
00806
00807 SgBoardConst m_const;
00808
00809
00810 SgGrid m_size;
00811
00812
00813
00814
00815 GoRules m_rules;
00816
00817
00818 GoSetup m_setup;
00819
00820 GoMoveInfo m_moveInfo;
00821
00822
00823
00824
00825 SgSList<Block,GO_MAX_NUM_MOVES>* m_blockList;
00826
00827
00828
00829
00830
00831 mutable SgMarker m_marker;
00832
00833 GoPointList m_capturedStones;
00834
00835
00836 bool m_allowAnyRepetition;
00837
00838
00839 bool m_allowKoRepetition;
00840
00841 bool m_koModifiesHash;
00842
00843 SgEmptyBlackWhite m_koColor;
00844
00845
00846 SgEmptyBlackWhite m_koLoser;
00847
00848 SgArray<bool,SG_MAXPOINT> m_isBorder;
00849
00850 SgSList<StackEntry,GO_MAX_NUM_MOVES>* m_moves;
00851
00852 static bool IsPass(SgPoint p);
00853
00854
00855 GoBoard(const GoBoard&);
00856
00857
00858 GoBoard& operator=(const GoBoard&);
00859
00860
00861
00862
00863
00864
00865 bool CheckKo(SgBlackWhite player);
00866
00867 void AddLibToAdjBlocks(SgPoint p);
00868
00869 void AddLibToAdjBlocks(SgPoint p, SgBlackWhite c);
00870
00871 void AddStoneToBlock(SgPoint p, SgBlackWhite c, Block* block,
00872 StackEntry& entry);
00873
00874 Block& CreateNewBlock();
00875
00876 void CreateSingleStoneBlock(SgPoint p, SgBlackWhite c);
00877
00878 SgSList<Block*,4> GetAdjacentBlocks(SgPoint p) const;
00879
00880 SgSList<Block*,4> GetAdjacentBlocks(SgPoint p, SgBlackWhite c) const;
00881
00882 void InitBlock(GoBoard::Block& block, SgBlackWhite c, SgPoint anchor);
00883
00884 bool IsAdjacentTo(SgPoint p, const Block* block) const;
00885
00886 void MergeBlocks(SgPoint p, SgBlackWhite c,
00887 const SgSList<Block*,4>& adjBlocks);
00888
00889 void RemoveLibAndKill(SgPoint p, SgBlackWhite opp, StackEntry& entry);
00890
00891 void RemoveLibFromAdjBlocks(SgPoint p, SgBlackWhite c);
00892
00893 void RestoreKill(Block* block, SgBlackWhite c);
00894
00895 void UpdateBlocksAfterAddStone(SgPoint p, SgBlackWhite c,
00896 StackEntry& entry);
00897
00898 void UpdateBlocksAfterUndo(const StackEntry& entry);
00899
00900 void CheckConsistencyBlock(SgPoint p) const;
00901
00902 bool FullBoardRepetition() const;
00903
00904
00905
00906
00907
00908
00909 bool CheckSuicide(SgPoint p, StackEntry& entry);
00910
00911 void AddStone(SgPoint p, SgBlackWhite c);
00912
00913 void RemoveStone(SgPoint p);
00914
00915 void AddStoneForUndo(SgPoint p, SgBlackWhite c);
00916
00917 void RemoveStoneForUndo(SgPoint p);
00918
00919 void KillBlock(const Block* block);
00920
00921 bool HasLiberties(SgPoint p) const;
00922
00923
00924 void RestoreState(const StackEntry& entry);
00925
00926
00927
00928
00929
00930 void SaveState(StackEntry& entry);
00931
00932 friend class LibertyCopyIterator;
00933 friend class LibertyIterator;
00934 friend class StoneIterator;
00935
00936 public:
00937
00938
00939
00940
00941 class StoneIterator
00942 {
00943 public:
00944 StoneIterator(const GoBoard& bd, SgPoint p);
00945
00946
00947 void operator++();
00948
00949
00950 SgPoint operator*() const;
00951
00952
00953 operator bool() const;
00954
00955 private:
00956
00957
00958
00959
00960
00961
00962 GoBoard::Block::StoneIterator m_it;
00963
00964 const GoBoard& m_board;
00965
00966 #ifndef NDEBUG
00967 uint64_t m_countPlay;
00968 #endif
00969
00970
00971 StoneIterator(const StoneIterator&);
00972
00973
00974 StoneIterator& operator=(const StoneIterator&);
00975 };
00976
00977
00978 class Iterator
00979 : public SgPointRangeIterator
00980 {
00981 public:
00982 Iterator(const GoBoard& bd);
00983 };
00984
00985
00986
00987
00988
00989
00990 class LibertyIterator
00991 {
00992 public:
00993 LibertyIterator(const GoBoard& bd, SgPoint p);
00994
00995
00996 void operator++();
00997
00998
00999 SgPoint operator*() const;
01000
01001
01002 operator bool() const;
01003
01004 private:
01005 Block::LibertyList::Iterator m_it;
01006
01007 const GoBoard& m_board;
01008
01009 #ifndef NDEBUG
01010 uint64_t m_countPlay;
01011 #endif
01012
01013
01014 LibertyIterator(const LibertyIterator&);
01015
01016
01017 LibertyIterator& operator=(const LibertyIterator&);
01018 };
01019
01020
01021
01022
01023
01024
01025
01026 class LibertyCopyIterator
01027 {
01028 public:
01029 LibertyCopyIterator(const GoBoard& bd, SgPoint p);
01030
01031
01032 void operator++();
01033
01034
01035 int operator*() const;
01036
01037
01038 operator bool() const;
01039
01040 private:
01041
01042
01043
01044
01045
01046
01047 Block::LibertyList m_liberties;
01048
01049 Block::LibertyList::Iterator m_it;
01050
01051 const GoBoard& m_board;
01052
01053 #ifndef NDEBUG
01054 SgHashCode m_oldHash;
01055 #endif
01056
01057
01058 LibertyCopyIterator(const LibertyCopyIterator&);
01059
01060
01061 LibertyCopyIterator& operator=(const LibertyCopyIterator&);
01062 };
01063 };
01064
01065 inline GoBoard::StoneIterator::StoneIterator(const GoBoard& bd, SgPoint p)
01066 : m_it(bd.m_state.m_block[p]->Stones()),
01067 m_board(bd)
01068 {
01069 SG_ASSERT(m_board.Occupied(p));
01070 #ifndef NDEBUG
01071 m_countPlay = m_board.CountPlay();
01072 #endif
01073 }
01074
01075 inline void GoBoard::StoneIterator::operator++()
01076 {
01077 ++m_it;
01078 }
01079
01080 inline SgPoint GoBoard::StoneIterator::operator*() const
01081 {
01082 SG_ASSERT(m_board.CountPlay() == m_countPlay);
01083 return *m_it;
01084 }
01085
01086 inline GoBoard::StoneIterator::operator bool() const
01087 {
01088 return m_it;
01089 }
01090
01091 inline GoBoard::Iterator::Iterator(const GoBoard& bd)
01092 : SgPointRangeIterator(bd.BoardConst().BoardIterAddress(),
01093 bd.BoardConst().BoardIterEnd())
01094 {
01095 }
01096
01097 inline GoBoard::LibertyIterator::LibertyIterator(const GoBoard& bd, SgPoint p)
01098 : m_it(bd.m_state.m_block[p]->Liberties()),
01099 m_board(bd)
01100 {
01101 SG_ASSERT(m_board.Occupied(p));
01102 #ifndef NDEBUG
01103 m_countPlay = m_board.CountPlay();
01104 #endif
01105 }
01106
01107 inline void GoBoard::LibertyIterator::operator++()
01108 {
01109 ++m_it;
01110 }
01111
01112 inline SgPoint GoBoard::LibertyIterator::operator*() const
01113 {
01114 SG_ASSERT(m_board.CountPlay() == m_countPlay);
01115 return *m_it;
01116 }
01117
01118 inline GoBoard::LibertyIterator::operator bool() const
01119 {
01120 return m_it;
01121 }
01122
01123 inline GoBoard::LibertyCopyIterator::LibertyCopyIterator(const GoBoard& bd,
01124 SgPoint p)
01125 : m_liberties(bd.m_state.m_block[p]->Liberties()),
01126 m_it(m_liberties),
01127 m_board(bd)
01128 {
01129 SG_ASSERT(m_board.Occupied(p));
01130 #ifndef NDEBUG
01131 m_oldHash = m_board.GetHashCode();
01132 #endif
01133 }
01134
01135 inline void GoBoard::LibertyCopyIterator::operator++()
01136 {
01137 ++m_it;
01138 }
01139
01140 inline int GoBoard::LibertyCopyIterator::operator*() const
01141 {
01142 SG_ASSERT(m_board.GetHashCode() == m_oldHash);
01143 return *m_it;
01144 }
01145
01146 inline GoBoard::LibertyCopyIterator::operator bool() const
01147 {
01148 return m_it;
01149 }
01150
01151 inline void GoBoard::HashCode::Clear()
01152 {
01153 m_hash.Clear();
01154 }
01155
01156 inline const SgHashCode& GoBoard::HashCode::Get() const
01157 {
01158 return m_hash;
01159 }
01160
01161 inline SgHashCode GoBoard::HashCode::GetInclToPlay(SgBlackWhite toPlay) const
01162 {
01163 SgHashCode hash = m_hash;
01164 BOOST_STATIC_ASSERT(SG_BLACK == 0);
01165 BOOST_STATIC_ASSERT(SG_WHITE == 1);
01166 int index = toPlay + 1;
01167 SG_ASSERTRANGE(index, START_INDEX_TOPLAY, END_INDEX_TOPLAY);
01168 SgHashUtil::XorZobrist(hash, index);
01169 return hash;
01170 }
01171
01172 inline void GoBoard::HashCode::XorCaptured(int moveNumber,
01173 SgPoint firstCapturedStone)
01174 {
01175 int index = 2 * SG_MAXPOINT + moveNumber % 64 + firstCapturedStone;
01176 SG_ASSERTRANGE(index, START_INDEX_CAPTURES, END_INDEX_CAPTURES);
01177 SgHashUtil::XorZobrist(m_hash, index);
01178 }
01179
01180 inline void GoBoard::HashCode::XorStone(SgPoint p, SgBlackWhite c)
01181 {
01182 SG_ASSERT_BOARDRANGE(p);
01183 SG_ASSERT_BW(c);
01184 BOOST_STATIC_ASSERT(SG_BLACK == 0);
01185 BOOST_STATIC_ASSERT(SG_WHITE == 1);
01186 int index = p + c * SG_MAXPOINT;
01187 SG_ASSERTRANGE(index, START_INDEX_STONES, END_INDEX_STONES);
01188 SgHashUtil::XorZobrist(m_hash, index);
01189 }
01190
01191 inline void GoBoard::HashCode::XorWinKo(int level, SgBlackWhite c)
01192 {
01193 SG_ASSERT(level > 0 && level <= MAX_KOLEVEL);
01194 SG_ASSERT_BW(c);
01195 BOOST_STATIC_ASSERT(SG_BLACK == 0);
01196 BOOST_STATIC_ASSERT(SG_WHITE == 1);
01197 int index = level + MAX_KOLEVEL * c + 2 * SG_MAXPOINT;
01198 SG_ASSERTRANGE(index, START_INDEX_WINKO, END_INDEX_WINKO);
01199 SgHashUtil::XorZobrist(m_hash, index);
01200 }
01201
01202 inline const SgPointSet& GoBoard::All(SgBlackWhite color) const
01203 {
01204 return m_state.m_all[color];
01205 }
01206
01207 inline const SgPointSet& GoBoard::AllEmpty() const
01208 {
01209 return m_state.m_empty;
01210 }
01211
01212 inline void GoBoard::AllowAnyRepetition(bool allowAny)
01213 {
01214 m_allowAnyRepetition = allowAny;
01215 }
01216
01217 inline void GoBoard::AllowKoRepetition(bool allowKo)
01218 {
01219 m_allowKoRepetition = allowKo;
01220 }
01221
01222 inline const SgPointSet& GoBoard::AllPoints() const
01223 {
01224 return SgPointSet::AllPoints(Size());
01225 }
01226
01227 inline SgPoint GoBoard::Anchor(SgPoint p) const
01228 {
01229 SG_ASSERT(Occupied(p));
01230 return m_state.m_block[p]->Anchor();
01231 }
01232
01233 inline bool GoBoard::AnyRepetitionAllowed() const
01234 {
01235 return m_allowAnyRepetition;
01236 }
01237
01238 inline bool GoBoard::AreInSameBlock(SgPoint p1, SgPoint p2) const
01239 {
01240 return Occupied(p1) && Occupied(p2) && Anchor(p1) == Anchor(p2);
01241 }
01242
01243 inline bool GoBoard::AtLeastNumLibs(SgPoint block, int n) const
01244 {
01245 return NumLiberties(block) >= n;
01246 }
01247
01248 inline bool GoBoard::AtMostNumLibs(SgPoint block, int n) const
01249 {
01250 return NumLiberties(block) <= n;
01251 }
01252
01253 inline bool GoBoard::CanUndo() const
01254 {
01255 return (m_moves->Length() > 0);
01256 }
01257
01258 inline const GoPointList& GoBoard::CapturedStones() const
01259 {
01260 return m_capturedStones;
01261 }
01262
01263 inline bool GoBoard::CapturingMove() const
01264 {
01265 return ! m_capturedStones.IsEmpty();
01266 }
01267
01268 inline const SgPointSet& GoBoard::Centers() const
01269 {
01270 return m_const.Centers();
01271 }
01272
01273 inline const SgPointSet& GoBoard::Corners() const
01274 {
01275 return m_const.Corners();
01276 }
01277
01278 inline uint64_t GoBoard::CountPlay() const
01279 {
01280 return m_countPlay;
01281 }
01282
01283 inline const SgPointSet& GoBoard::Edges() const
01284 {
01285 return m_const.Edges();
01286 }
01287
01288 inline int GoBoard::FirstBoardPoint() const
01289 {
01290 return m_const.FirstBoardPoint();
01291 }
01292
01293 inline const SgBoardConst& GoBoard::BoardConst() const
01294 {
01295 return m_const;
01296 }
01297
01298 inline SgPoint GoBoard::Get2ndLastMove() const
01299 {
01300 int moveNumber = MoveNumber();
01301 if (moveNumber < 2)
01302 return SG_NULLMOVE;
01303 const StackEntry& entry1 = (*m_moves)[moveNumber - 1];
01304 const StackEntry& entry2 = (*m_moves)[moveNumber - 2];
01305 SgBlackWhite toPlay = ToPlay();
01306 if (entry1.m_color != SgOppBW(toPlay) || entry2.m_color != toPlay)
01307 return SG_NULLMOVE;
01308 return entry2.m_point;
01309 }
01310
01311 inline SgBoardColor GoBoard::GetColor(SgPoint p) const
01312 {
01313 return m_state.m_color[p];
01314 }
01315
01316 inline const SgHashCode& GoBoard::GetHashCode() const
01317 {
01318 return m_state.m_hash.Get();
01319 }
01320
01321 inline SgHashCode GoBoard::GetHashCodeInclToPlay() const
01322 {
01323 return m_state.m_hash.GetInclToPlay(ToPlay());
01324 }
01325
01326 inline SgPoint GoBoard::GetLastMove() const
01327 {
01328 int moveNumber = MoveNumber();
01329 if (moveNumber == 0)
01330 return SG_NULLMOVE;
01331 const StackEntry& entry = (*m_moves)[moveNumber - 1];
01332 if (entry.m_color != SgOppBW(ToPlay()))
01333 return SG_NULLMOVE;
01334 return entry.m_point;
01335 }
01336
01337 inline GoMoveInfo GoBoard::GetLastMoveInfo() const
01338 {
01339 return m_moveInfo;
01340 }
01341
01342 inline SgBlackWhite GoBoard::GetStone(SgPoint p) const
01343 {
01344 SG_ASSERT(Occupied(p));
01345 return m_state.m_color[p];
01346 }
01347
01348 inline bool GoBoard::HasDiagonals(SgPoint p, SgBoardColor c) const
01349 {
01350 return (IsColor(p - SG_NS - SG_WE, c)
01351 || IsColor(p - SG_NS + SG_WE, c)
01352 || IsColor(p + SG_NS - SG_WE, c)
01353 || IsColor(p + SG_NS + SG_WE, c));
01354 }
01355
01356 inline bool GoBoard::HasEmptyNeighbors(SgPoint p) const
01357 {
01358 return m_state.m_nuNeighborsEmpty[p] != 0;
01359 }
01360
01361 inline bool GoBoard::HasLiberties(SgPoint p) const
01362 {
01363 return NumLiberties(p) > 0;
01364 }
01365
01366 inline bool GoBoard::HasNeighbors(SgPoint p, SgBlackWhite c) const
01367 {
01368 return (m_state.m_nuNeighbors[c][p] > 0);
01369 }
01370
01371 inline bool GoBoard::HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const
01372 {
01373 return HasNeighbors(p, c) || HasDiagonals(p, c);
01374 }
01375
01376 inline bool GoBoard::InAtari(SgPoint p) const
01377 {
01378 SG_ASSERT(Occupied(p));
01379 return AtMostNumLibs(p, 1);
01380 }
01381
01382 inline bool GoBoard::IsInBlock(SgPoint p, SgPoint anchor) const
01383 {
01384 SG_ASSERT(Occupied(anchor));
01385 SG_ASSERT(Anchor(anchor) == anchor);
01386 const Block* b = m_state.m_block[p];
01387 return (b != 0 && b->Anchor() == anchor);
01388 }
01389
01390 inline bool GoBoard::IsLibertyOfBlock(SgPoint p, SgPoint anchor) const
01391 {
01392 SG_ASSERT(IsEmpty(p));
01393 SG_ASSERT(Occupied(anchor));
01394 SG_ASSERT(Anchor(anchor) == anchor);
01395 const Block* b = m_state.m_block[anchor];
01396 if (m_state.m_nuNeighbors[b->Color()][p] == 0)
01397 return false;
01398 return ( m_state.m_block[p - SG_NS] == b
01399 || m_state.m_block[p - SG_WE] == b
01400 || m_state.m_block[p + SG_WE] == b
01401 || m_state.m_block[p + SG_NS] == b);
01402 }
01403
01404 inline bool GoBoard::CanCapture(SgPoint p, SgBlackWhite c) const
01405 {
01406 SgBlackWhite opp = SgOppBW(c);
01407 for (SgNb4Iterator nb(p); nb; ++nb)
01408 if (IsColor(*nb, opp) && AtMostNumLibs(*nb, 1))
01409 return true;
01410 return false;
01411 }
01412
01413 inline bool GoBoard::InCenter(SgPoint p) const
01414 {
01415 return Centers()[p];
01416 }
01417
01418 inline bool GoBoard::InCorner(SgPoint p) const
01419 {
01420 return Corners()[p];
01421 }
01422
01423 inline void GoBoard::Init(int size, const GoSetup& setup)
01424 {
01425 Init(size, m_rules, setup);
01426 }
01427
01428 inline bool GoBoard::IsSuicide(SgPoint p, SgBlackWhite toPlay) const
01429 {
01430 if (HasEmptyNeighbors(p))
01431 return false;
01432 SgBlackWhite opp = SgOppBW(toPlay);
01433 for (SgNb4Iterator it(p); it; ++it)
01434 {
01435 if (IsBorder(*it))
01436 continue;
01437 SgEmptyBlackWhite c = GetColor(*it);
01438 if (c == toPlay && NumLiberties(*it) > 1)
01439 return false;
01440 if (c == opp && NumLiberties(*it) == 1)
01441 return false;
01442 }
01443 return true;
01444 }
01445
01446 inline bool GoBoard::IsBorder(SgPoint p) const
01447 {
01448 SG_ASSERT(p != SG_PASS);
01449 return m_isBorder[p];
01450 }
01451
01452 inline bool GoBoard::IsColor(SgPoint p, int c) const
01453 {
01454 SG_ASSERT(p != SG_PASS);
01455 SG_ASSERT_EBW(c);
01456 return m_state.m_color[p] == c;
01457 }
01458
01459 inline bool GoBoard::IsEmpty(SgPoint p) const
01460 {
01461 SG_ASSERT(p != SG_PASS);
01462 return m_state.m_color[p] == SG_EMPTY;
01463 }
01464
01465 inline bool GoBoard::IsFirst(SgPoint p) const
01466 {
01467 SG_ASSERT(IsEmpty(p));
01468 return m_state.m_isFirst[p];
01469 }
01470
01471 inline bool GoBoard::IsLegal(int p, SgBlackWhite player) const
01472 {
01473 SG_ASSERT_BW(player);
01474 if (IsPass(p))
01475 return true;
01476 SG_ASSERT(SgPointUtil::InBoardRange(p));
01477 if (! IsEmpty(p))
01478 return false;
01479
01480 if (! Rules().AllowSuicide() && IsSuicide(p, player))
01481 return false;
01482
01483 if (IsFirst(p))
01484 return true;
01485 if (p == m_state.m_koPoint && m_state.m_toPlay == player)
01486 return (AnyRepetitionAllowed() || KoRepetitionAllowed());
01487 if (Rules().GetKoRule() == GoRules::SIMPLEKO)
01488 return true;
01489 if (IsNewPosition() && ! CanCapture(p, player))
01490 return true;
01491
01492
01493
01494 GoBoard* bd = const_cast<GoBoard*>(this);
01495 bd->Play(p, player);
01496 bool isLegal = ! LastMoveInfo(GO_MOVEFLAG_ILLEGAL);
01497 bd->Undo();
01498 return isLegal;
01499 }
01500
01501 inline bool GoBoard::IsNewPosition() const
01502 {
01503 return m_state.m_isNewPosition;
01504 }
01505
01506 inline bool GoBoard::IsLegal(int p) const
01507 {
01508 return IsLegal(p, ToPlay());
01509 }
01510
01511
01512
01513
01514 inline bool GoBoard::IsPass(SgPoint p)
01515 {
01516 return (p == SG_PASS || SgMoveUtil::IsCouponMove(p));
01517 }
01518
01519 inline bool GoBoard::IsSingleStone(SgPoint p) const
01520 {
01521 return (Occupied(p) && NumNeighbors(p, GetColor(p)) == 0);
01522 }
01523
01524 inline bool GoBoard::IsSuicide(SgPoint p) const
01525 {
01526 return IsSuicide(p, ToPlay());
01527 }
01528
01529 inline bool GoBoard::IsValidPoint(SgPoint p) const
01530 {
01531 return SgPointUtil::InBoardRange(p) && ! IsBorder(p);
01532 }
01533
01534 inline SgEmptyBlackWhite GoBoard::KoColor() const
01535 {
01536 return m_koColor;
01537 }
01538
01539 inline int GoBoard::KoLevel() const
01540 {
01541 return m_state.m_koLevel;
01542 }
01543
01544 inline SgEmptyBlackWhite GoBoard::KoLoser() const
01545 {
01546 return m_koLoser;
01547 }
01548
01549 inline bool GoBoard::KoModifiesHash() const
01550 {
01551 return m_koModifiesHash;
01552 }
01553
01554 inline SgPoint GoBoard::KoPoint() const
01555 {
01556 return m_state.m_koPoint;
01557 }
01558
01559 inline bool GoBoard::KoRepetitionAllowed() const
01560 {
01561 return m_allowKoRepetition;
01562 }
01563
01564 inline int GoBoard::LastBoardPoint() const
01565 {
01566 return m_const.LastBoardPoint();
01567 }
01568
01569 inline bool GoBoard::LastMoveInfo(GoMoveInfoFlag flag) const
01570 {
01571 return m_moveInfo.test(flag);
01572 }
01573
01574 inline int GoBoard::Left(SgPoint p) const
01575 {
01576 return m_const.Left(p);
01577 }
01578
01579 inline SgGrid GoBoard::Line(SgPoint p) const
01580 {
01581 return m_const.Line(p);
01582 }
01583
01584 inline const SgPointSet& GoBoard::LineSet(SgGrid line) const
01585 {
01586 return m_const.LineSet(line);
01587 }
01588
01589 inline int GoBoard::MoveNumber() const
01590 {
01591 return m_moves->Length();
01592 }
01593
01594 inline int GoBoard::Num8Neighbors(SgPoint p, int c) const
01595 {
01596 return NumNeighbors(p, c) + NumDiagonals(p, c);
01597 }
01598
01599 inline int GoBoard::Num8EmptyNeighbors(SgPoint p) const
01600 {
01601 return NumEmptyNeighbors(p) + NumEmptyDiagonals(p);
01602 }
01603
01604 inline int GoBoard::NuCapturedStones() const
01605 {
01606 return m_capturedStones.Length();
01607 }
01608
01609 inline int GoBoard::NumDiagonals(SgPoint p, SgBoardColor c) const
01610 {
01611 int n = 0;
01612 if (IsColor(p - SG_NS - SG_WE, c))
01613 ++n;
01614 if (IsColor(p - SG_NS + SG_WE, c))
01615 ++n;
01616 if (IsColor(p + SG_NS - SG_WE, c))
01617 ++n;
01618 if (IsColor(p + SG_NS + SG_WE, c))
01619 ++n;
01620 return n;
01621 }
01622
01623 inline int GoBoard::NumEmptyDiagonals(SgPoint p) const
01624 {
01625 return NumDiagonals(p, SG_EMPTY);
01626 }
01627
01628 inline int GoBoard::NumEmptyNeighbors(SgPoint p) const
01629 {
01630 return m_state.m_nuNeighborsEmpty[p];
01631 }
01632
01633 inline int GoBoard::NumLiberties(SgPoint p) const
01634 {
01635 SG_ASSERT(IsValidPoint(p));
01636 SG_ASSERT(Occupied(p));
01637 return m_state.m_block[p]->NumLiberties();
01638 }
01639
01640 inline int GoBoard::NumNeighbors(SgPoint p, SgBlackWhite c) const
01641 {
01642 return m_state.m_nuNeighbors[c][p];
01643 }
01644
01645 inline int GoBoard::NumPrisoners(SgBlackWhite color) const
01646 {
01647 return m_state.m_prisoners[color];
01648 }
01649
01650 inline int GoBoard::NumStones(SgPoint block) const
01651 {
01652 SG_ASSERT(Occupied(block));
01653 return m_state.m_block[block]->NumStones();
01654 }
01655
01656 inline SgPointSet GoBoard::Occupied() const
01657 {
01658 return m_state.m_all[SG_BLACK] | m_state.m_all[SG_WHITE];
01659 }
01660
01661 inline bool GoBoard::Occupied(SgPoint p) const
01662 {
01663 return (m_state.m_block[p] != 0);
01664 }
01665
01666 inline bool GoBoard::OccupiedInAtari(SgPoint p) const
01667 {
01668 const Block* b = m_state.m_block[p];
01669 return (b != 0 && b->NumLiberties() <= 1);
01670 }
01671
01672 inline bool GoBoard::OnEdge(SgPoint p) const
01673 {
01674 return Edges()[p];
01675 }
01676
01677 inline SgBlackWhite GoBoard::Opponent() const
01678 {
01679 return SgOppBW(m_state.m_toPlay);
01680 }
01681
01682 inline void GoBoard::Play(GoPlayerMove move)
01683 {
01684 Play(move.Point(), move.Color());
01685 }
01686
01687 inline void GoBoard::Play(SgPoint p)
01688 {
01689 Play(p, ToPlay());
01690 }
01691
01692 inline SgGrid GoBoard::Pos(SgPoint p) const
01693 {
01694 return m_const.Pos(p);
01695 }
01696
01697 inline int GoBoard::Right(SgPoint p) const
01698 {
01699 return m_const.Right(p);
01700 }
01701
01702 inline GoRules& GoBoard::Rules()
01703 {
01704 return m_rules;
01705 }
01706
01707 inline const GoRules& GoBoard::Rules() const
01708 {
01709 return m_rules;
01710 }
01711
01712 inline void GoBoard::SetKoLoser(SgEmptyBlackWhite color)
01713 {
01714 SG_ASSERT(KoLevel() == 0);
01715 m_koLoser = color;
01716 }
01717
01718 inline void GoBoard::SetKoModifiesHash(bool modify)
01719 {
01720 m_koModifiesHash = modify;
01721 }
01722
01723 inline void GoBoard::SetToPlay(SgBlackWhite player)
01724 {
01725 SG_ASSERT_BW(player);
01726 m_state.m_toPlay = player;
01727 }
01728
01729 inline const GoSetup& GoBoard::Setup() const
01730 {
01731 return m_setup;
01732 }
01733
01734 inline int GoBoard::Side(SgPoint p, int index) const
01735 {
01736 return m_const.Side(p, index);
01737 }
01738
01739 inline const SgPointSet& GoBoard::SideExtensions() const
01740 {
01741 return m_const.SideExtensions();
01742 }
01743
01744 inline SgGrid GoBoard::Size() const
01745 {
01746 return m_size;
01747 }
01748
01749 inline SgPoint GoBoard::TheLiberty(SgPoint p) const
01750 {
01751 SG_ASSERT(Occupied(p));
01752 SG_ASSERT(NumLiberties(p) == 1);
01753 return m_state.m_block[p]->Liberties()[0];
01754 }
01755
01756 inline SgBlackWhite GoBoard::ToPlay() const
01757 {
01758 return m_state.m_toPlay;
01759 }
01760
01761 inline int GoBoard::TotalNumEmpty() const
01762 {
01763 return (Size() * Size() - m_state.m_numStones[SG_BLACK]
01764 - m_state.m_numStones[SG_WHITE]);
01765 }
01766
01767 inline const SgBWArray<int>& GoBoard::TotalNumStones() const
01768 {
01769 return m_state.m_numStones;
01770 }
01771
01772 inline int GoBoard::TotalNumStones(SgBlackWhite color) const
01773 {
01774 return m_state.m_numStones[color];
01775 }
01776
01777 inline int GoBoard::Up(SgPoint p) const
01778 {
01779 return m_const.Up(p);
01780 }
01781
01782
01783
01784 #endif // GO_BOARD_H
01785