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