adjust deck analyzer to use hanabi instances

This commit is contained in:
Maximilian Keßler 2023-03-18 14:08:18 +01:00
parent ddeb19265d
commit dee13938cf
Signed by: max
GPG key ID: BCC5A619923C0BA5
2 changed files with 20 additions and 21 deletions

View file

@ -1,15 +1,10 @@
from compress import DeckCard from compress import DeckCard
from typing import List from typing import List
from enum import Enum from enum import Enum
from compress import decompress_deck
import numpy
from database import conn from database import conn
from hanabi import HanabiInstance
STANDARD_HAND_SIZE = {2: 5, 3: 5, 4: 4, 5: 4, 6: 3} from compress import decompress_deck
COLORS='rygbp'
deck_str = "15xaivliynfkrhpdwtprfaskwvfhnpcmjdksmlabcquqoegxugub"
deck = decompress_deck(deck_str)
class InfeasibilityType(Enum): class InfeasibilityType(Enum):
@ -32,21 +27,22 @@ class InfeasibilityReason():
return "Deck runs out of hand size after drawing card {}".format(self.index) return "Deck runs out of hand size after drawing card {}".format(self.index)
def analyze(instance: HanabiInstance, find_non_trivial=False) -> InfeasibilityReason | None:
def analyze(deck: List[DeckCard], num_players, find_non_trivial=False) -> InfeasibilityReason | None:
num_suits = max(map(lambda c: c.suitIndex, deck)) + 1
hand_size = STANDARD_HAND_SIZE[num_players]
# we will sweep through the deck and pretend that we instantly play all cards # we will sweep through the deck and pretend that we instantly play all cards
# as soon as we have them (and recurse this) # as soon as we have them (and recurse this)
# this allows us to detect standard pace issue arguments # this allows us to detect standard pace issue arguments
stacks = [0] * num_suits stacks = [0] * instance.num_suits
stored_cards = set() stored_cards = set()
stored_crits = set() stored_crits = set()
min_forced_pace = 100 min_forced_pace = 100
worst_index = 0 worst_index = 0
for (i, card) in enumerate(deck):
ret = None
for (i, card) in enumerate(instance.deck):
if card.rank == stacks[card.suitIndex] + 1: if card.rank == stacks[card.suitIndex] + 1:
# card is playable # card is playable
stacks[card.suitIndex] += 1 stacks[card.suitIndex] += 1
@ -69,16 +65,16 @@ def analyze(deck: List[DeckCard], num_players, find_non_trivial=False) -> Infeas
stored_cards.add(card) stored_cards.add(card)
## check for out of handsize: ## check for out of handsize:
if len(stored_crits) == num_players * hand_size: if len(stored_crits) == instance.num_players * instance.hand_size:
return InfeasibilityReason(InfeasibilityType.OutOfHandSize, i) return InfeasibilityReason(InfeasibilityType.OutOfHandSize, i)
if find_non_trivial and len(stored_cards) == num_players * hand_size: if find_non_trivial and len(stored_cards) == instance.num_players * instance.hand_size:
return InfeasibilityReason(InfeasibilityType.NotTrivial, i) ret = InfeasibilityReason(InfeasibilityType.NotTrivial, i)
# the last - 1 is there because we have to discard 'next', causing a further draw # the last - 1 is there because we have to discard 'next', causing a further draw
max_remaining_plays = (len(deck) - i - 1) + num_players - 1 max_remaining_plays = (instance.deck_size - i - 1) + instance.num_players - 1
needed_plays = 5 * num_suits - sum(stacks) needed_plays = 5 * instance.num_suits - sum(stacks)
missing = max_remaining_plays - needed_plays missing = max_remaining_plays - needed_plays
if missing < min_forced_pace: if missing < min_forced_pace:
# print("update to {}: {}".format(i, missing)) # print("update to {}: {}".format(i, missing))
@ -88,10 +84,12 @@ def analyze(deck: List[DeckCard], num_players, find_non_trivial=False) -> Infeas
# check that we correctly walked through the deck # check that we correctly walked through the deck
assert(len(stored_cards) == 0) assert(len(stored_cards) == 0)
assert(len(stored_crits) == 0) assert(len(stored_crits) == 0)
assert(sum(stacks) == 5 * num_suits) assert(sum(stacks) == 5 * instance.num_suits)
if min_forced_pace < 0: if min_forced_pace < 0:
return InfeasibilityReason(InfeasibilityType.OutOfPace, worst_index, min_forced_pace) return InfeasibilityReason(InfeasibilityType.OutOfPace, worst_index, min_forced_pace)
elif ret is not None:
return ret
else: else:
return None return None
@ -109,7 +107,7 @@ def run_on_database():
print("Checking {} {}-player seeds from database".format(len(res), num_p)) print("Checking {} {}-player seeds from database".format(len(res), num_p))
for (seed, num_players, deck) in res: for (seed, num_players, deck) in res:
deck = decompress_deck(deck) deck = decompress_deck(deck)
a = analyze(deck, num_players, True) a = analyze(HanabiInstance(deck, num_players), True)
if type(a) == InfeasibilityReason: if type(a) == InfeasibilityReason:
if a.type == InfeasibilityType.OutOfHandSize: if a.type == InfeasibilityType.OutOfHandSize:
# print("Seed {} infeasible: {}\n{}".format(seed, a, deck)) # print("Seed {} infeasible: {}\n{}".format(seed, a, deck))

View file

@ -1,5 +1,6 @@
from typing import Optional, List from typing import Optional, List
from enum import Enum from enum import Enum
from termcolor import colored
import constants import constants