Add simple auto move to practice.
This commit is contained in:
parent
6d22410658
commit
f74396f257
@ -102,14 +102,14 @@ GAME.Tile = class {
|
|||||||
constructor(index) {
|
constructor(index) {
|
||||||
this.piece = null;
|
this.piece = null;
|
||||||
|
|
||||||
this.threaten = [false, false];
|
this.threaten = [0, 0];
|
||||||
this.checking = false;
|
this.checking = false;
|
||||||
|
|
||||||
this.hex = HEX.tile_to_hex(index);
|
this.hex = HEX.tile_to_hex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.threaten = [false, false];
|
this.threaten = [0, 0];
|
||||||
this.checking = false;
|
this.checking = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -236,7 +236,7 @@ GAME.Game = class {
|
|||||||
// Get threatened tiles.
|
// Get threatened tiles.
|
||||||
for(let movement of this.movement_tiles(piece, piece.tile)) {
|
for(let movement of this.movement_tiles(piece, piece.tile)) {
|
||||||
if(movement.threat) {
|
if(movement.threat) {
|
||||||
this.board.tiles[movement.tile].threaten[piece.player] = true;
|
this.board.tiles[movement.tile].threaten[piece.player] += 1;
|
||||||
}
|
}
|
||||||
if(movement.check) {
|
if(movement.check) {
|
||||||
this.board.tiles[piece.tile].checking = true;
|
this.board.tiles[piece.tile].checking = true;
|
||||||
@ -408,7 +408,7 @@ GAME.Game = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// King may not move onto threatened tile.
|
// King may not move onto threatened tile.
|
||||||
if(piece.piece == GAME.Const.PieceId.Omen && tile_data.threaten[+(!piece.player)]) {
|
if(piece.piece == GAME.Const.PieceId.Omen && tile_data.threaten[+(!piece.player)] > 0) {
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,7 +490,7 @@ GAME.Game = class {
|
|||||||
// King cannot swap onto tile that is threatened.
|
// King cannot swap onto tile that is threatened.
|
||||||
// This case should also cover blocking.
|
// This case should also cover blocking.
|
||||||
if(target.piece == GAME.Const.PieceId.Omen
|
if(target.piece == GAME.Const.PieceId.Omen
|
||||||
&& (this.board.tiles[tile].threaten[+(!target.player)] || piece.blocking != 0)) {
|
&& (this.board.tiles[tile].threaten[+(!target.player)] > 0 || piece.blocking != 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return ((moves.direction & mask) != 0 && (range == 1 || (moves.stride & mask) != 0));
|
return ((moves.direction & mask) != 0 && (range == 1 || (moves.stride & mask) != 0));
|
||||||
|
@ -87,7 +87,7 @@ const INTERFACE = {
|
|||||||
if(movement.valid) {
|
if(movement.valid) {
|
||||||
// Show valid/threat hints if piece belongs to player and is player turn.
|
// Show valid/threat hints if piece belongs to player and is player turn.
|
||||||
if(INTERFACE_DATA.player == 2 || (player == INTERFACE_DATA.player && (GAME_DATA.turn & 1) == player)) {
|
if(INTERFACE_DATA.player == 2 || (player == INTERFACE_DATA.player && (GAME_DATA.turn & 1) == player)) {
|
||||||
if(GAME_DATA.board.tiles[movement.tile].threaten[+(!player)]) {
|
if(GAME_DATA.board.tiles[movement.tile].threaten[+(!player)] > 0) {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Threat;
|
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Threat;
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
||||||
@ -200,39 +200,8 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Handle player action.
|
// Handle player action.
|
||||||
if(is_valid) {
|
if(is_valid) {
|
||||||
|
let play = new GAME.Play(INTERFACE_DATA.select.source, INTERFACE_DATA.select.tile, INTERFACE_DATA.hover.tile);
|
||||||
// Send message to server for online game.
|
INTERFACE.process(play);
|
||||||
switch(INTERFACE_DATA.mode) {
|
|
||||||
|
|
||||||
// Apply action and change turn for local game.
|
|
||||||
case INTERFACE.Mode.Local: {
|
|
||||||
let play = new GAME.Play(INTERFACE_DATA.select.source, INTERFACE_DATA.select.tile, INTERFACE_DATA.hover.tile);
|
|
||||||
INTERFACE_DATA.play = play;
|
|
||||||
GAME_DATA.process(play);
|
|
||||||
|
|
||||||
INTERFACE_DATA.player = +(!INTERFACE_DATA.player);
|
|
||||||
INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate);
|
|
||||||
|
|
||||||
INTERFACE.draw();
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Send action to server for validation.
|
|
||||||
case INTERFACE.Mode.Online: {
|
|
||||||
let move_data = INTERFACE_DATA.select.source | (INTERFACE_DATA.select.tile << 1) | (INTERFACE_DATA.hover.tile << 7);
|
|
||||||
MESSAGE_COMPOSE([
|
|
||||||
PACK.u16(OpCode.GamePlay),
|
|
||||||
PACK.u16(0),
|
|
||||||
PACK.u16(GAME_DATA.turn),
|
|
||||||
PACK.u16(move_data),
|
|
||||||
]);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Branch into local game from here.
|
|
||||||
case INTERFACE.Mode.Replay: {
|
|
||||||
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERFACE_DATA.select = null;
|
INTERFACE_DATA.select = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -860,6 +829,38 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
process(play) {
|
||||||
|
// Send message to server for online game.
|
||||||
|
switch(INTERFACE_DATA.mode) {
|
||||||
|
// Apply action and change turn for local game.
|
||||||
|
case INTERFACE.Mode.Local: {
|
||||||
|
INTERFACE_DATA.play = play;
|
||||||
|
GAME_DATA.process(play);
|
||||||
|
|
||||||
|
INTERFACE_DATA.player = +(!INTERFACE_DATA.player);
|
||||||
|
INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate);
|
||||||
|
|
||||||
|
INTERFACE.draw();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Send action to server for validation.
|
||||||
|
case INTERFACE.Mode.Online: {
|
||||||
|
let move_data = play.source | (play.from << 1) | (play.to << 7);
|
||||||
|
MESSAGE_COMPOSE([
|
||||||
|
PACK.u16(OpCode.GamePlay),
|
||||||
|
PACK.u16(0),
|
||||||
|
PACK.u16(GAME_DATA.turn),
|
||||||
|
PACK.u16(move_data),
|
||||||
|
]);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Branch into local game from here.
|
||||||
|
case INTERFACE.Mode.Replay: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
rotate() {
|
rotate() {
|
||||||
INTERFACE_DATA.rotate ^= 1;
|
INTERFACE_DATA.rotate ^= 1;
|
||||||
INTERFACE.draw();
|
INTERFACE.draw();
|
||||||
@ -909,6 +910,109 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
auto() {
|
||||||
|
let moves = [ ];
|
||||||
|
let player = GAME_DATA.turn & 1;
|
||||||
|
let opponent = +(!player);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next_move.check) { score += 2; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moves.push({
|
||||||
|
score: score,
|
||||||
|
play: new GAME.Play(1, p, move.tile),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
if(move.valid) {
|
||||||
|
let hex = HEX.tile_to_hex(move.tile);
|
||||||
|
|
||||||
|
// Calculate base score.
|
||||||
|
let score = ((piece.piece + 1) * 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 * (1 + target.piece); }
|
||||||
|
else { score -= 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
score += +((-MATH.sign_branch(player) * (hex.y - current_hex.y)) > 0);
|
||||||
|
|
||||||
|
// Add score for check.
|
||||||
|
if(move.check) { score += 2; }
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next_move.check) { score += 2; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moves.push({
|
||||||
|
score: score,
|
||||||
|
play: new GAME.Play(0, piece.tile, move.tile),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(moves.length > 0) {
|
||||||
|
moves = moves.sort((a, b) => { return b.score - a.score; });
|
||||||
|
|
||||||
|
let select = Math.floor(Math.random() * Math.min(moves.length, 3));
|
||||||
|
INTERFACE.process(moves[select].play);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
INTERFACE.Radius = 2.0 / Math.sqrt(3.0);
|
INTERFACE.Radius = 2.0 / Math.sqrt(3.0);
|
||||||
|
@ -564,6 +564,7 @@ const SCENES = {
|
|||||||
UI.nav([
|
UI.nav([
|
||||||
UI.button("Rotate", () => { INTERFACE.rotate(); }),
|
UI.button("Rotate", () => { INTERFACE.rotate(); }),
|
||||||
UI.button("Mirror", () => { INTERFACE.mirror(); }),
|
UI.button("Mirror", () => { INTERFACE.mirror(); }),
|
||||||
|
UI.button("Auto", () => { INTERFACE.auto(); }),
|
||||||
], buttons_bottom);
|
], buttons_bottom);
|
||||||
|
|
||||||
let canvas = document.createElement("canvas");
|
let canvas = document.createElement("canvas");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user