Solver
This commit is contained in:
parent
81e7f8ddd9
commit
20638827f6
197
nirmana.jai
Normal file
197
nirmana.jai
Normal file
@ -0,0 +1,197 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user