Skip to content

Commit

Permalink
Support 10/11 Men's Morris
Browse files Browse the repository at this point in the history
Qt: Set default rule as 9nm.
  • Loading branch information
calcitem committed Jun 5, 2021
1 parent cbf88ae commit a350fd9
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 89 deletions.
2 changes: 1 addition & 1 deletion include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

//#define DEBUG_MODE

#define DEFAULT_RULE_NUMBER 1
#define DEFAULT_RULE_NUMBER 2

#define DEPTH_ADJUST (0)

Expand Down
3 changes: 0 additions & 3 deletions src/bitboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ extern uint8_t PopCnt16[1 << 16];

extern Bitboard SquareBB[SQ_32];

extern Bitboard StarSquareBB9;
extern Bitboard StarSquareBB12;

inline Bitboard square_bb(Square s) noexcept
{
if (!(SQ_BEGIN <= s && s < SQ_END))
Expand Down
10 changes: 5 additions & 5 deletions src/mills.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,16 +502,16 @@ Depth get_search_depth(const Position *pos)
if (pos->phase == Phase::placing) {
const int index = rule.piecesCount * 2 - pos->count<IN_HAND>(WHITE) - pos->count<IN_HAND>(BLACK);

if (rule.piecesCount == 12) {
assert(0 <= index && index <= 24);
if (rule.piecesCount == 9) {
assert(0 <= index && index <= 19);
d = placingDepthTable_9[index];
} else {
assert(0 <= index && index <= rule.piecesCount * 2);
if (!rule.hasBannedLocations && !rule.hasDiagonalLines) {
d = placingDepthTable_12_special[index];
} else {
d = placingDepthTable_12[index];
}
} else {
assert(0 <= index && index <= 19);
d = placingDepthTable_9[index];
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/movepick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void MovePicker::score()

//cur->value += bannedCount; // placing phrase, place nearby ban point

// for 12 men's morris (has diagonal), black 2nd move place star point is as important as close mill (TODO)
// If has Diagonal Lines, black 2nd move place star point is as important as close mill (TODO)
if (rule.hasDiagonalLines &&
pos.count<ON_BOARD>(BLACK) < 2 && // patch: only when black 2nd move
Position::is_star_square(static_cast<Square>(m))) {
Expand Down
2 changes: 1 addition & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class Position
Piece board[SQUARE_NB];
Bitboard byTypeBB[PIECE_TYPE_NB];
Bitboard byColorBB[COLOR_NB];
int pieceInHandCount[COLOR_NB] { 0, 12, 12 };
int pieceInHandCount[COLOR_NB] { 0, 9, 9 };
int pieceOnBoardCount[COLOR_NB] { 0, 0, 0 };
int pieceToRemoveCount{ 0 };
int gamePly { 0 };
Expand Down
21 changes: 8 additions & 13 deletions src/rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,19 @@
#include "rule.h"

struct Rule rule = {
"打三棋(12连棋)", // 打三棋
"Nine men's morris", // 莫里斯九子棋
// 规则说明
"1. 双方各12颗子,棋盘有斜线;\n"
"2. 摆棋阶段被提子的位置不能再摆子,直到走棋阶段;\n"
"3. 摆棋阶段,摆满棋盘算先手负;\n"
"4. 走棋阶段,后摆棋的一方先走;\n"
"5. 同时出现两个“三连”只能提一子;\n"
"6. 其它规则与成三棋基本相同。",
12, // 双方各12子
"规则与成三棋基本相同,只是在走子阶段,当一方仅剩3子时,他可以飞子到任意空位。",
9, // 双方各9子
3, // 赛点子数为3
true, // 有斜线
true, // 有禁点,摆棋阶段被提子的点不能再摆子
true, // 后摆棋者先行棋
false, // 没有斜线
false, // 没有禁点,摆棋阶段被提子的点可以再摆子
false, // 先摆棋者先行棋
false, // 多个“三连”只能提一子
true, // 可以提对手的“三连”子
false, // 不能提对手的“三连”子,除非无子可提;
true, // 摆棋满子(闷棋,只有12子棋才出现)算先手负
true, // 走棋阶段不能行动(被“闷”)算负
false, // 剩三子时不可以飞棋
true, // 剩三子时可以飞棋
99 // 99半步即50回合
};

Expand Down
21 changes: 18 additions & 3 deletions src/uci.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ namespace
{

// FEN string of the initial position, normal mill game
const char *StartFEN9 = "********/********/******** w p p 0 9 0 9 0 0 1";
const char *StartFEN10 = "********/********/******** w p p 0 10 0 10 0 0 1";
const char *StartFEN11 = "********/********/******** w p p 0 11 0 11 0 0 1";
const char *StartFEN12 = "********/********/******** w p p 0 12 0 12 0 0 1";
const char *StartFEN9 = "********/********/******** w p p 0 9 0 9 0 0 1";

char StartFEN[BUFSIZ];

// position() is called when engine receives the "position" UCI command.
Expand Down Expand Up @@ -157,10 +160,22 @@ void UCI::loop(int argc, char *argv[])
Position *pos = new Position;
string token, cmd;

if (rule.piecesCount == 9) {
switch (rule.piecesCount) {
case 9:
strncpy(StartFEN, StartFEN9, BUFSIZ);
} else if (rule.piecesCount == 12) {
break;
case 10:
strncpy(StartFEN, StartFEN10, BUFSIZ);
break;
case 11:
strncpy(StartFEN, StartFEN11, BUFSIZ);
break;
case 12:
strncpy(StartFEN, StartFEN12, BUFSIZ);
break;
default:
assert(0);
break;
}

pos->set(StartFEN, Threads.main());
Expand Down
12 changes: 6 additions & 6 deletions src/ucioption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,16 @@ void init(OptionsMap &o)
o["DeveloperMode"] << Option(true, on_developerMode);

// Rules
o["PiecesCount"] << Option(12, 6, 12, on_piecesCount);
o["PiecesCount"] << Option(9, 9, 12, on_piecesCount);
o["PiecesAtLeastCount"] << Option(3, 3, 5, on_piecesAtLeastCount);
o["HasDiagonalLines"] << Option(true, on_hasDiagonalLines);
o["HasBannedLocations"] << Option(true, on_hasBannedLocations);
o["IsDefenderMoveFirst"] << Option(true, on_isDefenderMoveFirst);
o["HasDiagonalLines"] << Option(false, on_hasDiagonalLines);
o["HasBannedLocations"] << Option(false, on_hasBannedLocations);
o["IsDefenderMoveFirst"] << Option(false, on_isDefenderMoveFirst);
o["MayRemoveMultiple"] << Option(false, on_mayRemoveMultiple);
o["MayRemoveFromMillsAlways"] << Option(true, on_mayRemoveFromMillsAlways);
o["MayRemoveFromMillsAlways"] << Option(false, on_mayRemoveFromMillsAlways);
o["IsWhiteLoseButNotDrawWhenBoardFull"] << Option(true, on_isWhiteLoseButNotDrawWhenBoardFull);
o["IsLoseButNotChangeSideWhenNoWay"] << Option(true, on_isLoseButNotChangeSideWhenNoWay);
o["MayFly"] << Option(false, on_mayFly);
o["MayFly"] << Option(true, on_mayFly);
o["MaxStepsLedToDraw"] << Option(50, 30, 50, on_maxStepsLedToDraw);

}
Expand Down
108 changes: 54 additions & 54 deletions src/ui/flutter_app/lib/mill/mills.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,7 @@ import 'rule.dart';
class Mills {
static void adjacentSquaresInit() {
// Note: Not follow order of MoveDirection array
const adjacentSquares12 = [
/* 0 */ [0, 0, 0, 0],
/* 1 */ [0, 0, 0, 0],
/* 2 */ [0, 0, 0, 0],
/* 3 */ [0, 0, 0, 0],
/* 4 */ [0, 0, 0, 0],
/* 5 */ [0, 0, 0, 0],
/* 6 */ [0, 0, 0, 0],
/* 7 */ [0, 0, 0, 0],

/* 8 */ [9, 15, 16, 0],
/* 9 */ [17, 8, 10, 0],
/* 10 */ [9, 11, 18, 0],
/* 11 */ [19, 10, 12, 0],
/* 12 */ [11, 13, 20, 0],
/* 13 */ [21, 12, 14, 0],
/* 14 */ [13, 15, 22, 0],
/* 15 */ [23, 8, 14, 0],

/* 16 */ [17, 23, 8, 24],
/* 17 */ [9, 25, 16, 18],
/* 18 */ [17, 19, 10, 26],
/* 19 */ [11, 27, 18, 20],
/* 20 */ [19, 21, 12, 28],
/* 21 */ [13, 29, 20, 22],
/* 22 */ [21, 23, 14, 30],
/* 23 */ [15, 31, 16, 22],

/* 24 */ [25, 31, 16, 0],
/* 25 */ [17, 24, 26, 0],
/* 26 */ [25, 27, 18, 0],
/* 27 */ [19, 26, 28, 0],
/* 28 */ [27, 29, 20, 0],
/* 29 */ [21, 28, 30, 0],
/* 30 */ [29, 31, 22, 0],
/* 31 */ [23, 24, 30, 0],

/* 32 */ [0, 0, 0, 0],
/* 33 */ [0, 0, 0, 0],
/* 34 */ [0, 0, 0, 0],
/* 35 */ [0, 0, 0, 0],
/* 36 */ [0, 0, 0, 0],
/* 37 */ [0, 0, 0, 0],
/* 38 */ [0, 0, 0, 0],
/* 39 */ [0, 0, 0, 0],
];

const adjacentSquares9 = [
const adjacentSquares = [
/* 0 */ [0, 0, 0, 0],
/* 1 */ [0, 0, 0, 0],
/* 2 */ [0, 0, 0, 0],
Expand Down Expand Up @@ -116,15 +69,62 @@ class Mills {
/* 39 */ [0, 0, 0, 0],
];

const adjacentSquares_diagonal = [
/* 0 */ [0, 0, 0, 0],
/* 1 */ [0, 0, 0, 0],
/* 2 */ [0, 0, 0, 0],
/* 3 */ [0, 0, 0, 0],
/* 4 */ [0, 0, 0, 0],
/* 5 */ [0, 0, 0, 0],
/* 6 */ [0, 0, 0, 0],
/* 7 */ [0, 0, 0, 0],

/* 8 */ [9, 15, 16, 0],
/* 9 */ [17, 8, 10, 0],
/* 10 */ [9, 11, 18, 0],
/* 11 */ [19, 10, 12, 0],
/* 12 */ [11, 13, 20, 0],
/* 13 */ [21, 12, 14, 0],
/* 14 */ [13, 15, 22, 0],
/* 15 */ [23, 8, 14, 0],

/* 16 */ [17, 23, 8, 24],
/* 17 */ [9, 25, 16, 18],
/* 18 */ [17, 19, 10, 26],
/* 19 */ [11, 27, 18, 20],
/* 20 */ [19, 21, 12, 28],
/* 21 */ [13, 29, 20, 22],
/* 22 */ [21, 23, 14, 30],
/* 23 */ [15, 31, 16, 22],

/* 24 */ [25, 31, 16, 0],
/* 25 */ [17, 24, 26, 0],
/* 26 */ [25, 27, 18, 0],
/* 27 */ [19, 26, 28, 0],
/* 28 */ [27, 29, 20, 0],
/* 29 */ [21, 28, 30, 0],
/* 30 */ [29, 31, 22, 0],
/* 31 */ [23, 24, 30, 0],

/* 32 */ [0, 0, 0, 0],
/* 33 */ [0, 0, 0, 0],
/* 34 */ [0, 0, 0, 0],
/* 35 */ [0, 0, 0, 0],
/* 36 */ [0, 0, 0, 0],
/* 37 */ [0, 0, 0, 0],
/* 38 */ [0, 0, 0, 0],
/* 39 */ [0, 0, 0, 0],
];

if (rule.hasDiagonalLines) {
Position.adjacentSquares = adjacentSquares12;
Position.adjacentSquares = adjacentSquares_diagonal;
} else {
Position.adjacentSquares = adjacentSquares9;
Position.adjacentSquares = adjacentSquares;
}
}

static void millTableInit() {
const millTable9 = [
const millTable = [
/* 0 */ [
[0, 0],
[0, 0],
Expand Down Expand Up @@ -331,7 +331,7 @@ class Mills {
]
];

const millTable12 = [
const millTable_diagonal = [
/* 0 */ [
[0, 0],
[0, 0],
Expand Down Expand Up @@ -539,9 +539,9 @@ class Mills {
];

if (rule.hasDiagonalLines) {
Position.millTable = millTable12;
Position.millTable = millTable_diagonal;
} else {
Position.millTable = millTable9;
Position.millTable = millTable;
}
}
}
11 changes: 11 additions & 0 deletions src/ui/flutter_app/lib/mill/position.dart
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,17 @@ class Position {
setSideToMove(PieceColor.opponent(_sideToMove));
st.key ^= Zobrist.side;
print("[position] $_sideToMove to move.");

/*
if (phase == Phase.moving &&
!rule.isLoseButNotChangeSideWhenNoWay &&
isAllSurrounded() &&
!rule.mayFly &&
pieceOnBoardCount[sideToMove()]! >= rule.piecesAtLeastCount) {
print("[position] $_sideToMove is no way to go.");
changeSideToMove();
}
*/
}

int updateKey(int s) {
Expand Down
6 changes: 5 additions & 1 deletion src/ui/flutter_app/lib/widgets/game_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class _GamePageState extends State<GamePage>
return;
}

// If nobody has placed, start to go.

// TODO
// WAR: Fix first tap response slow when piece count changed
if (position.phase == Phase.placing &&
Expand Down Expand Up @@ -233,6 +235,8 @@ class _GamePageState extends State<GamePage>
Game.instance.start();
}

// Human to go

bool ret = false;
Chain.capture(() {
switch (position.action) {
Expand Down Expand Up @@ -431,7 +435,7 @@ class _GamePageState extends State<GamePage>
Game.instance.sideToMove = position.sideToMove() ?? PieceColor.nobody;

setState(() {});
});
}); // Chain.capture

return ret;
}
Expand Down
18 changes: 17 additions & 1 deletion src/ui/flutter_app/lib/widgets/rule_settings_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
context: context,
titleString: S.of(context).piecesCount,
subtitleString: S.of(context).piecesCount_Detail,
trailingString: Config.piecesCount == 9 ? '9' : '12',
trailingString: Config.piecesCount.toString(),
onTap: setNTotalPiecesEachSide,
),
ListItemDivider(),
Expand Down Expand Up @@ -197,6 +197,22 @@ class _RuleSettingsPageState extends State<RuleSettingsPage> {
onChanged: callback,
),
ListItemDivider(),
RadioListTile(
activeColor: AppTheme.switchListTileActiveColor,
title: Text('10'),
groupValue: Config.piecesCount,
value: 10,
onChanged: callback,
),
ListItemDivider(),
RadioListTile(
activeColor: AppTheme.switchListTileActiveColor,
title: Text('11'),
groupValue: Config.piecesCount,
value: 11,
onChanged: callback,
),
ListItemDivider(),
RadioListTile(
activeColor: AppTheme.switchListTileActiveColor,
title: Text('12'),
Expand Down

0 comments on commit a350fd9

Please sign in to comment.