add better method for instance solving: try greedy solver first
This commit is contained in:
parent
07d95e99f5
commit
054112e272
1 changed files with 43 additions and 36 deletions
|
@ -1,15 +1,16 @@
|
||||||
import json
|
import json
|
||||||
from time import sleep
|
|
||||||
from site_api import get, api, replay
|
from site_api import get, api, replay
|
||||||
from sat import COLORS, solve
|
from sat import COLORS, solve_sat
|
||||||
from database import Game, store, load, commit, conn
|
from database import Game, store, load, commit, conn
|
||||||
from download_data import export_game
|
from download_data import export_game
|
||||||
from variants import num_suits, VARIANTS
|
from variants import num_suits, VARIANTS, variant_name
|
||||||
from alive_progress import alive_bar
|
from alive_progress import alive_bar
|
||||||
from compress import decompress_deck
|
from compress import decompress_deck, link
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from time import sleep, perf_counter
|
from time import sleep, perf_counter
|
||||||
|
from greedy_solver import GameState, GreedyStrategy
|
||||||
|
from logger_setup import logger
|
||||||
|
|
||||||
|
|
||||||
MAX_PROCESSES=4
|
MAX_PROCESSES=4
|
||||||
|
@ -104,22 +105,55 @@ def get_decks_for_all_seeds():
|
||||||
|
|
||||||
mutex = Lock()
|
mutex = Lock()
|
||||||
|
|
||||||
|
def solve_instance(num_players, deck):
|
||||||
|
for num_remaining_cards in [0, 5, 10, 20, 30]:
|
||||||
|
# print("trying with {} greedy moves".format(num_greedy_moves))
|
||||||
|
game = GameState(num_players, deck)
|
||||||
|
strat = GreedyStrategy(game)
|
||||||
|
|
||||||
|
# make a number of greedy moves
|
||||||
|
while not game.is_over() and not game.is_known_lost():
|
||||||
|
if num_remaining_cards != 0 and game.progress == game.deck_size - num_remaining_cards:
|
||||||
|
break # stop solution here
|
||||||
|
strat.make_move()
|
||||||
|
|
||||||
|
# check if we won already
|
||||||
|
if game.is_won():
|
||||||
|
# print("won with greedy strat")
|
||||||
|
return True, game, num_remaining_cards
|
||||||
|
|
||||||
|
# now, apply sat solver
|
||||||
|
if not game.is_over():
|
||||||
|
solvable, sol = solve_sat(game)
|
||||||
|
if solvable:
|
||||||
|
return solvable, sol, num_remaining_cards
|
||||||
|
logger.info("No success, reducing number of greedy moves, failed attempt was: {}".format(link(game.to_json())))
|
||||||
|
# print("Aborting trying with greedy strat")
|
||||||
|
logger.info("Starting full SAT solver")
|
||||||
|
game = GameState(num_players, deck)
|
||||||
|
a, b = solve_sat(game)
|
||||||
|
return a, b, 99
|
||||||
|
|
||||||
|
|
||||||
def solve_seed(seed, num_players, deck_compressed, var_id):
|
def solve_seed(seed, num_players, deck_compressed, var_id):
|
||||||
deck = decompress_deck(deck_compressed)
|
deck = decompress_deck(deck_compressed)
|
||||||
t0 = perf_counter()
|
t0 = perf_counter()
|
||||||
solvable, solution = solve(deck, num_players)
|
solvable, solution, num_remaining_cards = solve_instance(num_players, deck)
|
||||||
t1 = perf_counter()
|
t1 = perf_counter()
|
||||||
print("Solved instance {} in {} seconds".format(seed, round(t1-t0, 2)))
|
logger.info("Solved instance {} in {} seconds".format(seed, round(t1-t0, 2)))
|
||||||
|
|
||||||
mutex.acquire()
|
mutex.acquire()
|
||||||
lcur = conn.cursor()
|
lcur = conn.cursor()
|
||||||
lcur.execute("UPDATE seeds SET feasible = (%s) WHERE seed = (%s)", (solvable, seed))
|
lcur.execute("UPDATE seeds SET feasible = (%s) WHERE seed = (%s)", (solvable, seed))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
if solvable:
|
||||||
|
with open("remaining_cards.txt", "a") as f:
|
||||||
|
f.write("Success with {} cards left in draw by greedy solver on seed {}: {}\n".format(num_remaining_cards, seed ,link(solution.to_json())))
|
||||||
|
|
||||||
if not solvable:
|
if not solvable:
|
||||||
|
logger.info("seed {} was not solvable".format(seed))
|
||||||
with open('infeasible_instances.txt', 'a') as f:
|
with open('infeasible_instances.txt', 'a') as f:
|
||||||
f.write('{}-player, seed {:10}, {}\n'.format(num_players, seed, variant_name(var_id)))
|
f.write('{}-player, seed {:10}, {}\n'.format(num_players, seed, variant_name(var_id)))
|
||||||
# print('Seed {} ({} players) not solvable: {}'.format(seed, num_players, deck))
|
|
||||||
|
|
||||||
mutex.release()
|
mutex.release()
|
||||||
|
|
||||||
|
@ -127,10 +161,10 @@ def solve_seed(seed, num_players, deck_compressed, var_id):
|
||||||
def solve_unknown_seeds():
|
def solve_unknown_seeds():
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
for var in VARIANTS:
|
for var in VARIANTS:
|
||||||
cur.execute("SELECT seed, num_players, deck FROM seeds WHERE variant_id = (%s) AND feasible IS NULL AND deck IS NOT NULL AND num_players != 2 ORDER BY num_players DESC", (var['id'],))
|
cur.execute("SELECT seed, num_players, deck FROM seeds WHERE variant_id = (%s) AND feasible IS NULL AND deck IS NOT NULL", (var['id'],))
|
||||||
res = cur.fetchall()
|
res = cur.fetchall()
|
||||||
|
|
||||||
with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor:
|
with concurrent.futures.ProcessPoolExecutor(max_workers=MAX_PROCESSES) as executor:
|
||||||
fs = [executor.submit(solve_seed, r[0], r[1], r[2], var['id']) for r in res]
|
fs = [executor.submit(solve_seed, r[0], r[1], r[2], var['id']) for r in res]
|
||||||
with alive_bar(len(res), title='Seed solving on {}'.format(var['name'])) as bar:
|
with alive_bar(len(res), title='Seed solving on {}'.format(var['name'])) as bar:
|
||||||
for f in concurrent.futures.as_completed(fs):
|
for f in concurrent.futures.as_completed(fs):
|
||||||
|
@ -139,30 +173,3 @@ def solve_unknown_seeds():
|
||||||
|
|
||||||
|
|
||||||
solve_unknown_seeds()
|
solve_unknown_seeds()
|
||||||
exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
print('looked at {} games'.format(num_games))
|
|
||||||
for i in range(2,7):
|
|
||||||
print("Found {} seeds in {}-player in database".format(len(seeds[i]), i))
|
|
||||||
|
|
||||||
hard_seeds = []
|
|
||||||
for seed in seeds[3]:
|
|
||||||
if not known_solvable(seed):
|
|
||||||
# print("seed {} has no solve in online database".format(seed))
|
|
||||||
hard_seeds.append(seed)
|
|
||||||
print("Found {} seeds with no solve in database, attacking each with SAT solver"
|
|
||||||
.format(len(hard_seeds)))
|
|
||||||
|
|
||||||
for seed in hard_seeds:
|
|
||||||
r = replay(seed)
|
|
||||||
if not r:
|
|
||||||
continue
|
|
||||||
s, sol = solvable(r)
|
|
||||||
if s:
|
|
||||||
print("Seed {} was found to be solvable".format(seed))
|
|
||||||
# print(sol)
|
|
||||||
else:
|
|
||||||
print("==============================")
|
|
||||||
print("Found non-solvable seed {}", seed)
|
|
||||||
print("==============================")
|
|
||||||
|
|
Loading…
Reference in a new issue