adjust deck analyzer to use hanabi instances
This commit is contained in:
parent
ddeb19265d
commit
dee13938cf
2 changed files with 20 additions and 21 deletions
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue