2026-05-09 20:17:23 +02:00

198 lines
5.4 KiB
Plaintext

#import "Basic";
#import "Random";
#import "Hash_Table";
Position :: struct {
values : [12] u8;
moves : [] u8;
score : int;
index : int;
peril : bool;
}
position_create_start :: (values: [12] u8) -> Position {
result: Position;
result.values = values;
result.score = 0;
result.peril = false;
return result;
}
position_print :: (p: Position) -> () {
print("[");
for v, i: p.values {
if i > 0 print(" ");
print("%", v);
}
print("]");
if p.peril then print("*"); else print(" ");
print("(%)", p.score);
}
position_print_moves :: (p: Position) -> () {
for m: p.moves
print("% ", m);
}
position_is_final :: (p: Position) -> bool {
for v: p.values {
if v != 0 return false;
}
return true;
}
position_make_moves :: (p: Position, results: *[..] Position) -> () {
for i: 0..11 {
if p.values[i] == 0 then continue;
n := p.values[i];
new_values: [12] u8;
new_score := p.score;
for j: 0..11 {
if j != i then new_values[j] = p.values[j];
}
for j: 1..n {
idx := (i + j) % 12;
new_values[idx] += 1;
}
last := (i + n) % 12;
k := new_values[last];
if p.peril && k != 2 && k != 3 then continue;
new_moves := NewArray(p.moves.count + 1, u8);
for j: 0..p.moves.count-1 {
new_moves[j] = p.moves[j];
}
new_moves[p.moves.count] = cast(u8) i;
new_peril: bool;
if k == 2 || k ==3 {
new_values[last] = 0;
new_score += k;
new_peril = false;
while true {
last = (last + 11) % 12;
kk := new_values[last];
if kk == 2 || kk == 3 {
new_values[last] = 0;
new_score += kk * kk;
} else {
break;
}
}
} else {
new_peril = true;
}
new_position := Position.{
values = new_values,
moves = new_moves,
score = new_score,
peril = new_peril };
array_add(results, new_position);
}
}
position_equal :: (left: Position, right: Position) -> bool {
for i: 0..11 {
if left.values[i] != right.values[i] then return false;
}
if left.peril != right.peril then return false;
if left.score != right.score then return false;
return true;
}
position_hash :: (p: Position) -> u32 {
h : u32 = 17;
for v: p.values h = (h + v) * 37 + 89;
h = (h + cast(u32) p.score) * 37 + 89;
h = (h + cast(u32)(ifx p.peril then 1 else 2)) * 37 + 89;
return h;
}
Position_List :: struct {
list: [..] Position;
}
position_max_remaining_score :: (p: Position) -> int {
sum := 0;
for v: p.values sum += v;
return 3 + 9 * ((sum - 1) / 3);
}
position_solve :: (start: Position) -> (moves: [] u8, best_score: int) {
stacks: [256] Position_List;
all_positions: Table(Position, bool, position_hash, position_equal);
array_add(*stacks[0].list, start);
results: [..] Position;
best_score := 0;
best_moves: [] u8;
previous_time_ms := 0;
longest_moves_count := 0;
longest_moves: [] u8;
steps := 0;
while true {
steps += 1;
found := false;
score := -1;
for diff: 1..256 {
score = 256 - diff;
if stacks[score].list.count > 0 {
found = true;
break;
}
}
if !found then break;
index := cast(s64) (random_get() % cast(u64) stacks[score].list.count);
current := stacks[score].list[index];
array_unordered_remove_by_index(*stacks[score].list, index);
current_time_ms := to_milliseconds(current_time_consensus());
if score + position_max_remaining_score(current) < best_score then continue;
if current_time_ms - previous_time_ms > 1000 {
print("Steps: %, current: ", steps);
position_print_moves(current);
print(" --> ");
position_print(current);
print("\n");
previous_time_ms = current_time_ms;
}
if current.moves.count > longest_moves_count {
longest_moves = current.moves;
longest_moves_count = current.moves.count;
}
if position_is_final(current) {
if current.score > best_score {
print("*** Reached score %: ", current.score);
for m: current.moves {
print("% ", m);
}
print("\n");
best_score = current.score;
best_moves = current.moves;
}
continue;
}
array_reset(*results);
position_make_moves(current, *results);
for *r: results {
if table_contains(*all_positions, r) then continue;
array_add(*stacks[r.score].list, r);
table_add(*all_positions, r, true);
}
}
return best_moves, best_score;
}
main :: () -> () {
print("Hello.\n");
start := position_create_start(.[4, 1, 3, 1, 1, 3, 8, 5, 2, 8, 6, 8]);
position_print(start);
print("\n");
moves, best_score := position_solve(start);
print("Best score: % in % moves\n", best_score, moves.count);
for m, i: moves {
print("Move %: %\n", i + 1, m);
}
}