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) {
|
set_piece(piece, player, tile) {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
while(this.pieces[index] !== null) { index++; }
|
while(this.pieces[index] !== null) { index++; }
|
||||||
@ -84,6 +97,12 @@ GAME.Pool = class {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.pieces = [ ]; for(let i = 0; i < 7; ++i) { this.pieces.push(0); }
|
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 {
|
GAME.Column = class {
|
||||||
@ -108,6 +127,13 @@ GAME.Tile = class {
|
|||||||
this.hex = HEX.tile_to_hex(index);
|
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() {
|
reset() {
|
||||||
this.threaten = [0, 0];
|
this.threaten = [0, 0];
|
||||||
this.checking = false;
|
this.checking = false;
|
||||||
@ -175,6 +201,13 @@ GAME.Piece = class {
|
|||||||
this.blocking = 0;
|
this.blocking = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clone() {
|
||||||
|
let piece = new GAME.Piece(this.piece, this.player);
|
||||||
|
piece.promoted = this.promoted;
|
||||||
|
piece.tile = this.tile;
|
||||||
|
return piece;
|
||||||
|
}
|
||||||
|
|
||||||
moves() {
|
moves() {
|
||||||
let def = GAME.Const.Piece[this.piece];
|
let def = GAME.Const.Piece[this.piece];
|
||||||
let moves = null;
|
let moves = null;
|
||||||
@ -212,6 +245,17 @@ GAME.Game = class {
|
|||||||
this.update_board();
|
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() {
|
update_board() {
|
||||||
// Reset tiles
|
// Reset tiles
|
||||||
this.board.reset();
|
this.board.reset();
|
||||||
@ -447,7 +491,7 @@ GAME.Game = class {
|
|||||||
if(pieces_blocking == 1) {
|
if(pieces_blocking == 1) {
|
||||||
// Apply blocking to last .
|
// Apply blocking to last .
|
||||||
for(let idist = 1; idist < dist; idist++) {
|
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;
|
tiles[tiles.length - idist].block = mask;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -789,8 +789,6 @@ const INTERFACE = {
|
|||||||
GAME_DATA.turn = data.turn;
|
GAME_DATA.turn = data.turn;
|
||||||
INTERFACE_DATA.play = data.play;
|
INTERFACE_DATA.play = data.play;
|
||||||
|
|
||||||
console.log(data.play.source);
|
|
||||||
|
|
||||||
if(INTERFACE_DATA.play.source == 2) {
|
if(INTERFACE_DATA.play.source == 2) {
|
||||||
GAME_DATA.state.code = 2;
|
GAME_DATA.state.code = 2;
|
||||||
}
|
}
|
||||||
@ -912,40 +910,73 @@ const INTERFACE = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
auto() {
|
auto() {
|
||||||
|
function state_score(state, player) {
|
||||||
|
let score = 0;
|
||||||
|
let opponent = player ^ 1;
|
||||||
|
let turn = (state.turn & 1);
|
||||||
|
|
||||||
|
for(let i = 0; i < state.board.tiles.length; ++i) {
|
||||||
|
let tile = state.board.tiles[i];
|
||||||
|
score += (tile.threaten[player] - tile.threaten[opponent]) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function determine_play(state, search_player, depth) {
|
||||||
let moves = [ ];
|
let moves = [ ];
|
||||||
let player = GAME_DATA.turn & 1;
|
let player = state.turn & 1;
|
||||||
let opponent = +(!player);
|
|
||||||
|
|
||||||
// Get available placement moves.
|
// Get available placement moves.
|
||||||
for(let p = 0; p < 8; ++p) {
|
for(let p = 0; p < 8; ++p) {
|
||||||
if(GAME_DATA.pools[player].pieces[p] > 0) {
|
if(state.pools[player].pieces[p] > 0) {
|
||||||
for(let move of GAME_DATA.placement_tiles(p, player)) {
|
for(let move of state.placement_tiles(p, player)) {
|
||||||
if(move.valid) {
|
if(move.valid) {
|
||||||
let hex = HEX.tile_to_hex(move.tile);
|
|
||||||
|
|
||||||
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({
|
moves.push({
|
||||||
score: score,
|
score: 0,
|
||||||
play: new GAME.Play(1, p, move.tile),
|
play: new GAME.Play(1, p, move.tile),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -954,50 +985,14 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get available piece moves.
|
// Get available piece moves.
|
||||||
for(let i = 0; i < GAME_DATA.board.pieces.length; ++i) {
|
for(let i = 0; i < state.board.pieces.length; ++i) {
|
||||||
let piece = GAME_DATA.board.pieces[i];
|
let piece = state.board.pieces[i];
|
||||||
if(piece !== null) {
|
if(piece !== null) {
|
||||||
if(piece.player == player) {
|
if(piece.player == player) {
|
||||||
let current_hex = HEX.tile_to_hex(piece.tile);
|
for(let move of state.movement_tiles(piece, piece.tile)) {
|
||||||
|
|
||||||
for(let move of GAME_DATA.movement_tiles(piece, piece.tile)) {
|
|
||||||
if(move.valid) {
|
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({
|
moves.push({
|
||||||
score: score,
|
score: 0,
|
||||||
play: new GAME.Play(0, piece.tile, move.tile),
|
play: new GAME.Play(0, piece.tile, move.tile),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1006,11 +1001,55 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(moves.length > 0) {
|
// Get move scores.
|
||||||
moves = moves.sort((a, b) => { return b.score - a.score; });
|
for(let i = 0; i < moves.length; ++i) {
|
||||||
|
let st = state.clone();
|
||||||
|
st.process(moves[i].play);
|
||||||
|
moves[i].score = state_score(st, player);
|
||||||
|
}
|
||||||
|
|
||||||
let select = Math.floor(Math.random() * Math.min(moves.length, 2));
|
// Select move.
|
||||||
INTERFACE.process(moves[select].play);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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