first commit
This commit is contained in:
92
vial_solver.py
Normal file
92
vial_solver.py
Normal file
@ -0,0 +1,92 @@
|
||||
"""A solver for a vial-type game."""
|
||||
import time
|
||||
import math
|
||||
from fibonacci_heap import FibonacciHeap
|
||||
from vial_game import Game
|
||||
from exceptions import NoSolutions
|
||||
|
||||
def print_progress(amount_done):
|
||||
extra_symbol = ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'][
|
||||
math.floor(amount_done * 160) % 8
|
||||
]
|
||||
|
||||
progress_bar = "\r|{}{}{}| {}% ".format(
|
||||
'█'*math.floor(amount_done*20),
|
||||
extra_symbol,
|
||||
' '*(math.ceil((1-amount_done)*20)-1),
|
||||
math.floor(amount_done*100)
|
||||
)
|
||||
print(progress_bar, end="")
|
||||
|
||||
|
||||
def solve_game(starting_state: Game):
|
||||
"""Solves a vial game."""
|
||||
if starting_state.is_solved:
|
||||
return []
|
||||
|
||||
attempted_states = {starting_state.vial_string(): []}
|
||||
states = FibonacciHeap((starting_state, []), starting_state.min_moves)
|
||||
amount_done = 0
|
||||
moves_amount = -1
|
||||
|
||||
while len(states) > 0:
|
||||
(current_state, moves), value = states.extract_min()
|
||||
if len(moves) > moves_amount:
|
||||
moves_amount = len(moves)
|
||||
print(f"{len(states) + 1} ({len(attempted_states)})")
|
||||
|
||||
if amount_done + 0.00125 < len(moves)/value:
|
||||
amount_done = (len(moves)/value)
|
||||
print_progress(amount_done)
|
||||
|
||||
last_to_vial = moves[-1][1] if len(moves) > 1 else None
|
||||
possible_moves = current_state.possible_moves(last_to_vial)
|
||||
for from_vial, to_vial in possible_moves:
|
||||
new_state = current_state.copy()
|
||||
new_state.move(from_vial, to_vial)
|
||||
if new_state.vials[to_vial].is_solved:
|
||||
star = "*"
|
||||
else:
|
||||
star = " "
|
||||
new_state_moves = moves + [(from_vial, to_vial, star)]
|
||||
if new_state.is_solved:
|
||||
return new_state_moves
|
||||
|
||||
if new_state.vial_string() not in attempted_states:
|
||||
attempted_states[new_state.vial_string()] = new_state_moves
|
||||
new_state_value = new_state.min_moves + len(new_state_moves)
|
||||
states.insert((new_state, new_state_moves), new_state_value)
|
||||
|
||||
print("\r", end="")
|
||||
raise NoSolutions()
|
||||
|
||||
def format_instructions(instructions, start_time):
|
||||
"""Format instructions outputted by solve_game()."""
|
||||
time_in_milliseconds = math.floor((time.time()-start_time)*1000)
|
||||
time_text = ""
|
||||
if time_in_milliseconds >= (1000*60):
|
||||
time_in_minutes = str(math.floor(time_in_milliseconds/(1000*60)))
|
||||
time_text += time_in_minutes+"m "
|
||||
if time_in_milliseconds >= 1000:
|
||||
time_in_seconds = str(math.floor(time_in_milliseconds/1000)%60)
|
||||
time_text += time_in_seconds+"s "
|
||||
|
||||
time_text += str(time_in_milliseconds%1000)+"ms "
|
||||
|
||||
formatted_instructions = f"Time elapsed: {time_text}\n"
|
||||
formatted_instructions += "Instructions:\n"
|
||||
for i, instruction in enumerate(instructions):
|
||||
if i%7 == 0 and i != 0:
|
||||
formatted_instructions += "\n"
|
||||
if i%21 == 0 and i != 0:
|
||||
formatted_instructions += "\n"
|
||||
if i%63 == 0 and i != 0:
|
||||
formatted_instructions += "\n\n"
|
||||
|
||||
from_vial = instruction[0]
|
||||
to_vial = instruction[1]
|
||||
star = instruction[2]
|
||||
step = f" {star}{from_vial:2} --> {to_vial:2}{star} \t"
|
||||
formatted_instructions += step
|
||||
|
||||
return formatted_instructions
|
Reference in New Issue
Block a user