Integrate panel to bidding

master
En Yi 2019-06-14 00:04:26 +01:00
parent 016a39a466
commit f88b0abda3
4 changed files with 129 additions and 49 deletions

89
UI.py
View File

@ -5,6 +5,8 @@ from signalslot import Signal
class GenericUI: class GenericUI:
def __init__(self, x, y, width, height): def __init__(self, x, y, width, height):
self.draw_update = Signal()
self.x = x self.x = x
self.y = y self.y = y
self.width = width self.width = width
@ -82,13 +84,13 @@ class TextBox(GenericUI):
def redraw(self): def redraw(self):
super().redraw() super().redraw()
if self.visible: #if self.visible:
outline = (0, 0, self.rect.w, self.rect.h) outline = (0, 0, self.rect.w, self.rect.h)
pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness) pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness)
rendered_text = self.font.render(self.text, True, self.text_colour).convert_alpha() rendered_text = self.font.render(self.text, True, self.text_colour).convert_alpha()
rect_center = self.background.get_rect().center rect_center = self.background.get_rect().center
text_rect = rendered_text.get_rect(center=rect_center) text_rect = rendered_text.get_rect(center=rect_center)
self.background.blit(rendered_text, text_rect) self.background.blit(rendered_text, text_rect)
def set_text(self, text): def set_text(self, text):
self.text = text self.text = text
@ -112,13 +114,13 @@ class Button(TextBox):
self.background.fill((255, 255, 255)) self.background.fill((255, 255, 255))
else: else:
super().redraw() super().redraw()
if self.visible: #if self.visible:
outline = (0, 0, self.rect.w, self.rect.h) outline = (0, 0, self.rect.w, self.rect.h)
pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness) pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness)
rendered_text = self.font.render(self.text, True, self.text_colour).convert_alpha() rendered_text = self.font.render(self.text, True, self.text_colour).convert_alpha()
rect_center = self.background.get_rect().center rect_center = self.background.get_rect().center
text_rect = rendered_text.get_rect(center=rect_center) text_rect = rendered_text.get_rect(center=rect_center)
self.background.blit(rendered_text, text_rect) self.background.blit(rendered_text, text_rect)
def hold(self, *args): def hold(self, *args):
if not self.button_down: if not self.button_down:
@ -164,17 +166,17 @@ class ScrollList(GenericUI):
def redraw(self): def redraw(self):
super().redraw() super().redraw()
if self.visible: #if self.visible:
outline = (0, 0, self.rect.w, self.rect.h) outline = (0, 0, self.rect.w, self.rect.h)
pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness) pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness)
i = 0 i = 0
for text, text_rect in zip(self.texts, self.text_rects): for text, text_rect in zip(self.texts, self.text_rects):
if i == self.selected: if i == self.selected:
pygame.draw.rect(self.background, self.selected_colour, text_rect) pygame.draw.rect(self.background, self.selected_colour, text_rect)
rendered_text = self.font.render(text, True, self.text_colour).convert_alpha() rendered_text = self.font.render(text, True, self.text_colour).convert_alpha()
self.background.blit(rendered_text, text_rect) self.background.blit(rendered_text, text_rect)
i += 1 i += 1
def process_events(self, event): def process_events(self, event):
draw_update = super().process_events(event) draw_update = super().process_events(event)
@ -274,6 +276,7 @@ class ScrollList(GenericUI):
current_y += text_rect.height current_y += text_rect.height
self.max_offset = max(0, current_y - self.height - self.outline_thickness) self.max_offset = max(0, current_y - self.height - self.outline_thickness)
self.redraw() self.redraw()
self.draw_update.emit()
class CallPanel(GenericUI): class CallPanel(GenericUI):
@ -291,7 +294,7 @@ class CallPanel(GenericUI):
ui_width = 75 ui_width = 75
ui_height = 25 ui_height = 25
width_spacings = (width - 3 * ui_width - 2 * margins) / 4 width_spacings = (width - 3 * ui_width - 2 * margins) / 4
height_spacings = (height - 2 * margins - 2 * ui_height) / 3 height_spacings = (height - 2 * margins - 3 * ui_height) / 4
self.output_text = ['', ''] self.output_text = ['', '']
self.label1 = TextBox(margins+width_spacings, margins, self.label1 = TextBox(margins+width_spacings, margins,
@ -309,33 +312,39 @@ class CallPanel(GenericUI):
self.list2.list_selected.connect(lambda text, **z: self.print_list_selection(text, 1)) self.list2.list_selected.connect(lambda text, **z: self.print_list_selection(text, 1))
self.output_box = TextBox(margins+width_spacings*3+ui_width*2, margins+height_spacings, self.output_box = TextBox(margins+width_spacings*3+ui_width*2, margins+height_spacings,
ui_width, ui_height, text_size=self.text_size) ui_width, ui_height, text='Bid', text_size=self.text_size)
self.confirm_button = Button(margins+width_spacings*3+ui_width*2, margins+height_spacings*2+ui_height, self.confirm_button = Button(margins+width_spacings*3+ui_width*2, margins+height_spacings*2+ui_height,
ui_width, ui_height, text='OK', text_size=self.text_size) ui_width, ui_height, text='OK', text_size=self.text_size)
self.confirm_button.clicked.connect(self.emit_output) self.confirm_button.clicked.connect(self.emit_output)
self.cancel_button = Button(margins + width_spacings * 3 + ui_width * 2,
margins + height_spacings * 3 + ui_height * 2,
ui_width, ui_height, text='Cancel', text_size=self.text_size)
self.cancel_button.visible = False
self.cancel_button.clicked.connect(self.cancelling)
self.children = [self.label1, self.list1, self.label2, self.list2, self.children = [self.label1, self.list1, self.label2, self.list2,
self.confirm_button, self.output_box] self.confirm_button, self.output_box, self.cancel_button]
for element in self.children: for element in self.children:
element.parent = self element.parent = self
self.redraw() self.redraw()
def redraw(self): def redraw(self, **kwargs):
super().redraw() super().redraw()
#self.background.fill((255,0,255)) #self.background.fill((255,0,255))
if self.visible: #if self.visible:
outline = (0, 0, self.rect.w, self.rect.h) outline = (0, 0, self.rect.w, self.rect.h)
pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness) pygame.draw.rect(self.background, self.outline_colour, outline, self.outline_thickness)
for element in self.children: for element in self.children:
if element.visible:
self.background.blit(element.background, element.get_pos()) self.background.blit(element.background, element.get_pos())
def process_events(self, event): def process_events(self, event):
draw_update = False draw_update = False
for element in self.children: for element in self.children:
if element.process_events(event): if element.visible and element.process_events(event):
draw_update = True draw_update = True
if draw_update: if draw_update:
@ -347,9 +356,17 @@ class CallPanel(GenericUI):
self.output_box.set_text(' '.join(self.output_text)) self.output_box.set_text(' '.join(self.output_text))
def emit_output(self, **kwargs): def emit_output(self, **kwargs):
output = self.output_text[0]+self.output_text[1][0].lower() initial = ''
if self.output_text[1]:
initial = self.output_text[1][0].lower()
output = self.output_text[0].lower() + initial
self.confirm_output.emit(output=output) self.confirm_output.emit(output=output)
def cancelling(self, **kwargs):
self.confirm_output.emit(output='')
class TestScreen(view.PygView): class TestScreen(view.PygView):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -393,6 +410,10 @@ class TestScreen(view.PygView):
if event.key == pygame.K_ESCAPE: if event.key == pygame.K_ESCAPE:
running = False running = False
if event.key == pygame.K_o:
self.panel.list1.replace_list([str(i+1) for i in range(7)])
draw_update = True
for element in self.elements: for element in self.elements:
if element.process_events(event): if element.process_events(event):
draw_update = True draw_update = True

View File

@ -21,3 +21,4 @@ HIGHEST_CARD = 414
LOWEST_CARD = 102 LOWEST_CARD = 102
DOUBLE_CLICK_EVENT = pygame.USEREVENT + 1 DOUBLE_CLICK_EVENT = pygame.USEREVENT + 1
DOUBLE_CLICK_TIMING = 300 DOUBLE_CLICK_TIMING = 300
CALL_EVENT = pygame.USEREVENT + 2

View File

@ -1,7 +1,7 @@
import cards import cards
import pprint import pprint
import pygame import pygame
from game_consts import GameState, PlayerRole, STARTING_HAND, DOUBLE_CLICK_EVENT, DOUBLE_CLICK_TIMING from game_consts import GameState, PlayerRole, STARTING_HAND, DOUBLE_CLICK_EVENT, DOUBLE_CLICK_TIMING, CALL_EVENT
class Player(cards.Deck): class Player(cards.Deck):
@ -57,7 +57,7 @@ class Player(cards.Deck):
if sub_state == 0: if sub_state == 0:
if self.AI: if self.AI:
return self.AI.make_a_bid() return self.AI.make_a_bid()
return self.make_a_bid() return self.make_a_bid(game_events=game_events)
else: else:
if self.AI: if self.AI:
return self.AI.call_partner() return self.AI.call_partner()
@ -69,7 +69,7 @@ class Player(cards.Deck):
return self.remove_card(pos) return self.remove_card(pos)
return self.make_a_play(sub_state, game_events=game_events) return self.make_a_play(sub_state, game_events=game_events)
def make_a_bid(self): def make_a_bid(self, game_events=None):
""" """
The procedure to make a bid The procedure to make a bid
:return: A valid bid number :return: A valid bid number
@ -191,6 +191,36 @@ class MainPlayer(Player):
self.left_mouse_down = False self.left_mouse_down = False
self.double_clicking = False self.double_clicking = False
def make_a_bid(self, game_events=None):
"""
The procedure to make a bid
:return: A valid bid number
"""
if game_events:
for event in game_events:
if event.type == CALL_EVENT:
bid = event.call
print(bid)
if not bid:
return 0
bid = cards.convert_bid_string(bid)
if bid < 0:
print("Error in processing bid")
return -1
if self._table_status["bid"] >= bid:
if bid > 75:
print("You cannot bid beyond 7 No Trump")
else:
print("You might need to bid higher")
return -1
return bid
return -1
return -1
def make_a_play(self, substate, game_events=None): def make_a_play(self, substate, game_events=None):
card = None card = None
if game_events: if game_events:

View File

@ -8,7 +8,7 @@ import copy
import time import time
from signalslot import Signal from signalslot import Signal
from ai_comp import ai from ai_comp import ai
from game_consts import GameState, PlayerRole, STARTING_HAND, NUM_OF_PLAYERS from game_consts import GameState, PlayerRole, STARTING_HAND, NUM_OF_PLAYERS, CALL_EVENT
VIEW_TRANSPARENT = False # Make the text box not transparent VIEW_TRANSPARENT = False # Make the text box not transparent
@ -49,10 +49,10 @@ class Table:
All played cards go into a hidden discard pile. All played cards go into a hidden discard pile.
""" """
update_table = Signal()
def __init__(self, x, y, width, height, clear_colour, autoplay=False, view_all_cards=False): def __init__(self, x, y, width, height, clear_colour, autoplay=False, view_all_cards=False):
# TODO: Reduce the amount of update_table call # TODO: Reduce the amount of update_table call
self.update_table = Signal()
self.x = x self.x = x
self.y = y self.y = y
self.width = width self.width = width
@ -195,8 +195,15 @@ class Table:
self.calling_panel = UI.CallPanel(playdeckx[0]+w_deck+5,playdecky[0]+w_deck-140, self.calling_panel = UI.CallPanel(playdeckx[0]+w_deck+5,playdecky[0]+w_deck-140,
250, 140) 250, 140)
self.calling_panel.parent = self self.calling_panel.parent = self
self.calling_panel.visible = False
self.parent = None self.parent = None
self.calling_panel.confirm_output.connect(self.emit_call)
def emit_call(self, output, **kwargs):
print(output)
pygame.event.post(pygame.event.Event(CALL_EVENT, call=output))
def get_offset_pos(self): def get_offset_pos(self):
x, y = 0, 0 x, y = 0, 0
if self.parent: if self.parent:
@ -306,7 +313,6 @@ class Table:
if draw_update: if draw_update:
self.update_table.emit() self.update_table.emit()
def continue_game(self, game_events): def continue_game(self, game_events):
""" """
This is where the FSM is. State transition should occur here. This is where the FSM is. State transition should occur here.
@ -329,7 +335,7 @@ class Table:
self.write_message("Start to Bid") self.write_message("Start to Bid")
self.prepare_bidding() self.prepare_bidding()
elif self.game_state == GameState.BIDDING: elif self.game_state == GameState.BIDDING:
bid_complete = self.start_bidding() bid_complete = self.start_bidding(game_events)
if bid_complete: if bid_complete:
self.game_state = GameState.PLAYING self.game_state = GameState.PLAYING
self.update_all_players(role=True, wins=True) self.update_all_players(role=True, wins=True)
@ -385,30 +391,52 @@ class Table:
1 * (not self.first_player)) % NUM_OF_PLAYERS) 1 * (not self.first_player)) % NUM_OF_PLAYERS)
self.write_message(msg, line=2, delay_time=1) self.write_message(msg, line=2, delay_time=1)
def start_bidding(self): self.calling_panel.list1.replace_list([str(i+1) for i in range(7)])
self.calling_panel.list2.replace_list(['Clubs', 'Diamonds', 'Hearts', 'Spades', 'No Trump'])
self.calling_panel.cancel_button.visible = True
self.calling_panel.redraw()
self.update_table.emit()
def start_bidding(self, game_events):
""" """
The bidding procedure. The bidding procedure.
:return: Whether bidding is completed :return: Whether bidding is completed
""" """
# Highest bid: 7 NoTrump. No further check required # Highest bid: 7 NoTrump. No further check required
if self.passes < NUM_OF_PLAYERS - 1 and self.table_status["bid"] < 75: if self.passes < NUM_OF_PLAYERS - 1 and self.table_status["bid"] < 75:
player_bid = self.players[self.current_player].make_decision(self.game_state, 0) if not self.require_player_input:
if not self.players[self.current_player].AI:
self.require_player_input = True
self.calling_panel.visible = True
self.update_table.emit()
return
else:
player_bid = self.players[self.current_player].make_decision(self.game_state, 0)
else:
player_bid = self.players[self.current_player].make_decision(self.game_state, 0, game_events)
if player_bid < 0:
return
self.require_player_input = False
self.calling_panel.visible = False
self.update_table.emit()
if not player_bid: if not player_bid:
if not self.first_player: # Starting bidder pass do not count at the start if not self.first_player: # Starting bidder pass do not count at the start
self.passes += 1 self.passes += 1
else: else:
self.table_status["bid"] = player_bid self.table_status["bid"] = player_bid
self.passes = 0 self.passes = 0
msg = "Current Bid: {0:d} {1:s}".format(self.table_status["bid"] // 10,
cards.get_suit_string(self.table_status["bid"] % 10))
self.write_message(msg, line=1, update_now=False)
msg = 'Bid Leader: Player {0:d}'.format(self.current_player)
self.write_message(msg, line=2, update_now=True)
if self.table_status["bid"] < 75: if self.table_status["bid"] < 75:
self.current_player += 1 self.current_player += 1
self.current_player %= NUM_OF_PLAYERS self.current_player %= NUM_OF_PLAYERS
msg = "Current Bid: {0:d} {1:s}".format(self.table_status["bid"] // 10,
cards.get_suit_string(self.table_status["bid"] % 10))
self.write_message(msg, line=1, update_now=False)
msg = 'Bid Leader: Player {0:d}'.format((self.current_player - self.passes
- 1 * (not self.first_player)) % NUM_OF_PLAYERS)
self.write_message(msg, line=2, update_now=False)
self.display_current_player(self.current_player) self.display_current_player(self.current_player)
if self.first_player: if self.first_player:
self.first_player = False self.first_player = False