#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); } }