Create Rogue Duel
This commit is contained in:
parent
f8b5d804df
commit
a705e5d38c
2 changed files with 141 additions and 3 deletions
21
cube_pool.py
21
cube_pool.py
|
|
@ -1,10 +1,11 @@
|
||||||
# Loads disjoint pools from a cube CSV
|
# Loads disjoint pools from a cube CSV
|
||||||
|
|
||||||
|
import collections
|
||||||
import csv
|
import csv
|
||||||
import itertools
|
import itertools
|
||||||
import random
|
import random
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, Set
|
from typing import Dict, List, Set
|
||||||
|
|
||||||
import cubecobra_csv
|
import cubecobra_csv
|
||||||
|
|
||||||
|
|
@ -17,9 +18,23 @@ class CubePool:
|
||||||
assert color_category in 'wubrgchml', f'{card_name}: {color_category}'
|
assert color_category in 'wubrgchml', f'{card_name}: {color_category}'
|
||||||
self._categories[color_category].append(card_name)
|
self._categories[color_category].append(card_name)
|
||||||
|
|
||||||
def wide_sample(self, n: int):
|
def wide_sample(self, n: int) -> List[str]:
|
||||||
wide_iterator = list(itertools.chain.from_iterable(self._categories.values()))
|
wide_iterator = list(itertools.chain.from_iterable(self._categories.values()))
|
||||||
return random.sample(wide_iterator, n)
|
sample = random.sample(wide_iterator, n)
|
||||||
|
return sample
|
||||||
|
|
||||||
|
def category_sample(self, color_category: str, n: int) -> List[str]:
|
||||||
|
return random.sample(self._categories[color_category], n)
|
||||||
|
|
||||||
|
def draw_from_category(self, color_category: str, n: int) -> List[str]:
|
||||||
|
drawn = self.category_sample(color_category, n)
|
||||||
|
self.remove_cards(drawn, color_category)
|
||||||
|
return drawn
|
||||||
|
|
||||||
|
def remove_cards(self, removed: List[str], color_category: str):
|
||||||
|
existing_counter = collections.Counter(self._categories[color_category])
|
||||||
|
removed_counter = collections.Counter(removed)
|
||||||
|
self._categories[color_category] = list((existing_counter - removed_counter).elements())
|
||||||
|
|
||||||
|
|
||||||
def load_pools(csv_path: str, pool_tags: Set[str]) -> Dict[str, CubePool]:
|
def load_pools(csv_path: str, pool_tags: Set[str]) -> Dict[str, CubePool]:
|
||||||
|
|
|
||||||
123
rogue_duel.py
Normal file
123
rogue_duel.py
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
# Play Rogue Duel, a 2-player format in which players duel multiple times,
|
||||||
|
# improving their decks between games.
|
||||||
|
|
||||||
|
import random
|
||||||
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
|
import cube_json
|
||||||
|
import cube_pool
|
||||||
|
|
||||||
|
CUBE_NAME = 'TheElegantCube_fetched'
|
||||||
|
|
||||||
|
|
||||||
|
class RogueDuelPlayerState:
|
||||||
|
def __init__(self):
|
||||||
|
self.colors = []
|
||||||
|
self.deck = []
|
||||||
|
|
||||||
|
|
||||||
|
class RogueDuelState:
|
||||||
|
def __init__(self):
|
||||||
|
self.player1 = RogueDuelPlayerState()
|
||||||
|
self.player2 = RogueDuelPlayerState()
|
||||||
|
self.player_states = (self.player1, self.player2)
|
||||||
|
|
||||||
|
csv_path = cube_json.request_cube_csv('TheElegantCube_fetched', 'elegant')
|
||||||
|
self.pools: Dict[str, cube_pool.CubePool] = cube_pool.load_pools(csv_path, {'core', 'occasional'})
|
||||||
|
self.discard_pile: List[str] = []
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
state = RogueDuelState()
|
||||||
|
_decide_colors(state)
|
||||||
|
_pick_artifacts(state)
|
||||||
|
_fill_with_lands(state)
|
||||||
|
print(state.player1.deck)
|
||||||
|
print(state.player2.deck)
|
||||||
|
|
||||||
|
|
||||||
|
def _decide_colors(state: RogueDuelState):
|
||||||
|
sealed_pools: Dict[str, List[str]] = {}
|
||||||
|
for color_category in 'wubrg':
|
||||||
|
sealed_pools[color_category] = (state.pools['core'].draw_from_category(color_category, 6) +
|
||||||
|
state.pools['occasional'].draw_from_category(color_category, 2))
|
||||||
|
print(sealed_pools)
|
||||||
|
|
||||||
|
colors_available = list('wubrg')
|
||||||
|
color = random.choice('wubrg')
|
||||||
|
colors_available.remove(color)
|
||||||
|
print(f'Player 1 assigned color: {color}')
|
||||||
|
state.player1.colors.append(color)
|
||||||
|
state.player1.deck.extend(sealed_pools[color])
|
||||||
|
|
||||||
|
color = _pick_a_color(colors_available, 'Player 2, choose your first color from:')
|
||||||
|
state.player2.colors.append(color)
|
||||||
|
state.player2.deck.extend(sealed_pools[color])
|
||||||
|
|
||||||
|
color = _pick_a_color(colors_available, 'Player 1, choose your second color from:')
|
||||||
|
state.player1.colors.append(color)
|
||||||
|
state.player1.deck.extend(sealed_pools[color])
|
||||||
|
|
||||||
|
color = _pick_a_color(colors_available, 'Player 2, choose your second color from:')
|
||||||
|
state.player2.colors.append(color)
|
||||||
|
state.player2.deck.extend(sealed_pools[color])
|
||||||
|
|
||||||
|
state.discard_pile.extend(sealed_pools[colors_available[0]])
|
||||||
|
|
||||||
|
|
||||||
|
def _pick_a_color(colors_available: List[str], prompt: str) -> str:
|
||||||
|
color = ''
|
||||||
|
while color not in colors_available:
|
||||||
|
color = input(f'{prompt} {colors_available}')
|
||||||
|
colors_available.remove(color)
|
||||||
|
return color
|
||||||
|
|
||||||
|
|
||||||
|
def _pick_artifacts(state: RogueDuelState):
|
||||||
|
artifact_pool: List[str] = (state.pools['core'].draw_from_category('c', 4) +
|
||||||
|
state.pools['occasional'].draw_from_category('c', 1))
|
||||||
|
print(artifact_pool)
|
||||||
|
card = _pick_a_card(artifact_pool, 'Player 1, choose an artifact:')
|
||||||
|
state.player1.deck.append(card)
|
||||||
|
card = _pick_a_card(artifact_pool, 'Player 2, choose an artifact:')
|
||||||
|
state.player2.deck.append(card)
|
||||||
|
state.discard_pile.extend(artifact_pool)
|
||||||
|
|
||||||
|
|
||||||
|
def _pick_a_card(cards_available: List[str], prompt: str) -> str:
|
||||||
|
for i, card in enumerate(cards_available, 1):
|
||||||
|
print(f'[{i:>2}] {card}')
|
||||||
|
index_chosen = -1
|
||||||
|
while index_chosen < 0 or index_chosen >= len(cards_available):
|
||||||
|
index_chosen = int(input(prompt)) - 1
|
||||||
|
card_chosen = cards_available[index_chosen]
|
||||||
|
cards_available.remove(card_chosen)
|
||||||
|
return card_chosen
|
||||||
|
|
||||||
|
|
||||||
|
def _fill_with_lands(state: RogueDuelState):
|
||||||
|
RAINBOW_DUALS = ['Terramorphic Expanse', 'Evolving Wilds']
|
||||||
|
state.pools['core'].remove_cards(RAINBOW_DUALS, 'l')
|
||||||
|
for player_state, rainbow_land in zip(state.player_states, RAINBOW_DUALS):
|
||||||
|
for color in player_state.colors:
|
||||||
|
player_state.deck.extend(5 * [_basic_for_color(color)])
|
||||||
|
player_state.deck.append(rainbow_land)
|
||||||
|
# Add two duals
|
||||||
|
duals = _fetch_duals(state, player_state.colors)
|
||||||
|
#assert len(duals) == 2, f'Found duals {duals} for colors {player_state.colors}'
|
||||||
|
player_state.deck.extend(duals)
|
||||||
|
|
||||||
|
|
||||||
|
def _basic_for_color(color: str) -> str:
|
||||||
|
return {'w': 'Plains', 'u': 'Island', 'b': 'Swamp', 'r': 'Mountain', 'g': 'Forest'}[color]
|
||||||
|
|
||||||
|
|
||||||
|
def _fetch_duals(state: RogueDuelState, colors: List[str]) -> List[str]:
|
||||||
|
duals = []
|
||||||
|
# Get duals
|
||||||
|
state.pools['core'].remove_cards(duals, 'l')
|
||||||
|
return duals
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue