Improve automatic move.
This commit is contained in:
parent
00a105dd4a
commit
d3a238fbd4
@ -62,6 +62,19 @@ GAME.Board = class {
|
||||
}
|
||||
}
|
||||
|
||||
clone() {
|
||||
let board = new GAME.Board();
|
||||
for(let i = 0; i < this.tiles.length; ++i) { board.tiles[i] = this.tiles[i].clone(); }
|
||||
for(let i = 0; i < this.pieces.length; ++i) {
|
||||
if(this.pieces[i] !== null) {
|
||||
board.pieces[i] = this.pieces[i].clone();
|
||||
} else {
|
||||
board.pieces[i] = null;
|
||||
}
|
||||
}
|
||||
return board;
|
||||
}
|
||||
|
||||
set_piece(piece, player, tile) {
|
||||
let index = 0;
|
||||
while(this.pieces[index] !== null) { index++; }
|
||||
@ -84,6 +97,12 @@ GAME.Pool = class {
|
||||
constructor() {
|
||||
this.pieces = [ ]; for(let i = 0; i < 7; ++i) { this.pieces.push(0); }
|
||||
}
|
||||
|
||||
clone() {
|
||||
let pool = new GAME.Pool();
|
||||
for(let i = 0; i < pool.pieces.length; ++i) { pool.pieces[i] = this.pieces[i]; }
|
||||
return pool;
|
||||
}
|
||||
};
|
||||
|
||||
GAME.Column = class {
|
||||
@ -108,6 +127,13 @@ GAME.Tile = class {
|
||||
this.hex = HEX.tile_to_hex(index);
|
||||
}
|
||||
|
||||
clone() {
|
||||
let tile = new GAME.Tile(0);
|
||||
tile.piece = this.piece;
|
||||
tile.hex = this.hex;
|
||||
return tile;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.threaten = [0, 0];
|
||||
this.checking = false;
|
||||
@ -175,6 +201,13 @@ GAME.Piece = class {
|
||||
this.blocking = 0;
|
||||
}
|
||||
|
||||
clone() {
|
||||
let piece = new GAME.Piece(this.piece, this.player);
|
||||
piece.promoted = this.promoted;
|
||||
piece.tile = this.tile;
|
||||
return piece;
|
||||
}
|
||||
|
||||
moves() {
|
||||
let def = GAME.Const.Piece[this.piece];
|
||||
let moves = null;
|
||||
@ -212,6 +245,17 @@ GAME.Game = class {
|
||||
this.update_board();
|
||||
}
|
||||
|
||||
clone() {
|
||||
let game = new GAME.Game();
|
||||
|
||||
game.turn = this.turn;
|
||||
game.board = this.board.clone();
|
||||
game.pools = [ this.pools[0].clone(), this.pools[1].clone() ];
|
||||
|
||||
game.update_board();
|
||||
return game;
|
||||
}
|
||||
|
||||
update_board() {
|
||||
// Reset tiles
|
||||
this.board.reset();
|
||||
@ -447,7 +491,7 @@ GAME.Game = class {
|
||||
if(pieces_blocking == 1) {
|
||||
// Apply blocking to last .
|
||||
for(let idist = 1; idist < dist; idist++) {
|
||||
if(GAME_DATA.board.tiles[tiles[tiles.length - idist].tile].piece !== null) {
|
||||
if(this.board.tiles[tiles[tiles.length - idist].tile].piece !== null) {
|
||||
tiles[tiles.length - idist].block = mask;
|
||||
break;
|
||||
}
|
||||
|
@ -789,8 +789,6 @@ const INTERFACE = {
|
||||
GAME_DATA.turn = data.turn;
|
||||
INTERFACE_DATA.play = data.play;
|
||||
|
||||
console.log(data.play.source);
|
||||
|
||||
if(INTERFACE_DATA.play.source == 2) {
|
||||
GAME_DATA.state.code = 2;
|
||||
}
|
||||
@ -912,105 +910,146 @@ const INTERFACE = {
|
||||
},
|
||||
|
||||
auto() {
|
||||
let moves = [ ];
|
||||
let player = GAME_DATA.turn & 1;
|
||||
let opponent = +(!player);
|
||||
function state_score(state, player) {
|
||||
let score = 0;
|
||||
let opponent = player ^ 1;
|
||||
let turn = (state.turn & 1);
|
||||
|
||||
// Get available placement moves.
|
||||
for(let p = 0; p < 8; ++p) {
|
||||
if(GAME_DATA.pools[player].pieces[p] > 0) {
|
||||
for(let move of GAME_DATA.placement_tiles(p, player)) {
|
||||
if(move.valid) {
|
||||
let hex = HEX.tile_to_hex(move.tile);
|
||||
for(let i = 0; i < state.board.tiles.length; ++i) {
|
||||
let tile = state.board.tiles[i];
|
||||
score += (tile.threaten[player] - tile.threaten[opponent]) / 2;
|
||||
}
|
||||
|
||||
let score = GAME_DATA.board.tiles[move.tile].threaten[player] - GAME_DATA.board.tiles[move.tile].threaten[opponent];
|
||||
if(player == 0) {
|
||||
score += 2 * Math.max(0, GAME_DATA.board.columns[hex.x].extent[player] - hex.y);
|
||||
} else {
|
||||
score += 2 * Math.max(0, hex.y - GAME_DATA.board.columns[hex.x].extent[player]);
|
||||
}
|
||||
|
||||
let moves_from = GAME_DATA.movement_tiles(new GAME.Piece(p, player), move.tile);
|
||||
for(let next_move of moves_from) {
|
||||
if(next_move.valid) {
|
||||
// Add score for taking.
|
||||
let target_id = GAME_DATA.board.tiles[next_move.tile].piece;
|
||||
if(target_id !== null) {
|
||||
let target = GAME_DATA.board.pieces[target_id];
|
||||
if(target.player == opponent) { score += (1 + target.piece) * (1 + target.promoted); }
|
||||
}
|
||||
|
||||
if(next_move.check) { score += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
moves.push({
|
||||
score: score,
|
||||
play: new GAME.Play(1, p, move.tile),
|
||||
});
|
||||
for(let i = 0; i < state.board.pieces.length; ++i) {
|
||||
let piece_id = state.board.pieces[i];
|
||||
if(piece_id !== null) {
|
||||
let piece = state.board.pieces[i];
|
||||
let tile = state.board.tiles[piece.tile];
|
||||
|
||||
if(piece.player == player) {
|
||||
score += 1 + (4 * piece.piece) + (4 * (piece.promoted + 1));
|
||||
score += (1 + piece.piece) * (tile.threaten[player] - tile.threaten[opponent]);
|
||||
} else {
|
||||
score -= 1 + (3 * piece.piece) + (4 * (piece.promoted + 1));
|
||||
score -= (1 + piece.piece) * (tile.threaten[opponent] - tile.threaten[player]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(let i = 0; i < state.pools[player].pieces.length; ++i) {
|
||||
score += 2 * state.pools[player].pieces[i];
|
||||
}
|
||||
for(let i = 0; i < state.pools[opponent].pieces.length; ++i) {
|
||||
score -= 2 * state.pools[opponent].pieces[i];
|
||||
}
|
||||
|
||||
for(let i = 0; i < state.board.columns.length; ++i) {
|
||||
let column = state.board.columns[i];
|
||||
if(player == 0) {
|
||||
score += column.extent[player] / 8;
|
||||
score -= (8 - column.extent[opponent]) / 8;
|
||||
} else {
|
||||
score += (8 - column.extent[player]) / 8;
|
||||
score -= column.extent[opponent] / 8;
|
||||
}
|
||||
}
|
||||
|
||||
if(state.state.check) {
|
||||
if(turn == player) { score -= 2; }
|
||||
else { score += 2; }
|
||||
}
|
||||
if(state.state.checkmate) {
|
||||
if(turn == player) { score -= 1000; }
|
||||
else { score += 1000; }
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
// Get available piece moves.
|
||||
for(let i = 0; i < GAME_DATA.board.pieces.length; ++i) {
|
||||
let piece = GAME_DATA.board.pieces[i];
|
||||
if(piece !== null) {
|
||||
if(piece.player == player) {
|
||||
let current_hex = HEX.tile_to_hex(piece.tile);
|
||||
|
||||
for(let move of GAME_DATA.movement_tiles(piece, piece.tile)) {
|
||||
function determine_play(state, search_player, depth) {
|
||||
let moves = [ ];
|
||||
let player = state.turn & 1;
|
||||
|
||||
// Get available placement moves.
|
||||
for(let p = 0; p < 8; ++p) {
|
||||
if(state.pools[player].pieces[p] > 0) {
|
||||
for(let move of state.placement_tiles(p, player)) {
|
||||
if(move.valid) {
|
||||
let hex = HEX.tile_to_hex(move.tile);
|
||||
|
||||
// Calculate base score.
|
||||
let score = ((piece.piece + 1) * (1 + piece.promoted) * GAME_DATA.board.tiles[piece.tile].threaten[opponent])
|
||||
+ GAME_DATA.board.tiles[move.tile].threaten[player]
|
||||
- ((piece.piece + 1) * GAME_DATA.board.tiles[move.tile].threaten[opponent]);
|
||||
|
||||
// Add score for taking.
|
||||
let target_id = GAME_DATA.board.tiles[move.tile].piece;
|
||||
if(target_id !== null) {
|
||||
let target = GAME_DATA.board.pieces[target_id];
|
||||
if(target.player == opponent) { score += (2 + target.piece) * (1 + target.promoted); }
|
||||
else { score -= 1; }
|
||||
}
|
||||
|
||||
score += +((-MATH.sign_branch(player) * (hex.y - current_hex.y)) > 0);
|
||||
|
||||
// Add score for check.
|
||||
if(move.check) { score += 1; }
|
||||
|
||||
let moves_from = GAME_DATA.movement_tiles(piece, move.tile);
|
||||
for(let next_move of moves_from) {
|
||||
if(next_move.valid) {
|
||||
// Add score for taking.
|
||||
let target_id = GAME_DATA.board.tiles[next_move.tile].piece;
|
||||
if(target_id !== null) {
|
||||
let target = GAME_DATA.board.pieces[target_id];
|
||||
if(target.player == opponent) { score += (1 + target.piece) * (1 + target.promoted); }
|
||||
}
|
||||
|
||||
if(next_move.check) { score += 1; }
|
||||
}
|
||||
}
|
||||
|
||||
moves.push({
|
||||
score: score,
|
||||
play: new GAME.Play(0, piece.tile, move.tile),
|
||||
score: 0,
|
||||
play: new GAME.Play(1, p, move.tile),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get available piece moves.
|
||||
for(let i = 0; i < state.board.pieces.length; ++i) {
|
||||
let piece = state.board.pieces[i];
|
||||
if(piece !== null) {
|
||||
if(piece.player == player) {
|
||||
for(let move of state.movement_tiles(piece, piece.tile)) {
|
||||
if(move.valid) {
|
||||
moves.push({
|
||||
score: 0,
|
||||
play: new GAME.Play(0, piece.tile, move.tile),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get move scores.
|
||||
for(let i = 0; i < moves.length; ++i) {
|
||||
let st = state.clone();
|
||||
st.process(moves[i].play);
|
||||
moves[i].score = state_score(st, player);
|
||||
}
|
||||
|
||||
// Select move.
|
||||
if(moves.length > 0) {
|
||||
moves.sort((a, b) => { return b.score - a.score });
|
||||
|
||||
if(depth == 0) {
|
||||
// Get move scores for search player.
|
||||
for(let i = 0; i < moves.length; ++i) {
|
||||
let st = state.clone();
|
||||
st.process(moves[i].play);
|
||||
moves[i].score = state_score(st, search_player);
|
||||
}
|
||||
} else {
|
||||
for(let i = 0; i < moves.length && i < 3; ++i) {
|
||||
let st = state.clone();
|
||||
st.process(moves[i].play);
|
||||
|
||||
let result = determine_play(st, search_player, depth - 1);
|
||||
if(result !== null) {
|
||||
moves[i].score = result.score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select random from ties.
|
||||
let selection = 0;
|
||||
for(let i = 1; i < moves.length; ++i) {
|
||||
if(moves[i].score == moves[i-1].score) {
|
||||
selection++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
selection = Math.min(moves.length, selection + 3);
|
||||
|
||||
return moves[Math.floor(Math.random() * selection)];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if(moves.length > 0) {
|
||||
moves = moves.sort((a, b) => { return b.score - a.score; });
|
||||
|
||||
let select = Math.floor(Math.random() * Math.min(moves.length, 2));
|
||||
INTERFACE.process(moves[select].play);
|
||||
let result = determine_play(GAME_DATA, GAME_DATA.turn & 1, 1);
|
||||
if(result !== null) {
|
||||
INTERFACE.process(result.play);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user