stash
This commit is contained in:
parent
a715bda02c
commit
3cc49b4813
4 changed files with 64 additions and 35 deletions
|
@ -59,7 +59,7 @@ def check_game(game_id: int) -> Tuple[int, GameState]:
|
||||||
return unsolvable_turn, solution
|
return unsolvable_turn, solution
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
game_id = 961092
|
game_id = 963339
|
||||||
export_game(game_id)
|
export_game(game_id)
|
||||||
print("checking game {}".format(game_id))
|
print("checking game {}".format(game_id))
|
||||||
turn, sol = check_game(game_id)
|
turn, sol = check_game(game_id)
|
||||||
|
|
36
hanabi.py
36
hanabi.py
|
@ -85,19 +85,20 @@ class HanabiInstance():
|
||||||
self,
|
self,
|
||||||
deck: List[DeckCard], # assumes a default deck, every suit has to be distributed either [1,1,1,2,2,3,3,4,4,5] or [1,2,3,4,5]
|
deck: List[DeckCard], # assumes a default deck, every suit has to be distributed either [1,1,1,2,2,3,3,4,4,5] or [1,2,3,4,5]
|
||||||
num_players: int, # number of players that play this deck, in range [2,6]
|
num_players: int, # number of players that play this deck, in range [2,6]
|
||||||
|
|
||||||
hand_size: Optional[int] = None, # number of cards that each player holds
|
hand_size: Optional[int] = None, # number of cards that each player holds
|
||||||
num_strikes: Optional[int] = None, # number of strikes that leads to game loss
|
num_strikes: Optional[int] = None, # number of strikes that leads to game loss
|
||||||
clue_starved: bool = False, # if true, discarding and playing fives only gives back half a clue
|
clue_starved: bool = False, # if true, discarding and playing fives only gives back half a clue
|
||||||
variant_id: Optional[int] = None # optional: variant id of hanab.live, useful if instance gets exported to be viewed in browser
|
fives_give_clue: bool = True, # if false, then playing a five will not change the clue count
|
||||||
):
|
):
|
||||||
assert(2 <= num_players <= 6)
|
|
||||||
|
|
||||||
# defining properties
|
# defining properties
|
||||||
self.deck = deck
|
self.deck = deck
|
||||||
self.num_players = num_players
|
self.num_players = num_players
|
||||||
self.hand_size = hand_size or constants.HAND_SIZES[self.num_players]
|
self.hand_size = hand_size or constants.HAND_SIZES[self.num_players]
|
||||||
self.num_strikes = num_strikes or constants.NUM_STRIKES
|
self.num_strikes = num_strikes or constants.NUM_STRIKES
|
||||||
self.clue_starved = clue_starved
|
self.clue_starved = clue_starved
|
||||||
|
self.fives_give_clue = fives_give_clue
|
||||||
|
|
||||||
# normalize deck indices
|
# normalize deck indices
|
||||||
for (idx, card) in enumerate(self.deck):
|
for (idx, card) in enumerate(self.deck):
|
||||||
|
@ -119,9 +120,6 @@ class HanabiInstance():
|
||||||
+ 8 + (self.num_suits - 1) \
|
+ 8 + (self.num_suits - 1) \
|
||||||
+ (-1 if self.num_players >= 5 else 0)
|
+ (-1 if self.num_players >= 5 else 0)
|
||||||
|
|
||||||
# TODO: set a meaningful default here for export?
|
|
||||||
self._variant_id: Optional[int] = variant_id
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_dealt_cards(self):
|
def num_dealt_cards(self):
|
||||||
return self.num_players * self.hand_size
|
return self.num_players * self.hand_size
|
||||||
|
@ -130,15 +128,6 @@ class HanabiInstance():
|
||||||
def draw_pile_size(self):
|
def draw_pile_size(self):
|
||||||
return self.deck_size - self.num_dealt_cards
|
return self.deck_size - self.num_dealt_cards
|
||||||
|
|
||||||
@property
|
|
||||||
def variant_id(self):
|
|
||||||
if self._variant_id is not None:
|
|
||||||
return self._variant_id
|
|
||||||
else:
|
|
||||||
# ensure no key error can happen
|
|
||||||
assert(self.is_standard())
|
|
||||||
return constants.VARIANT_IDS_STANDARD_DISTRIBUTIONS[self.num_suits][self.num_dark_suits]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_score(self):
|
def max_score(self):
|
||||||
return 5 * self.num_suits
|
return 5 * self.num_suits
|
||||||
|
@ -147,21 +136,6 @@ class HanabiInstance():
|
||||||
def clue_increment(self):
|
def clue_increment(self):
|
||||||
return 0.5 if self.clue_starved else 1
|
return 0.5 if self.clue_starved else 1
|
||||||
|
|
||||||
# returns True if the instance has values matching hanabi-live rules
|
|
||||||
# (i.e. standard + extra variants with 5 / 6 suits)
|
|
||||||
def is_standard(self):
|
|
||||||
return all([
|
|
||||||
2 <= self.num_players <= 6,
|
|
||||||
self.hand_size == constants.HAND_SIZES[self.num_players],
|
|
||||||
self.num_strikes == constants.NUM_STRIKES,
|
|
||||||
3 <= self.num_suits <= 6,
|
|
||||||
0 <= self.num_dark_suits <= 2,
|
|
||||||
4 <= self.num_suits - self.num_dark_suits or self.num_suits == 3
|
|
||||||
# TODO: check that variant id matches deck distribution
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GameState():
|
class GameState():
|
||||||
def __init__(self, instance: HanabiInstance):
|
def __init__(self, instance: HanabiInstance):
|
||||||
|
@ -210,7 +184,7 @@ class GameState():
|
||||||
card = self.instance.deck[card_idx]
|
card = self.instance.deck[card_idx]
|
||||||
if card.rank == self.stacks[card.suitIndex] + 1:
|
if card.rank == self.stacks[card.suitIndex] + 1:
|
||||||
self.stacks[card.suitIndex] += 1
|
self.stacks[card.suitIndex] += 1
|
||||||
if card.rank == 5 and self.clues != 8:
|
if card.rank == 5 and self.clues != 8 and self.fives_give_clue:
|
||||||
self.clues += self.instance.clue_increment
|
self.clues += self.instance.clue_increment
|
||||||
else:
|
else:
|
||||||
self.strikes += 1
|
self.strikes += 1
|
||||||
|
|
6
sat.py
6
sat.py
|
@ -304,7 +304,7 @@ def solve_sat(starting_state: GameState | HanabiInstance) -> Tuple[bool, Optiona
|
||||||
|
|
||||||
model = get_model(constraints)
|
model = get_model(constraints)
|
||||||
if model:
|
if model:
|
||||||
# print_model(model, game_state, ls)
|
print_model(model, game_state, ls)
|
||||||
solution = evaluate_model(model, copy.deepcopy(game_state), ls)
|
solution = evaluate_model(model, copy.deepcopy(game_state), ls)
|
||||||
return True, solution
|
return True, solution
|
||||||
else:
|
else:
|
||||||
|
@ -355,11 +355,11 @@ def evaluate_model(model, cur_game_state: GameState, ls: Literals) -> GameState:
|
||||||
|
|
||||||
|
|
||||||
def run_deck():
|
def run_deck():
|
||||||
puzzle = False
|
puzzle = True
|
||||||
if puzzle:
|
if puzzle:
|
||||||
deck_str = 'p5 p3 b4 r5 y4 y4 y5 r4 b2 y2 y3 g5 g2 g3 g4 p4 r3 b2 b3 b3 p4 b1 p2 b1 b1 p2 p1 p1 g1 r4 g1 r1 r3 r1 g1 r1 p1 b4 p3 g2 g3 g4 b5 y1 y1 y1 r2 r2 y2 y3'
|
deck_str = 'p5 p3 b4 r5 y4 y4 y5 r4 b2 y2 y3 g5 g2 g3 g4 p4 r3 b2 b3 b3 p4 b1 p2 b1 b1 p2 p1 p1 g1 r4 g1 r1 r3 r1 g1 r1 p1 b4 p3 g2 g3 g4 b5 y1 y1 y1 r2 r2 y2 y3'
|
||||||
|
|
||||||
deck = [DeckCard(COLORS.index(c[0]), int(c[1])) for c in deck_str.split(" ")]
|
deck = [DeckCard(COLOR_INITIALS.index(c[0]), int(c[1])) for c in deck_str.split(" ")]
|
||||||
num_p = 5
|
num_p = 5
|
||||||
else:
|
else:
|
||||||
deck_str = "15gfvqluvuwaqnmrkpkaignlaxpjbmsprksfcddeybfixchuhtwo"
|
deck_str = "15gfvqluvuwaqnmrkpkaignlaxpjbmsprksfcddeybfixchuhtwo"
|
||||||
|
|
55
variants.py
55
variants.py
|
@ -13,3 +13,58 @@ def variant_name(variant_id):
|
||||||
|
|
||||||
def num_suits(variant_id):
|
def num_suits(variant_id):
|
||||||
return next(len(var['suits']) for var in VARIANTS if var['id'] == variant_id)
|
return next(len(var['suits']) for var in VARIANTS if var['id'] == variant_id)
|
||||||
|
|
||||||
|
def properties(variant_id):
|
||||||
|
return next(var for var in VARIANTS if var['id'] == variant_id)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
x = set()
|
||||||
|
c = set()
|
||||||
|
for var in VARIANTS:
|
||||||
|
for k in var.keys():
|
||||||
|
x.add(k)
|
||||||
|
for s in var['suits']:
|
||||||
|
c.add(s)
|
||||||
|
for y in x:
|
||||||
|
print(y)
|
||||||
|
|
||||||
|
for s in c:
|
||||||
|
print(s)
|
||||||
|
|
||||||
|
# need: suit name -> colors
|
||||||
|
|
||||||
|
"""
|
||||||
|
# actual changes of theoretical instance
|
||||||
|
clueStarved
|
||||||
|
throwItInHole (no clues for fives)
|
||||||
|
|
||||||
|
# general restrictions on what clues are allowed
|
||||||
|
alternatingClues
|
||||||
|
clueColors
|
||||||
|
clueRanks
|
||||||
|
synesthesia (no rank clused, but color touches rank as well)
|
||||||
|
|
||||||
|
# can be ignored
|
||||||
|
cowPig
|
||||||
|
duck
|
||||||
|
|
||||||
|
# -> use oracle?
|
||||||
|
# clue touch changed
|
||||||
|
chimneys
|
||||||
|
funnels
|
||||||
|
colorCluesTouchNothing
|
||||||
|
rankCluesTouchNothing
|
||||||
|
oddsAndEvens (ranks touch ranks of same parity)
|
||||||
|
|
||||||
|
# changes behaviour of ones or fives
|
||||||
|
specialAllClueColors
|
||||||
|
specialAllClueRanks
|
||||||
|
specialNoClueColors
|
||||||
|
specialNoClueRanks
|
||||||
|
specialDeceptive
|
||||||
|
specialRank
|
||||||
|
|
||||||
|
upOrDown
|
||||||
|
criticalFours
|
||||||
|
"""
|
||||||
|
|
Loading…
Reference in a new issue