add code to compress whole json games
This commit is contained in:
parent
b19fc187d6
commit
26f5e2f3f1
1 changed files with 69 additions and 2 deletions
71
compress.py
71
compress.py
|
@ -1,23 +1,35 @@
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
import more_itertools
|
||||||
|
|
||||||
BASE62 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
BASE62 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
COLORS = 'rygbp'
|
COLORS = 'rygbp'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
with open("variants.json", 'r') as f:
|
||||||
|
VARIANTS = json.loads(f.read())
|
||||||
|
|
||||||
|
def variant_id(variant):
|
||||||
|
return next(var['id'] for var in VARIANTS if var['name'] == variant)
|
||||||
|
|
||||||
|
|
||||||
## Helper method, iterate over chunks of length n in a string
|
## Helper method, iterate over chunks of length n in a string
|
||||||
def chunks(s: str, n: int):
|
def chunks(s: str, n: int):
|
||||||
for i in range(0, len(s), n):
|
for i in range(0, len(s), n):
|
||||||
yield s[i:i+n]
|
yield s[i:i+n]
|
||||||
|
|
||||||
|
|
||||||
class DeckCard():
|
class DeckCard():
|
||||||
def __init__(self, suitIndex: int, rank: int):
|
def __init__(self, suitIndex: int, rank: int):
|
||||||
self.suitIndex: int = suitIndex
|
self.suitIndex: int = suitIndex
|
||||||
self.rank: int = rank
|
self.rank: int = rank
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_json(deck_card):
|
||||||
|
return DeckCard(**deck_card)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.suitIndex == other.suitIndex and self.rank == other.rank
|
return self.suitIndex == other.suitIndex and self.rank == other.rank
|
||||||
|
|
||||||
|
@ -38,6 +50,15 @@ class Action():
|
||||||
self.target = target
|
self.target = target
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_json(action):
|
||||||
|
print("Converting {} to an action".format(action))
|
||||||
|
return Action(
|
||||||
|
ActionType(action['type']),
|
||||||
|
int(action['target']),
|
||||||
|
action.get('value', None)
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
match self.type:
|
match self.type:
|
||||||
case ActionType.Play:
|
case ActionType.Play:
|
||||||
|
@ -50,10 +71,12 @@ class Action():
|
||||||
return "Clue rank {} to player {}".format(self.value, self.target)
|
return "Clue rank {} to player {}".format(self.value, self.target)
|
||||||
case ActionType.EndGame:
|
case ActionType.EndGame:
|
||||||
return "Player {} ends the game (code {})".format(self.target, self.value)
|
return "Player {} ends the game (code {})".format(self.target, self.value)
|
||||||
|
return "Undefined"
|
||||||
|
|
||||||
def compress_actions(actions: List[Action]) -> str:
|
def compress_actions(actions: List[Action]) -> str:
|
||||||
minType = 0
|
minType = 0
|
||||||
maxType = 0
|
maxType = 0
|
||||||
|
print(actions)
|
||||||
if len(actions) != 0:
|
if len(actions) != 0:
|
||||||
minType = min(map(lambda a: a.type.value, actions))
|
minType = min(map(lambda a: a.type.value, actions))
|
||||||
maxType = max(map(lambda a: a.type.value, actions))
|
maxType = max(map(lambda a: a.type.value, actions))
|
||||||
|
@ -72,8 +95,10 @@ def decompress_actions(actions_str: str) -> List[Action]:
|
||||||
minType = int(actions_str[0])
|
minType = int(actions_str[0])
|
||||||
maxType = int(actions_str[1])
|
maxType = int(actions_str[1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError("invalid action string")
|
raise ValueError("invalid action string: invalid min/max range")
|
||||||
assert(maxType >= minType)
|
assert(maxType >= minType)
|
||||||
|
if not len(actions_str) % 2 == 0:
|
||||||
|
raise ValueError("Invalid length of action str")
|
||||||
typeRange = maxType - minType + 1
|
typeRange = maxType - minType + 1
|
||||||
def decompress_action(action):
|
def decompress_action(action):
|
||||||
actionType = ActionType(BASE62.index(action[0]) % typeRange)
|
actionType = ActionType(BASE62.index(action[0]) % typeRange)
|
||||||
|
@ -111,6 +136,40 @@ def decompress_deck(deck_str: str) -> List[DeckCard]:
|
||||||
return [decompress_card(c) for c in deck_str[2:]]
|
return [decompress_card(c) for c in deck_str[2:]]
|
||||||
|
|
||||||
|
|
||||||
|
def compressJSONGame(game_json: dict) -> str:
|
||||||
|
out = ""
|
||||||
|
num_players = len(game_json.get('players', []))
|
||||||
|
num_players = game_json.get('num_players', num_players)
|
||||||
|
if not 2 <= num_players:
|
||||||
|
raise ValueError("Invalid JSON game: could not parse num players")
|
||||||
|
out = "{}".format(num_players)
|
||||||
|
try:
|
||||||
|
deck = game_json['deck']
|
||||||
|
except:
|
||||||
|
raise KeyError("JSON game contains no deck")
|
||||||
|
assert(len(deck) > 0)
|
||||||
|
if type(deck[0]) != DeckCard:
|
||||||
|
try:
|
||||||
|
deck = [DeckCard.from_json(card) for card in deck]
|
||||||
|
except:
|
||||||
|
raise ValueError("invalid jSON format: could not convert to deck cards")
|
||||||
|
# now, deck is in the correct form
|
||||||
|
out += compress_deck(deck)
|
||||||
|
out += "," # first part finished
|
||||||
|
actions = game_json.get('actions', [])
|
||||||
|
if len(actions) == 0:
|
||||||
|
print("WARNING: action array is empty")
|
||||||
|
else:
|
||||||
|
if type(actions[0]) != Action:
|
||||||
|
try:
|
||||||
|
actions = [Action.from_json(action) for action in actions]
|
||||||
|
except:
|
||||||
|
raise ValueError("invalid JSON format: could not convert to actions")
|
||||||
|
out += compress_actions(actions)
|
||||||
|
out += ","
|
||||||
|
variant = game_json.get("variant", "No Variant")
|
||||||
|
out += str(variant_id(variant))
|
||||||
|
return ''.join(more_itertools.intersperse("-", out, 20))
|
||||||
|
|
||||||
## test
|
## test
|
||||||
|
|
||||||
|
@ -128,3 +187,11 @@ print(x)
|
||||||
c = '15ywseiijdqgholmnxcqrrxpvppvuukdkacakauswlmntfffbbgh'
|
c = '15ywseiijdqgholmnxcqrrxpvppvuukdkacakauswlmntfffbbgh'
|
||||||
l = decompress_deck(c)
|
l = decompress_deck(c)
|
||||||
print(l)
|
print(l)
|
||||||
|
|
||||||
|
|
||||||
|
game = {"deck": [{"rank": 5, "suitIndex": 4}, {"rank": 3, "suitIndex": 4}, {"rank": 4, "suitIndex": 3}, {"rank": 5, "suitIndex": 0}, {"rank": 4, "suitIndex": 1}, {"rank": 4, "suitIndex": 1}, {"rank": 5, "suitIndex": 1}, {"rank": 4, "suitIndex": 0}, {"rank": 2, "suitIndex": 3}, {"rank": 2, "suitIndex": 1}, {"rank": 3, "suitIndex": 1}, {"rank": 5, "suitIndex": 2}, {"rank": 2, "suitIndex": 2}, {"rank": 3, "suitIndex": 2}, {"rank": 4, "suitIndex": 2}, {"rank": 4, "suitIndex": 4}, {"rank": 3, "suitIndex": 0}, {"rank": 2, "suitIndex": 3}, {"rank": 3, "suitIndex": 3}, {"rank": 3, "suitIndex": 3}, {"rank": 4, "suitIndex": 4}, {"rank": 1, "suitIndex": 3}, {"rank": 2, "suitIndex": 4}, {"rank": 1, "suitIndex": 3}, {"rank": 1, "suitIndex": 3}, {"rank": 2, "suitIndex": 4}, {"rank": 1, "suitIndex": 4}, {"rank": 1, "suitIndex": 4}, {"rank": 1, "suitIndex": 2}, {"rank": 4, "suitIndex": 0}, {"rank": 1, "suitIndex": 2}, {"rank": 1, "suitIndex": 0}, {"rank": 3, "suitIndex": 0}, {"rank": 1, "suitIndex": 0}, {"rank": 1, "suitIndex": 2}, {"rank": 1, "suitIndex": 0}, {"rank": 1, "suitIndex": 4}, {"rank": 4, "suitIndex": 3}, {"rank": 3, "suitIndex": 4}, {"rank": 2, "suitIndex": 2}, {"rank": 3, "suitIndex": 2}, {"rank": 4, "suitIndex": 2}, {"rank": 5, "suitIndex": 3}, {"rank": 1, "suitIndex": 1}, {"rank": 1, "suitIndex": 1}, {"rank": 1, "suitIndex": 1}, {"rank": 2, "suitIndex": 0}, {"rank": 2, "suitIndex": 0}, {"rank": 2, "suitIndex": 1}, {"rank": 3, "suitIndex": 1}], "first_player": 0, "options": {"variant": "No Variant"}, "players": ["Alice", "Bob", "Cathy", "Donald", "Emily"], "actions": [{"type": 4, "target": 0, "value": 4}]}
|
||||||
|
|
||||||
|
print("STARTING TEST")
|
||||||
|
c = compressJSONGame(game)
|
||||||
|
print(c)
|
||||||
|
print("hanab.live/shared-replay-json/" + c)
|
||||||
|
|
Loading…
Reference in a new issue