Skip to content

Commit ea605c7

Browse files
committed
Improve Gomoku AI threat defense
1 parent cae12a3 commit ea605c7

3 files changed

Lines changed: 56 additions & 6 deletions

File tree

scripts/gomoku_ai.rss

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ let mut enemy_win_x = -1;
211211
let mut enemy_win_y = -1;
212212
let mut enemy_win_distance = 1000;
213213
let mut enemy_wins = 0;
214+
let mut enemy_four_x = -1;
215+
let mut enemy_four_y = -1;
216+
let mut enemy_four_score = -1;
217+
let mut enemy_four_distance = 1000;
214218
let mut scan_y = 0;
215219
while scan_y < 15 {
216220
let mut scan_x = 0;
@@ -234,6 +238,18 @@ while scan_y < 15 {
234238
enemy_win_y = scan_y;
235239
enemy_win_distance = distance;
236240
}
241+
} else {
242+
let enemy_threat = threat_score(&board, scan_x, scan_y, opponent);
243+
let enemy_followup_wins = winning_extensions(&board, scan_x, scan_y, opponent, 1);
244+
if enemy_followup_wins > 0 && (
245+
enemy_threat > enemy_four_score ||
246+
(enemy_threat == enemy_four_score && distance < enemy_four_distance)
247+
) {
248+
enemy_four_x = scan_x;
249+
enemy_four_y = scan_y;
250+
enemy_four_score = enemy_threat;
251+
enemy_four_distance = distance;
252+
}
237253
}
238254
board[scan_y * 15 + scan_x] = 0;
239255
}
@@ -255,6 +271,10 @@ if stones == 0 {
255271
best_x = enemy_win_x;
256272
best_y = enemy_win_y;
257273
} else {
274+
if enemy_four_x >= 0 {
275+
best_x = enemy_four_x;
276+
best_y = enemy_four_y;
277+
} else {
258278
let mut top_x: [int] = [-1, -1, -1, -1, -1, -1, -1, -1];
259279
let mut top_y: [int] = [-1, -1, -1, -1, -1, -1, -1, -1];
260280
let mut top_score: [int] = [
@@ -290,11 +310,15 @@ if stones == 0 {
290310
if defense >= 120000 {
291311
order = 1200000000 + defense - distance;
292312
} else {
293-
if own_wins == 1 {
294-
order = order + 18000000;
295-
}
296-
if enemy_extensions == 1 {
297-
order = order + 12000000;
313+
if defense >= 32000 {
314+
order = 900000000 + defense - distance;
315+
} else {
316+
if own_wins == 1 {
317+
order = order + 18000000;
318+
}
319+
if enemy_extensions == 1 {
320+
order = order + 12000000;
321+
}
298322
}
299323
}
300324
}
@@ -456,6 +480,7 @@ if stones == 0 {
456480
root = root + 1;
457481
}
458482
}
483+
}
459484
}
460485
}
461486
}

tests/ai_matchplay.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn gomoku_ai_self_play_is_legal_deterministic_and_responsive() {
5050
.count() as u128;
5151
assert_eq!(stones, plies);
5252
assert!(
53-
plies >= 8,
53+
plies >= 18,
5454
"self-play ended before exercising midgame search"
5555
);
5656
let average_micros = ai_micros / plies;

tests/gomoku_strength.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,31 @@ fn ai_rejects_a_one_ply_blunder_that_allows_an_enemy_fork() {
256256
);
257257
}
258258

259+
#[test]
260+
fn ai_blocks_an_enemy_open_three_before_chasing_shapes() {
261+
let board = seeded_board(&[
262+
(7, 7, 1),
263+
(7, 6, 2),
264+
(6, 7, 1),
265+
(8, 7, 2),
266+
(6, 5, 1),
267+
(6, 6, 2),
268+
(8, 6, 1),
269+
(5, 6, 2),
270+
(4, 6, 1),
271+
(5, 7, 2),
272+
(7, 5, 1),
273+
(9, 5, 2),
274+
(5, 5, 1),
275+
]);
276+
277+
let (x, y, _) = choose(&board, 2);
278+
assert!(
279+
[(4, 5), (8, 5)].contains(&(x, y)),
280+
"AI move ({x}, {y}) ignored an enemy open-three extension"
281+
);
282+
}
283+
259284
#[test]
260285
fn ai_survives_a_deterministic_tactical_match() {
261286
let mut board = GomokuBoard::default();

0 commit comments

Comments
 (0)