Octopus_Carnival/ono_sendai/prova.py

288 lines
8.7 KiB
Python
Raw Normal View History

2019-08-17 17:40:16 +02:00
from picotui.context import Context
from picotui.screen import Screen
from time import sleep
2019-08-19 00:12:42 +02:00
import os
2019-08-19 18:24:38 +02:00
import json
2019-08-17 17:40:16 +02:00
from widgets import *
2019-08-19 18:24:38 +02:00
from state import Table, Hand
from metro_holografix.cardtypes import *
2019-08-18 17:19:11 +02:00
import state
action = ''
exit = False
2019-08-19 00:12:42 +02:00
ID = "tui"
2019-08-19 18:24:38 +02:00
game = state.State(["bot1", ID])
2019-08-17 17:40:16 +02:00
class FrameFactory:
titles = ['0x10', '0x11', '0x12', '0x13', '0x14', '0x15', '0x16', '0x17',
'0x18', '0x19', '0x1A', '0x1B', '0x1D', '0x1E', '0x1F', '0x20',
'0x21', '0x22', '0x23', '0x24', '0x25', '0x26', '0x27',
'0x28', '0x29', '0x2A', '0x2B', '0x2D', '0x2E', '0x2F', '0x30'
'0x31', '0x32', '0x33', '0x34', '0x35', '0x36', '0x37', '0x00'] # more than enough
def __init__(self, d):
self.np = 13
self.d = d
self.widgets = []
self.x = 1 + self.np
self.y = 1
self.titlen = 0
self.hand = None
self.maxwidth = 0
2019-08-18 17:19:11 +02:00
def constrainAllWidgets(self, callerId):
cc = self.widgets[callerId].choice if id != -1 else self.hand.choice
# check hand first
if callerId != -1 and self.hand.choice > 1 and cc > 1:
self.hand.choice = 1
self.hand.redraw()
return
# check other widgets
for w in self.widgets:
if w.id != callerId and w.choice != 1:
if w.choice == 0 and cc == 0:
w.choice = 1
w.redraw()
return
elif w.choice > 1 and cc > 1:
w.choice = 1
w.redraw()
return
else:
pass
2019-08-17 17:40:16 +02:00
def newFrame(self, cards):
# can handle 9 frames per row
assert type(cards) is list, type(cards)
h = 2 + len(cards) # height ?
self.maxwidth = h if h > self.maxwidth else self.maxwidth
title = self.titles[self.titlen]
2019-08-18 17:19:11 +02:00
w = WCardRadioButton(cards, len(self.widgets), self.constrainAllWidgets)
2019-08-17 17:40:16 +02:00
self.d.add(self.x, self.y, WColoredFrame(12, h, title))
self.d.add(self.x+1, self.y+1, w)
self.widgets.append(w)
self.advance()
def advance(self):
self.x += self.np
self.titlen+=1
if self.x > self.np * 9:
# second row
self.y += self.maxwidth
self.x = 1 + self.np # first column for hand
def emptyFrame(self):
title = self.titles[-1]
2019-08-18 17:19:11 +02:00
w = WCardRadioButton(['', ''], len(self.widgets), self.constrainAllWidgets)
2019-08-17 17:40:16 +02:00
self.d.add(self.x, self.y, WColoredFrame(12, 4, title))
self.d.add(self.x+1, self.y+1, w)
self.widgets.append(w)
self.advance()
def newHandFrame(self, cards):
assert type(cards) is list, type(cards)
h = 27 # height ?
2019-08-19 00:12:42 +02:00
self.d.add(1, 1, WColoredFrame(12, h, 'HAND: '+str(len(cards)), blue))
2019-08-18 17:19:11 +02:00
coloredCards = [f'{Fore.BLUE}'+cards[0]] + cards[1:-1] + [cards[-1]+f'{Style.RESET_ALL}']
w = WCardRadioButton(coloredCards, -1, self.constrainAllWidgets, isHand=True)
2019-08-17 17:40:16 +02:00
self.d.add(2, 2, w)
self.hand = w
def getChoices(self):
2019-08-17 18:21:18 +02:00
src = (None, None); dst = None
2019-08-17 17:40:16 +02:00
if self.widgets[0].choice == 0:
dst = 'Empty'
2019-08-17 18:21:18 +02:00
if self.hand.choice > 1:
src = 'Hand', self.hand.choice-2
2019-08-17 17:40:16 +02:00
for i, w in enumerate(self.widgets[1:]):
if w.choice == 0:
assert dst != 'Empty'
dst = i
elif w.choice > 1:
2019-08-17 18:21:18 +02:00
assert src[0] != 'Hand'
2019-08-17 17:40:16 +02:00
src = i, w.choice-2
return src, dst
2019-08-18 17:19:11 +02:00
def makeButtons(d):
buttonSend = WColoredButton(7, "SND", C_RED)
dialog.add(108, 28, buttonSend)
buttonSend.finish_dialog = ACTION_OK
def btnSend(w):
global action; action = "SEND"
buttonSend.on_click = btnSend
buttonRst = WColoredButton(7, "RST", C_RED)
dialog.add(100, 28, buttonRst)
buttonRst.finish_dialog = ACTION_OK
def btnReset(w):
global action; action = "RESET"
buttonRst.on_click = btnReset
buttonMov = WColoredButton(7, "MOV", C_BLUE)
dialog.add(92, 28, buttonMov)
buttonMov.finish_dialog = ACTION_OK
def btnMove(w):
global action; action = "MOVE"
buttonMov.on_click = btnMove
buttonDraw = WColoredButton(7, "DRW", C_RED)
dialog.add(84, 28, buttonDraw)
buttonDraw.finish_dialog = ACTION_OK
def btnDraw(w):
global action; action = "DRAW"
buttonDraw.on_click = btnDraw
buttonAbort = WColoredButton(13, f'{Fore.BLACK}'+" ABRT "+f'{Style.RESET_ALL}', C_WHITE)
dialog.add(4, 28, buttonAbort)
buttonAbort.finish_dialog = ACTION_OK
def doExit(w):
global action ; action = "EXIT"
buttonAbort.on_click = doExit
buttonback = WColoredButton(7, " BAK ", C_MAGENTA)
dialog.add(76, 28, buttonback)
buttonback.finish_dialog = ACTION_OK
def doBack(w):
global action ; action = "BACK"
buttonback.on_click = doBack
2019-08-17 17:40:16 +02:00
2019-08-19 00:12:42 +02:00
def wrong_play():
from sys import stdout
os.system('clear')
print(f'{Fore.RED}'+'Wrong play. Retry...'+f'{Style.RESET_ALL}')
sleep(2)
2019-08-19 18:24:38 +02:00
def spawn_and_wait(str):
2019-08-19 00:12:42 +02:00
import sys
2019-08-19 18:24:38 +02:00
from subprocess import PIPE, Popen
2019-08-19 00:12:42 +02:00
from animation.octopus import animate
2019-08-19 18:24:38 +02:00
r, w = os.pipe()
2019-08-19 00:12:42 +02:00
pid = os.fork()
if pid == 0:
# child
2019-08-19 18:24:38 +02:00
os.close(r)
res = Popen(["../hosaka/_build/default/main.exe"], stdout=PIPE, stdin=PIPE)
out, err = res.communicate(str.encode('utf-8'))
res.stdin.close()
w = os.fdopen(w, 'w')
w.write(out.decode('utf-8'))
2019-08-19 00:12:42 +02:00
sys.exit()
else:
2019-08-19 18:24:38 +02:00
os.close(w)
2019-08-19 00:12:42 +02:00
p = os.waitpid(pid, os.WNOHANG)
while p == (0, 0):
animate(10)
p = os.waitpid(pid, os.WNOHANG)
2019-08-19 18:24:38 +02:00
r = os.fdopen(r)
output = r.read()
return output
def validate_auto_play(original, nl):
# nl is a nested list of taggedcards, but without type
# must reconstruct
def make_cards(l):
return Card(*l)
pp = []
for ts in nl:
pp.append(TaggedCards([make_cards(cl) for cl in ts]))
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:
return 'DRAW'
else:
return table, hand
def make_auto_move(original, game):
table, hand = game.last()
tstr = state.toJson(table, hand)
output = spawn_and_wait(tstr)
res = validate_auto_play(original, json.loads(output))
if type(res) is str:
2019-08-19 00:12:42 +02:00
game.draw()
2019-08-19 18:24:38 +02:00
elif type(res) is tuple:
game.advance(*res)
game.done()
else:
assert False, type(res)
game.next_turn()
2019-08-19 00:12:42 +02:00
game.next_turn()
2019-08-19 18:24:38 +02:00
while not exit and not game.hasEnded:
2019-08-19 00:12:42 +02:00
while game.cur_player != ID:
2019-08-19 18:24:38 +02:00
make_auto_move(game.last()[0], game)
if game.hasEnded == True:
break
if game.hasEnded == True:
break
2019-08-19 00:12:42 +02:00
2019-08-17 17:40:16 +02:00
with Context():
2019-08-19 18:24:38 +02:00
table, hand = game.last()
2019-08-17 17:40:16 +02:00
Screen.attr_color(C_WHITE, C_GREEN)
Screen.cls()
Screen.attr_reset()
2019-08-18 17:19:11 +02:00
dialog = Dialog(1, 1, 120, 30)
f = FrameFactory(dialog)
makeButtons(dialog)
2019-08-17 17:40:16 +02:00
#### FRAMES ####
f.emptyFrame()
for cards in table.widget_repr():
f.newFrame(cards)
2019-08-17 18:21:18 +02:00
f.newHandFrame(hand.widget_repr())
2019-08-17 17:40:16 +02:00
2019-08-18 17:19:11 +02:00
dialog.redraw()
res = dialog.loop()
2019-08-17 17:40:16 +02:00
if res == 1001 or res == 9: # or res == KEY_END or res == KEY_ESC: # 1001 is exit? # 9 is ctrl-c
exit = True
else:
2019-08-18 17:19:11 +02:00
if action == 'EXIT':
exit = True
elif action == 'MOVE':
# TODO: transition effect
2019-08-19 18:24:38 +02:00
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
else:
continue
2019-08-18 17:19:11 +02:00
elif action == 'DRAW':
2019-08-19 00:12:42 +02:00
game.draw()
game.next_turn()
2019-08-18 17:19:11 +02:00
elif action == 'RESET':
2019-08-19 00:12:42 +02:00
while game.size() > 1:
game.backtrack()
2019-08-18 17:19:11 +02:00
elif action == 'SEND':
2019-08-19 00:12:42 +02:00
try:
game.done()
game.next_turn()
except state.WrongMoveException as e:
wrong_play()
2019-08-18 17:19:11 +02:00
elif action == 'BACK':
2019-08-19 00:12:42 +02:00
game.backtrack()
2019-08-18 17:19:11 +02:00
else:
assert False
2019-08-19 18:24:38 +02:00
if game.hasEnded:
print(f'{Fore.RED}' + "Game has ended, player '" + game.winner + "' has won"+f'{Style.RESET_ALL}')
print('TODO: ordina per bene KQ12, mostra le carte in mano agli altri')
print('LOGGER')
print('magari perche` la mossa e` sbagliata')