diff --git a/ono_sendai/animation/0.txt b/ono_sendai/animation/0.txt index 82698f9..4536e6b 100644 --- a/ono_sendai/animation/0.txt +++ b/ono_sendai/animation/0.txt @@ -20,4 +20,4 @@ -LOADING... + WAIT... diff --git a/ono_sendai/animation/1.txt b/ono_sendai/animation/1.txt index 407f903..5170e74 100644 --- a/ono_sendai/animation/1.txt +++ b/ono_sendai/animation/1.txt @@ -20,4 +20,4 @@ Φ╚╫╫╫╫` ▀╬╫N╨▌ ▒╩╫╫╫▌ ▀╫╫╧* -LOADING... + WAIT... diff --git a/ono_sendai/animation/2.txt b/ono_sendai/animation/2.txt index ee986f5..c1b328c 100644 --- a/ono_sendai/animation/2.txt +++ b/ono_sendai/animation/2.txt @@ -20,4 +20,4 @@ "╩Ñ╬▌ ╙ÑÑ╨` -LOADING... + WAIT... diff --git a/ono_sendai/animation/3.txt b/ono_sendai/animation/3.txt index 462f18b..b957e0e 100644 --- a/ono_sendai/animation/3.txt +++ b/ono_sendai/animation/3.txt @@ -20,4 +20,4 @@ ` .╬]╫╫╫╫╛ ╙▓╫╫N╨╫⌐ ` "╩Ñ╣▀ ╙ÑÑ" -LOADING... + WAIT... diff --git a/ono_sendai/animation/4.txt b/ono_sendai/animation/4.txt index 2844d0a..59e16cd 100644 --- a/ono_sendai/animation/4.txt +++ b/ono_sendai/animation/4.txt @@ -20,4 +20,4 @@ '╝╨'"╜▀ßM^` ▒╨╫╫╫╫⌐ ▀╬╫Ñ╙╫⌐ └╝╧╙└` ╜┘ "╩ÑÑ╩ ▀ÑÑ"` -LOADING... + WAIT... diff --git a/ono_sendai/animation/__pycache__/octopus.cpython-36.pyc b/ono_sendai/animation/__pycache__/octopus.cpython-36.pyc new file mode 100644 index 0000000..fe60c53 Binary files /dev/null and b/ono_sendai/animation/__pycache__/octopus.cpython-36.pyc differ diff --git a/ono_sendai/prova.py b/ono_sendai/main.py similarity index 75% rename from ono_sendai/prova.py rename to ono_sendai/main.py index 628b9d8..655ecd5 100644 --- a/ono_sendai/prova.py +++ b/ono_sendai/main.py @@ -11,12 +11,12 @@ from state import Table, Hand from metro_holografix.cardtypes import * import state -logging.basicConfig(level=logging.INFO, filename='game.log', filemode='a', format='%(levelname)s - %(message)s') +logging.basicConfig(level=logging.DEBUG, filename='/tmp/game.log', filemode='a', format='%(levelname)s - %(message)s') logging.info("START") action = '' exit = False -ID = "you" +ID = "YOU" class FrameFactory: titles = ['0x10', '0x11', '0x12', '0x13', '0x14', '0x15', '0x16', '0x17', @@ -101,7 +101,16 @@ class FrameFactory: self.hand = w def getChoices(self): - src = (None, None); dst = None + def make_card(w): + s = w.items[w.choice][1] + if s == ' ': + s = w.items[1][1]; assert w.choice == 2 + v = w.items[w.choice][-3] + ve = 13 if v == 'K' else 12 if v == 'Q' else 11 if v == 'J' else 10 if v == '0' else int(v) + se = 'Pikes' if s == '♠' else 'Hearts' if s == '♥' else 'Tiles' if s == '♦' else 'Clovers' + return Card(se, ve) + + src = (None, None); dst = None; card = None if self.widgets[0].choice == 0: dst = 'Empty' @@ -111,11 +120,15 @@ class FrameFactory: for i, w in enumerate(self.widgets[1:]): if w.choice == 0: assert dst != 'Empty' + logging.debug(f'{w.items} , {i}: {w.choice}') dst = i elif w.choice > 1: assert src[0] != 'Hand' + logging.debug(f'{w.items} , {i}: {w.choice}') src = i, w.choice-2 - return src, dst + card = make_card(w) + + return src, dst, card def makeButtons(dialog, stats): buttonSend = WColoredButton(7, "SND", C_RED) @@ -196,7 +209,7 @@ def spawn_and_wait(tstr, difficulty): output = r.read() return output -def validate_auto_play(original, nl): +def validate_auto_play(otable, ohand, nl): # nl is a nested list of taggedcards, but without type # must reconstruct def make_cards(l): @@ -207,17 +220,39 @@ def validate_auto_play(original, nl): hand = Hand([c for cards in [p.cards for p in pp if p.tag == 'NonValido'] for c in cards]) table = Table([p for p in pp if p.tag == 'Valido']) assert len(table.cards) == 0 or table.is_valid() - if original.equality(table) == True: + assert len(otable.flatten()) + len(ohand.cards) == len(hand.cards) + len(table.flatten()) + if otable.equality(table) == True: return 'DRAW' else: return table, hand - + +def dispatchMove(game, src, dst, to_move): + if src[0] is None or src[1] is None or dst is None: + return + else: + table, hand = game.last() + t, h = None, None + if src[0] == 'Hand' and dst == 'Empty': + t, h = state.fromHandToEmpty(table, hand, src[1]) + elif src[0] == 'Hand' and type(dst) is int: + t, h = state.fromHandToTable(table, hand, src[1], dst) + elif type(src[0]) is int and dst == 'Empty': + t, h = state.fromTableToEmpty(table, hand, src, to_move) + elif type(src[0]) is int and type(dst) is int: + t, h = state.fromTableToTable(table, hand, src, dst, to_move) + else: + assert False + + assert t is not None and h is not None + logging.info(f"MOVE ({game.nrounds}): {game.cur_player} = {src}:{dst}") + return game.advance(t, h) + def make_auto_move(original, game, difficulty): table, hand = game.last() tstr = state.toJson(table, hand) output = spawn_and_wait(tstr, difficulty) - res = validate_auto_play(original, json.loads(output)) + res = validate_auto_play(table, hand, json.loads(output)) if type(res) is str: logging.info(f"BOT-DRAW ({game.nrounds}): {game.cur_player} = {game.last()}") game.draw() @@ -230,10 +265,12 @@ def make_auto_move(original, game, difficulty): game.next_turn() -def main(difficulty): - global exit, action +def main(difficulty, dbg=False): + global exit, action - game = state.State(["bot1", ID]) + dbgCnt = 0 + + game = state.State(ID, ["PVR", ID]) # game = state.State([ID, "bot1"]) game.next_turn() @@ -243,8 +280,11 @@ def main(difficulty): make_auto_move(game.last()[0], game, difficulty) if game.hasEnded == True: break - if game.hasEnded == True: - break + + if dbgCnt >= 3: + dbgCnt = 0 + from IPython import embed as fuck + fuck() with Context(): @@ -256,9 +296,12 @@ def main(difficulty): f = FrameFactory(dialog) stats = f' Round: {game.nrounds} - ' - for idp, h in game.players.items(): - stats += f'{idp}: {len(h.cards)}, ' - stats = stats[:-2] + ' ' # remove last comma + if game.hasEnded: + stats += f'Winner: {game.winner}' + else: + for idp, h in game.players.items(): + stats += f'{idp}: {len(h.cards)}, ' + stats = stats[:-2] + ' ' # remove last comma makeButtons(dialog, stats) #### FRAMES #### @@ -271,17 +314,16 @@ def main(difficulty): res = dialog.loop() if res == 1001 or res == 9: # or res == KEY_END or res == KEY_ESC: # 1001 is exit? # 9 is ctrl-c exit = True + elif game.hasEnded: + pass else: if action == 'EXIT': exit = True elif action == 'MOVE' or res == KEY_ENTER or res == b'm': # TODO: transition effect - src, dst = f.getChoices() - if src[0] is not None and src[1] is not None and dst is not None: - game.move_and_advance(src, dst) # get them from next - logging.info(f"MOVE ({game.nrounds}): {game.cur_player} = {src}:{dst}") - else: - continue + src, dst, ccard = f.getChoices() + logging.debug(ccard) + dispatchMove(game, src, dst, ccard) elif action == 'DRAW' or res == b'd': logging.info(f"DRAW ({game.nrounds}): {game.cur_player} = {game.last()}") game.draw() @@ -303,27 +345,40 @@ def main(difficulty): elif action == 'BACK': game.backtrack() logging.info(f"BACK ({game.nrounds}): {game.cur_player}") + elif res == b'p' and dbg == True: + dbgCnt += 1 else: pass if game.hasEnded: print(f'{Fore.RED}' + "Game has ended, player '" + game.winner + "' has won"+f'{Style.RESET_ALL}') - + else: + s = input(f'{Fore.MAGENTA}Do you want to save the game? (y/n)\n') + while s.lower() not in ['y', 'yes', 'n', 'no']: + s = input(f"{Fore.MAGENTA}Please write 'y' or 'n'\n") + print(f'{Style.RESET_ALL}') + if s.lower() == 'y' or s.lower() == 'yes': + game.dump() if __name__ == '__main__': from sys import argv print(argv[1]) diff = argv[1] + dbg = 'DEBUG' in argv if diff == 'easy': - main(7) + main(7, dbg) elif diff == 'medium': - main(14) + main(14, dbg) elif diff == 'hard': - main(21) + main(21, dbg) else: try: diff = int(diff) except: print('Wrong argument for difficulty') - main(int(diff)) + main(int(diff), dbg) + + +print('cli interface') +print('initial screen') diff --git a/ono_sendai/save.final b/ono_sendai/save.final new file mode 100644 index 0000000..a0804f8 --- /dev/null +++ b/ono_sendai/save.final @@ -0,0 +1 @@ +{"table": [[["Clovers", 3], ["Hearts", 3], ["Pikes", 3], ["Tiles", 3]], [["Clovers", 8], ["Hearts", 8], ["Pikes", 8]], [["Clovers", 13], ["Hearts", 13], ["Tiles", 13]], [["Clovers", 2], ["Hearts", 2], ["Tiles", 2]], [["Clovers", 1], ["Hearts", 1], ["Tiles", 1]], [["Clovers", 4], ["Pikes", 4], ["Tiles", 4]], [["Hearts", 5], ["Hearts", 6], ["Hearts", 7], ["Hearts", 8]], [["Clovers", 10], ["Clovers", 11], ["Clovers", 9]], [["Hearts", 2], ["Hearts", 3], ["Hearts", 4]], [["Pikes", 1], ["Pikes", 12], ["Pikes", 13]], [["Hearts", 10], ["Hearts", 11], ["Hearts", 12]]], "PVR": [["Clovers", 2], ["Pikes", 5], ["Clovers", 6], ["Hearts", 7], ["Pikes", 7], ["Pikes", 7], ["Pikes", 9], ["Tiles", 9], ["Tiles", 11], ["Tiles", 11]], "YOU": [["Tiles", 6], ["Clovers", 7], ["Tiles", 9], ["Hearts", 10], ["Pikes", 10], ["Pikes", 11], ["Tiles", 12], ["Tiles", 13]], "nrounds": 25, "players": ["PVR", "YOU"]} \ No newline at end of file diff --git a/ono_sendai/state.py b/ono_sendai/state.py index b6c8953..b6f4d77 100644 --- a/ono_sendai/state.py +++ b/ono_sendai/state.py @@ -88,7 +88,9 @@ class WrongMoveException(Exception): pass class State: - def __init__(self, ids): + def __init__(self, human, ids): + assert human in ids + self.humanPlayer = human self.deck = make_deck() self.winner = None self.hasEnded = False @@ -124,8 +126,8 @@ class State: if original.equality(table): raise WrongMoveException() elif not table.is_valid() or len(set(original.flatten()) - set(table.flatten())) != 0: - if self.cur_player != 'you': - fuck() # debug + if self.cur_player != self.humanPlayer: + fuck() # debug # TODO: should remove raise WrongMoveException() else: self.table, self.players[self.cur_player] = table, hand @@ -147,16 +149,34 @@ class State: def size(self): return len(self.turn) - def move_and_advance(self, src, dst): - table, hand = self.last() - t, h = gioca(table, hand, src, dst) - self.turn.append((t, h)) - return t, h - def advance(self, table, hand): self.turn.append((table, hand)) return table, hand + def dump(self): + j = dict() + j['table'] = [tc.cards for tc in self.table.cards] + for pl, hand in self.players.items(): + j[pl] = hand.cards + j['nrounds'] = self.nrounds + j['players'] = list(self.players.keys()) + with open('save.machiavelli', 'w') as f: + f.write(json.dumps(j)) + return j + + def load(self): + with open('save.machiavelli', 'r') as f: + j = json.loads(f.read()) + self.nrounds = j['nrounds'] + tcards = [] + for tc in j['table']: + tcards.append(TaggedCards([Card(seed, value) for seed, value in tc])) + self.table = Table(tcards) + self.players = dict() + for pl in j['players']: + self.players[pl] = Hand([Card(seed, value) for seed, value in j[pl]]) + + def fromJson(j): hcards = [Card(seed, value) for seed, value in j['hand']] tcards = [] @@ -172,30 +192,110 @@ def toJson(table, hand): j['table'].append(tc.cards) return json.dumps(j) -# TODO: refactor language -def gioca(tavolo, hand, src, dst): - giocata = [] if dst == 'Empty' else tavolo.cards[dst] - da_muovere = hand.cards[src[1]] if src[0] == 'Hand' else tavolo.cards[src[0]].cards[src[1]] - hcards = hand.cards[:src[1]] + hand.cards[src[1]+1:] if src[0] == 'Hand' else hand.cards - assert src[0] != 'Hand' or len(hcards) == len(hand.cards) - 1 +# def gioca(tavolo, hand, src, dst): +# giocata = [] if dst == 'Empty' else tavolo.cards[dst] +# da_muovere = hand.cards[src[1]] if src[0] == 'Hand' else tavolo.cards[src[0]].cards[src[1]] +# hcards = hand.cards[:src[1]] + hand.cards[src[1]+1:] if src[0] == 'Hand' else hand.cards +# assert src[0] != 'Hand' or len(hcards) == len(hand.cards) - 1 - assert type(dst) is int or dst == 'Empty' - assert type(src[0]) is int or src[0] == 'Hand' - assert type(da_muovere) is Card - assert type(giocata) is TaggedCards or giocata == [] +# assert type(dst) is int or dst == 'Empty' +# assert type(src[0]) is int or src[0] == 'Hand' +# assert type(da_muovere) is Card +# assert type(giocata) is TaggedCards or giocata == [] - idx = -1 if dst == 'Empty' else tavolo.cards.index(giocata) - news = [TaggedCards([da_muovere])] if type(giocata) is list else [] - rimpiazzata = False - for i, t in enumerate(tavolo.cards): - if i == idx: - p = TaggedCards(giocata.cards + [da_muovere]) - news.append(p) - elif not rimpiazzata and da_muovere in t.cards: - t = [c for c in t.cards if c != da_muovere] - if t != []: - news.append(TaggedCards(t)) - rimpiazzata = True +# idx = -1 if dst == 'Empty' else tavolo.cards.index(giocata) +# if type(giocata) is list: # we want a new empty cell +# news = [TaggedCards([da_muovere])] +# else: +# news = [] + +def fromHandToEmpty(table, hand, src): + assert type(src) is int + to_move = hand.cards[src] + hcards = hand.cards[:src] + hand.cards[src+1:] + assert len(hcards) == len(hand.cards) - 1 + + assert type(to_move) is Card + + news = [TaggedCards([to_move])] + table.cards + newTable = Table(news) + assert len(newTable.flatten()) + len(hcards) == len(hand.cards) + len(table.flatten()), fuck() + return newTable, Hand(hcards) + +def fromHandToTable(table, hand, src, dst): + assert type(dst) is int + assert type(src) is int + + in_play = table.cards[dst] + to_move = hand.cards[src] + hcards = hand.cards[:src] + hand.cards[src+1:] + assert len(hcards) == len(hand.cards) - 1 + + assert type(to_move) is Card + assert type(in_play) is TaggedCards or in_play == [] + + idx = table.cards.index(in_play) + news = [] + news = table.cards[:dst] + table.cards[dst+1:] + [TaggedCards(table.cards[dst].cards + [to_move])] + newTable = Table(news) + assert len(newTable.flatten()) + len(hcards) == len(hand.cards) + len(table.flatten()), fuck() + return newTable, Hand(hcards) + +def removeFromTcards(t, to_move): + # tmp = [] + # for j, c in enumerate(t.cards): + # if c == to_move: + # break + # tmp.append(c) + # tmp.extend(t.cards[j+1:]) + # return tmp + cards = copy(t.cards) + cards.remove(to_move) + return cards + +def fromTableToEmpty(table, hand, src, to_move): + assert type(src) is tuple # TODO: unused src[1], even in other TableToTable + in_play = [] + tpos, cpos = src + hcards = hand.cards + + assert type(src[0]) is int + assert type(to_move) is Card + + news = [TaggedCards([to_move])] + + for i, t in enumerate(table.cards): + if tpos == i: + tmp = removeFromTcards(t, to_move) + if tmp != []: + news.append(TaggedCards(tmp)) else: news.append(t) - return Table(news), Hand(hcards) + newTable = Table(news) + assert len(newTable.flatten()) + len(hcards) == len(hand.cards) + len(table.flatten()), fuck() + return newTable, Hand(hcards) + +def fromTableToTable(table, hand, src, dst, to_move): + assert type(src) is tuple + in_play = table.cards[dst] + tpos, cpos = src + # to_move = table.cards[tpos].cards[cpos] + hcards = hand.cards + assert type(to_move) is Card + assert type(in_play) is TaggedCards + + news = [] + rimpiazzata = False + for i, t in enumerate(table.cards): + if i == dst: + p = TaggedCards(in_play.cards + [to_move]) + news.append(p) + elif tpos == i: + tmp = removeFromTcards(t, to_move) + if tmp != []: + news.append(TaggedCards(tmp)) + else: + news.append(t) + newTable = Table(news) + assert len(newTable.flatten()) + len(hcards) == len(hand.cards) + len(table.flatten()), fuck() + return newTable, Hand(hcards) diff --git a/ono_sendai/widgets.py b/ono_sendai/widgets.py index 24a8c29..47fb5a4 100644 --- a/ono_sendai/widgets.py +++ b/ono_sendai/widgets.py @@ -30,7 +30,7 @@ class WColoredButton(WButton): return r def handle_key(self, inp): - if inp in [KEY_ENTER, b's', b'd', b'm']: + if inp in [KEY_ENTER, b's', b'd', b'm', b'p']: return inp pass @@ -46,7 +46,7 @@ class WColoredFrame(WFrame): self.color = color def handle_key(self, inp): - if inp in [KEY_ENTER, b's', b'd', b'm']: + if inp in [KEY_ENTER, b's', b'd', b'm', b'p']: return inp pass @@ -91,7 +91,7 @@ class WCardRadioButton(WRadioButton): self.id = id def handle_key(self, inp): - if inp in [KEY_ENTER, b's', b'd', b'm']: + if inp in [KEY_ENTER, b's', b'd', b'm', b'p']: return inp pass