def __init__(self, schid, cid, password, rootdir): """ Instantiates a new object. @param schid: the id of the serverconnection handler @type schid: int @param cid: the id of the channel @type cid: int @param password: the password of the channel @type password: str @param rootdir: the root download directory @type rootdir: str """ super().__init__() self.schid = schid self.cid = cid self.password = password self.rootdir = rootdir self.collectionFinished = Signal() self.collectionError = Signal() self.queue = {} self.files = {} PluginHost.registerCallbackProxy(self)
def __init__(self, schid, cid, password, parent=None, *, readonly=False): super(QAbstractItemModel, self).__init__(parent) self.schid = schid self.cid = cid self.password = password self.readonly = readonly self.pathChanged = Signal() self.error = Signal() self._path = None self.newpath = None self.files = [] self.newfiles = [] self.retcode = None self.renretcode = None self.renfile = () self.titles = [ self._tr("Name"), self._tr("Size"), self._tr("Type"), self._tr("Last Changed") ] PluginHost.registerCallbackProxy(self)
def setup_method(self, method): self.signal_a = Signal(threadsafe=True) self.signal_b = Signal(args=['foo']) self.slot_a = mock.Mock(spec=lambda **kwargs: None) self.slot_a.return_value = None self.slot_b = mock.Mock(spec=lambda **kwargs: None) self.slot_b.return_value = None
def __init__(self, num, height): """ height = ft """ self.__num = num self.__height = height self.__people = [] # people currently on the floor (not necessarily waiting for elevators) self.__queue = [] # people requested the elevator and currently waiting for one self.__signal_elevator_requested = Signal(args=['from_floor', 'to_floor']) self.__signal_people_boarded = Signal(args=['elevator_id', 'floor_num', 'people'])
def __init__(self, floors=[], elevators=[]): self.__floors = floors # absolute coords self.__floor_coords = [0] * len(self.__floors) for i in range(1, len(self.__floor_coords)): self.__floor_coords[i] += self.__floor_coords[i-1] + self.__floors[i-1].height self.__elevators = {e.id : e for e in elevators} # indicates a command to an elevator to change velocity self.__signal_change_velocity = Signal(args=['elevator_id', 'velocity']) self.__signal_stop = Signal(args=['elevator_id'])
class zmqReceiverLoggerThread(threading.Thread): data_received = Signal(args=[], threadsafe=True) def __init__(self, port=5556): super(zmqReceiverLoggerThread, self).__init__() self.context = zmq.Context() self.socket = self.context.socket(zmq.PULL) self.port = port self.interrupt = False def run(self): self.socket.bind("tcp://*:%s" % (self.port)) while True: try: data = self.socket.recv_pyobj() if len(data) > 0: print data self.data_received.emit(args=data) except (KeyboardInterrupt, SystemExit): self.socket.close() self.context.term() else: pass
def setup_method(self, method): self.signal = Signal(threadsafe=False) self.seen_exception = False def failing_slot(**args): raise MyTestError('die!') self.signal.connect(failing_slot)
def __init__(self, x, y, width, height, text='Button', text_size=25): self.button_down = False self.clicked = Signal() super().__init__(x, y, width, height, text=text, text_size=text_size) self.hold_function = self.hold self.release_function = self.release self.redraw()
def setup_method(self, method): class MyObject(object): def __init__(self): self.called = False def slot(self, **kwargs): self.called = True self.obj_ref = MyObject() self.slot = Slot(self.obj_ref.slot, weak=True) self.signal = Signal() self.signal.connect(self.slot)
def __init__(self, id, size=10, height=10): """ people - list of people currently in the elevator size - elevator capacity in terms of people count velocity - velocity along y axis position - current y coordinate door_opening_time - time taken to open doors in seconds door_closing_time - time taken to close doors in seconds """ self.__id = id self.__people = [] self.__signal_person_inside = Signal(args=['person']) self.__signal_position_change = Signal(args=['elevator_id', 'x', 'y']) # direction: True = up, Down = False self.__signal_door_opened = Signal(args=['elevator_id', 'direction', 'people_inside', 'available_capacity', 'floor_num']) self.__signal_door_closed = Signal(args=['elevator_id', 'people_inside']) self.__size = size self.__velocity = 0 self.__position = (0, 0) self.__height = height self.__door_opening_time = 1.5 self.__door_closing_time = 2.5
def __init__(self, x, y, width, height, texts, text_size=25): super().__init__(x, y, width, height) self.list_selected = Signal(args=['text']) self.font = pygame.font.SysFont("None", text_size) self.texts = texts self.text_rects = [] self.y_offset = 0 self.selected = -1 self.outline_thickness = 3 self.selected_colour = (255, 0, 0) self.max_offset = 0 self.replace_list(texts) self.release_function = self.check_click_pos
def test_semaphore(self, inspect): slot = mock.Mock() slot.side_effect = lambda **k: time.sleep(.3) signal = Signal('tost') signal.connect(slot) x = Task.get_or_create(signal, dict(some_kwarg='foo')) y = Task.get_or_create(signal, dict(some_kwarg='foo')) eventlet.spawn(x) time.sleep(.1) eventlet.spawn(y) time.sleep(.1) assert slot.call_count == 1 time.sleep(.4) assert slot.call_count == 2
def __init__(self, result_copy=True, result_deepcopy=True): """ Initialisation. This should be overridden by subclasses to accept and validate the inputs presented for the operation, raising an appropriate Exception subclass if the inputs are found to be invalid. These should be stored here by the initialisation function as private variables in suitably sanitised form. The core state machine object shall then be created and stored before the object is returned to the caller. """ # Event object to represent when this operation is "done" self._done_evt = Event() # Signal emitted when the operation is "done" self.done_sig = Signal(name="done", threadsafe=True) # Result returned by operation self._result = None self._result_copy = result_copy self._result_deepcopy = result_deepcopy
def __init__(self, x, y, width, height): self.draw_update = Signal() self.x = x self.y = y self.width = width self.height = height self.rect = pygame.rect.Rect(x, y, width, height) self.visible = True self.clear_colour = (0, 0, 0) self.outline_colour = (255, 0, 0) self.outline_thickness = 3 self.text_colour = (255, 255, 255) self.background = pygame.Surface((self.width, self.height)) self.background.fill(self.clear_colour) self.background.set_colorkey(self.clear_colour) self.background = self.background.convert() self.hold_function = None self.release_function = None self.parent = None self.children = None
def __init__(self): self._loop = DummyLoop() self.bind_calls = [] self.transmitted = [] self.received_msg = Signal()
def __init__(self, schid, cid, password='', path='/', parent=None, *, staticpath=False, readonly=False, downloaddir=None, iconpack=None): """ Instantiates a new object. @param schid: the id of the serverconnection handler @type schid: int @param cid: the id of the channel @type cid: int @param password: password to the channel, defaults to an empty string @type password: str @param path: path to display, defaults to the root path @type path: str @param parent: parent of the dialog; optional keyword arg; defaults to None @type parent: QWidget @param staticpath: if set to True, the initial path can't be changed by the user; optional keyword arg; defaults to False @type staticpath: bool @param readonly: if set to True, the user can't download, upload or delete files, or create new directories; optional keyword arg; defaults to False @type readonly: bool @param downloaddir: directory to download files to; optional keyword arg; defaults to None; if set to None, the TS3 client's download directory is used @type downloaddir: str @param iconpack: iconpack to load icons from; optional keyword arg; defaults to None; if set to None, the current iconpack is used @type iconpack: ts3client.IconPack """ super(QDialog, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) iconpackopened = False if not iconpack: try: iconpack = ts3client.IconPack.current() iconpack.open() iconpackopened = True except Exception as e: self.delete() raise e try: setupUi(self, pytson.getPluginPath("ressources", "filebrowser.ui"), iconpack=iconpack) self.statusbar = SmartStatusBar(self) self.layout().addWidget(self.statusbar) self.statusbar.hide() except Exception as e: self.delete() raise e err, cname = ts3lib.getChannelVariableAsString( schid, cid, ChannelProperties.CHANNEL_NAME) if err == ERROR_ok: self.setWindowTitle( self._tr("File Browser - {cname}").format(cname=cname)) else: self.setWindowTitle(self._tr("File Browser")) self.schid = schid self.cid = cid self.password = password self.path = None self.staticpath = staticpath self.readonly = readonly self.createretcode = None self.delretcode = None if not self.readonly and not downloaddir: cfg = ts3client.Config() q = cfg.query("SELECT value FROM filetransfer " "WHERE key='DownloadDir'") del cfg if q.next(): self.downloaddir = q.value("value") else: self.delete() raise Exception("Error getting DownloadDir from config") else: self.downloaddir = downloaddir if not self.readonly: menu = self.menu = QMenu(self) self.openAction = menu.addAction(QIcon(iconpack.icon("FILE_UP")), self._tr("Open")) self.openAction.connect("triggered()", self.on_openAction_triggered) self.downAction = menu.addAction(QIcon(iconpack.icon("DOWN")), self._tr("Download")) self.downAction.connect("triggered()", self.downloadFiles) self.renameAction = menu.addAction(QIcon(iconpack.icon("EDIT")), self._tr("Rename")) self.renameAction.connect("triggered()", self.on_renameAction_triggered) self.copyAction = menu.addAction(QIcon(iconpack.icon("COPY")), self._tr("Copy URL")) self.copyAction.connect("triggered()", self.on_copyAction_triggered) self.delAction = menu.addAction(QIcon(iconpack.icon("DELETE")), self._tr("Delete")) self.delAction.connect("triggered()", self.deleteFiles) self.upAction = menu.addAction(QIcon(iconpack.icon("UP")), self._tr("Upload files")) self.upAction.connect("triggered()", self.uploadFiles) self.createAction = menu.addAction(QIcon.fromTheme("folder"), self._tr("Create Folder")) self.createAction.connect("triggered()", self.createFolder) self.refreshAction = menu.addAction( QIcon(iconpack.icon("FILE_REFRESH")), self._tr("Refresh")) self.refreshAction.connect("triggered()", self.refresh) self.allactions = [ self.openAction, self.downAction, self.renameAction, self.copyAction, self.delAction, self.upAction, self.createAction, self.refreshAction ] self.collector = FileCollector(schid, cid, password, self.downloaddir) self.collector.collectionFinished.connect(self._startDownload) self.collector.collectionError.connect(self.showError) self.fileDoubleClicked = Signal() self.contextMenuRequested = Signal() self.transdlg = None self.listmodel = FileListModel(schid, cid, password, self, readonly=readonly) self.listmodel.pathChanged.connect(self.onPathChanged) self.listmodel.error.connect(self.showError) self.proxy = QSortFilterProxyModel(self) self.proxy.setSortRole(Qt.UserRole) self.proxy.setSortCaseSensitivity(Qt.CaseInsensitive) self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxy.setSourceModel(self.listmodel) self.listmodel.path = path self._adjustUi() if iconpackopened: iconpack.close() PluginHost.registerCallbackProxy(self)
def setup_method(self, method): self.signal = Signal()
def __init__(self, x, y, width, height): super().__init__(x, y, width, height) self.background.set_colorkey(None) self.confirm_output = Signal(args=['output']) self.text_size = 20 margins = 5 ui_width = 80 ui_height = 25 width_spacings = (width - 2.5 * ui_width - 2 * margins) / 4 height_spacings = (height - 2 * margins - 3 * ui_height) / 4 self.output_text = ['', ''] self.list1 = ScrollList(margins + width_spacings, margins, ui_width / 2, height - 2 * margins, texts=[str(i) for i in range(20)], text_size=self.text_size) self.list1.list_selected.connect( lambda text, **z: self.print_list_selection(text, 0)) self.list2 = ScrollList(margins + width_spacings * 2 + ui_width / 2, margins, ui_width, height - 2 * margins, texts=['a', 'b', 'c', 'd'], text_size=self.text_size) self.list2.list_selected.connect( lambda text, **z: self.print_list_selection(text, 1)) self.output_box = TextBox(margins + width_spacings * 3 + ui_width * 1.5, margins + height_spacings, ui_width, ui_height, text='-', text_size=self.text_size) self.confirm_button = Button(margins + width_spacings * 3 + ui_width * 1.5, margins + height_spacings * 2 + ui_height, ui_width, ui_height, text='Call', text_size=self.text_size) self.confirm_button.clicked.connect(self.emit_output) self.cancel_button = Button( margins + width_spacings * 3 + ui_width * 1.5, margins + height_spacings * 3 + ui_height * 2, ui_width, ui_height, text='Pass', 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.list1, self.list2, self.confirm_button, self.output_box, self.cancel_button ] for element in self.children: element.parent = self self.redraw()
def test_named_signal_has_a_nice_repr(): signal = Signal(name='update_stuff') assert repr(signal) == '<signalslot.Signal: update_stuff>'
def test_anonymous_signal_has_nice_repr(): signal = Signal() assert repr(signal) == '<signalslot.Signal: NO_NAME>'
def __init__(self, conn): self.connecting = Signal() self.connected = Signal() self.sleeping = Signal() self.disconnected = Signal() self.reconnecting = Signal() '''(remote)''' self.typing = Signal() '''(remote)''' self.typingPaused = Signal() '''(remote)''' self.available = Signal() '''(remote)''' self.unavailable = Signal() self.messageSent = Signal() self.messageDelivered = Signal() '''(fmsg)''' self.messageReceived = Signal() '''messageReceived with fmsg.author''' self.groupMessageReceived = Signal() ''' (fmsg) -> media_type: image, audio, video, location, vcard -> data image: -> url -> preview audio, video: -> url location: -> latitude -> longitude -> preview vcard: -> contact (vcard format) ''' self.mediaReceived = Signal() '''mediaReceived with fmsg.author''' self.groupMediaReceived = Signal() '''(group, author, subject)''' self.newGroupSubject = Signal() '''(group, who)''' self.groupAdd = Signal() '''(group, who)''' self.groupRemove = Signal() ''' (groups: [{subject, id, owner}]) ''' self.groupsReceived = Signal() self.groupListReceived = Signal() self.lastSeenUpdated = Signal() self.sendTyping = Signal() self.sendPaused = Signal() self.getLastOnline = Signal() self.disconnectRequested = Signal() self.disconnectRequested.connect(self.onDisconnectRequested) self.loginFailed = Signal() self.loginSuccess = Signal() self.connectionError = Signal() self.conn = conn self.sendTyping.connect(self.conn.sendTyping) self.sendPaused.connect(self.conn.sendPaused) self.getLastOnline.connect(self.conn.getLastOnline) self.startPingTimer()
class UDP_Server(object): def __init__(self, ip, port, ttl, type_, id_): handler = UDP_Communications.UDP_Server.SenderHandler( self.__packet_received) self._server = UDP_Communications.UDP_Server(handler) # debug=True for more outputs in the Python command line. self._server.debug = False # Turn off local adapter filter; Let it switched off self._server.adapter_filter(False) self._server.init_udp(ip, port, ttl, System.Byte(type_), System.Byte(id_), True) if not self._server.udp_active(): raise RuntimeError("Server is not running!") pass def send_command(self, command, **kwargs): data = ['command', str(command)] for k, v in kwargs.items(): data.append(str(k)) data.append(str(v)) result = self._server.send_command(data) return result def send_data(self, **kwargs): data = [] for k, v in kwargs.items(): data.append(str(k)) data.append(str(v)) self._server.send_data(data) def send_command_wait_for_reply(self, command, data=None, **kwargs): dataCmd = ['command', str(command)] if data is not None: for k, v in data.items(): dataCmd.extend([k, v]) for k, v in kwargs.items(): dataCmd.append(str(k)) dataCmd.append(str(v)) method = self._server.send_command.Overloads[ System.Array[System.String], System.String("").GetType().MakeByRefType()] res = method(dataCmd, "") return res[1] def start_stream(self, rxType, rxId): result = self._server.startStream(System.Byte(rxType), System.Byte(rxId)) return result def stop_stream(self, rxType, rxId): self._server.stopStream(System.Byte(rxType), System.Byte(rxId)) def stop(self): self._server.stop_udp() def send_stream(self, rxType, rxId, data): result = self._server.write(data.tobytes(), System.Byte(rxType), System.Byte(rxId)) return result def stream_data_available(self, rxType, rxId): result = self._server.StreamDataAvailable(System.Byte(rxType), System.Byte(rxId)) # Is any data available if result[0]: # Is it data from the desired stream? if result[1] != rxType or result[2] != rxId: return False # Return result return result[0] def get_stream_data(self, rxType, rxId): streamData = self._server.getStreamData(System.Byte(rxType), System.Byte(rxId)) if streamData is None: return dataArray = [] # NOTE: This is very inefficient; Has to be improved # The problem is conversion from System.Byte to e.g. numpy data type #for x in streamData: # dataArray.append(x) # NOTE: For now we just convert the first 10 elements. However, everything is received. for x in range(9): dataArray.append(streamData[x]) return dataArray def __packet_received(self, server, event): paket = event.Paket if paket is None: return res_packet = Packet(paket) self.packet_received.emit(packet=res_packet) packet_received = Signal(args=['packet'])
def __init__(self): # Init logging facility # From : http://sametmax.com/ecrire-des-logs-en-python/ logger = logging.getLogger() logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s') file_handler = RotatingFileHandler('api_log.log', 'a', 1000000, 1) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(formatter) logger.addHandler(file_handler) stream_handler = logging.StreamHandler() stream_handler.setLevel(logging.DEBUG) logger.addHandler(stream_handler) # Signals self.signal_MCU_state_changed = Signal(args=['alive']) self.signal_received_descriptor = Signal(args=['var_id','var_type','var_name','var_writeable','group_id']) self.signal_received_group_descriptor = Signal(args=['group_id','group_name']) self.signal_received_value = Signal(args=['var_id']) self.distantio = distantio_protocol() self.protocol = Protocol(self.unused) # Queue holding received characters to be processed by worker process self.input_queue = mp.Queue() # Queue holding decoded frames self.output_queue = mp.Queue() # Conditions for controlling run process self.condition_new_rx_data = mp.Event() self.condition_new_rx_data.clear() self.condition_run_process = mp.Event() self.condition_run_process.clear() # Worker process for decoding characters self.producer_conn, self.consumer_conn = mp.Pipe() self.worker = Worker(self.input_queue,self.producer_conn,self.condition_new_rx_data,self.condition_run_process) self.worker.start() # Array containing buffers with MCU variables values self.variables_values = dict() # max size of the buffers self.buffer_length = 128 # Array containing last time each individual variable was updated self.last_variables_update = dict() # Min delay in seconds between two emit value received signal self.emit_signal_delay = 0.1 self.time_start = time.time() # Timer for monitoring MCU alive self.mcu_died_delay = 2.0 self.mcu_alive_timer = threading.Timer(self.mcu_died_delay,self.on_mcu_lost_connection) self.variable_list = dict() self.connected = False self.datalogger = Datalogger() # Start MCU timer self.mcu_alive_timer = threading.Timer(self.mcu_died_delay,self.on_mcu_lost_connection) self.mcu_alive_timer.start() logging.info('DistantIO API initialized successfully.')
class Table: """ A Table is the place where all actions takes place. It is essentially a FSM, doing different routines at each state. It needs to keep track of the score, roles, the rules, etc. It needs to ask each player for decisions and respond to them accordingly. The table will also need to inform any decision to the Main Screen so that it can update the screen to reflect that change through the use of callbacks (Signal and Slot). This call should be minimised by making all the changes before calling to update the screen in one go. FSM cycles --- Preloop - Prepare the cards once - Initiate Players and connect them to the Table 1. Shuffle and Deal out cards to Players. 2a. Detect weak hands and ask for reshuffle. 2b. Return to (1) if any reshuffle occurs, otherwise proceed. 3. Bidding round. Randomly pick a starting player, in clockwise manner ask for a bid until it is valid. 3b. Proceed only if 3 consecutive skips are detected. 3c. Ask the winner of the bid a card not in their hand. 3d. Set up the player roles, trump suit, rounds to win for both side 3e. Play the game. Start with bid winner if NO TRUMP, otherwise Starting next to the bid winner. 4a. With the first player, ask for any card, excluding trump suits if trump is not broken 4b. With subsequent players, ask for cards that follow the suit of the first player , include trump suit if trump is broken. Ask for any card if the player cannot follow suit. 4c. Once all 4 players has made valid plays, announce results, update scoring. Announce player roles if the partner card is played. Break trump if trump is played. 4d. Repeat 4 until 13 rounds are made. Maybe add early win if confirmed one side wins 5. Ask for a new game. Go back to 1 if true. 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): # TODO: Reduce the amount of update_table call self.x = x self.y = y self.width = width self.height = height self.table_font = pygame.font.SysFont("None", 25) self.player_font = pygame.font.SysFont("None", 25) # For gameplay self.game_state = GameState.DEALING self.current_round = 0 self.passes = 0 self.current_player = 0 self.first_player = False # This is for bidding purposes self.players = [] self.players_playzone = [] # Table status will be made known to the player by reference self.table_status = { 'played cards': [0, 0, 0, 0], 'leading player': 0, 'trump suit': 1, 'trump broken': False, 'round history': [], 'bid': 0, 'partner': 0, 'partner reveal': False, 'defender': { 'target': 0, 'wins': 0 }, 'attacker': { 'target': 0, 'wins': 0 } } # Prepare the surfaces for displaying self.background = pygame.Surface((self.width, self.height)) self.background.fill(clear_colour) self.background = self.background.convert() # TODO: Update the drawing of the table? # Prepare the card with dimensions w_deck = min(self.height, self.width) * 0.18 l_deck = min(self.width, self.height) * 0.7 # This is not a deck as it will never be drawn self.discard_deck = cards.prepare_playing_cards( int(w_deck * 0.7), int(w_deck * 0.9)) game_margins = 5 # Players' deck positioning playerx = ((self.width - l_deck) // 2, game_margins, (self.width - l_deck) // 2, self.width - w_deck - game_margins) playery = (self.height - w_deck - game_margins, (self.height - l_deck) // 2, game_margins, (self.height - l_deck) // 2) h_spacing = 20 v_spacing = 25 # Middle playfield for announcer and player playing deck positioning playfield_margins = 5 margins_with_w_deck = w_deck + playfield_margins + game_margins playfield_x = margins_with_w_deck playfield_y = margins_with_w_deck playfield_width = self.width - margins_with_w_deck * 2 playfield_height = self.height - margins_with_w_deck * 2 playdeckx = (playfield_x + (playfield_width - w_deck) / 2, playfield_x, playfield_x + (playfield_width - w_deck) / 2, playfield_x + playfield_width - w_deck) playdecky = (playfield_y + playfield_height - w_deck, playfield_y + (playfield_height - w_deck) / 2, playfield_y, playfield_y + (playfield_height - w_deck) / 2) # Player stats positioning stats_width = 100 self.stats_height = 100 stats_spacing = 10 self.player_stats_x = (playdeckx[0] - stats_width - stats_spacing, playdeckx[1], playdeckx[2] + w_deck + stats_spacing, playdeckx[3]) self.player_stats_y = (playdecky[0] + w_deck - self.stats_height, playdecky[1] - self.stats_height - stats_spacing, playdecky[2], playdecky[3] + w_deck + stats_spacing) self.player_stats = [[], [], [], []] # TODO: change surface to use colorkey, maybe, if the performance is tanked # Prepare all the player surfaces for i in range(4): vert = i % 2 == 1 spacing = h_spacing if vert: spacing = v_spacing reveal_mode = cards.DeckReveal.HIDE_ALL if i == 0 or view_all_cards: reveal_mode = cards.DeckReveal.SHOW_ALL self.players.append( Player(playerx[i], playery[i], l_deck, w_deck, spacing, vert_orientation=vert, deck_reveal=reveal_mode)) self.players[i].connect_to_table(self.table_status) if i > 0: self.players[i].add_ai(ai.RandomAI(self.table_status)) self.players_playzone.append( cards.Deck(playdeckx[i], playdecky[i], w_deck, w_deck, 0)) for j in range(3): surf = pygame.Surface((stats_width, self.stats_height / 3), pygame.SRCALPHA) rendered_text = self.player_font.render( "Player {0:d}".format(i), True, (255, 0, 255)).convert_alpha() self.center_text_on_surface( surf, rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) self.player_stats[i].append(surf) if autoplay: self.players[0].add_ai(ai.RandomAI(self.table_status)) # Announcer positioning and surface creation announcer_margins = 5 announcer_spacing = announcer_margins + w_deck self.announcer_x = playfield_x + announcer_spacing self.announcer_y = playfield_y + announcer_spacing self.announcer_width = playfield_width - 2 * announcer_spacing self.announcer_height = playfield_height - 2 * announcer_spacing self.announcer_line = [] for i in range(3): surf = pygame.Surface( (self.announcer_width, self.announcer_height / 3), pygame.SRCALPHA) self.announcer_line.append(surf) self.update_all_players(role=True, wins=True) self.write_message("Press P to play!") self.ongoing = False def center_text_on_surface(self, surf, rendered_text, clear_colour): line_center = surf.get_rect().center text_rect = rendered_text.get_rect(center=line_center) surf.fill(clear_colour) surf.blit(rendered_text, text_rect) def write_message(self, text, delay_time=0.5, line=0, update_now=True): """ Write a message into the center board surface (announcer) :param text: String to be displayed on the center board :param delay_time: How much delay to put once the string is display :param line: Which line of the announcer to write to :return: None """ if 0 <= line < len(self.announcer_line): print(text) text = text.strip('\n') rendered_text = self.table_font.render( text, True, (255, 255, 255)).convert_alpha() self.center_text_on_surface( self.announcer_line[line], rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) if update_now: self.update_table.emit() time.sleep(delay_time) def update_players_role(self, player_num, update_now=True): self.player_stats[player_num][1].fill( (255, 255, 255, 255 * VIEW_TRANSPARENT)) if self.players[player_num].role == PlayerRole.DEFENDER: rendered_text = self.player_font.render( "Defender", True, (0, 64, 192)).convert_alpha() self.center_text_on_surface( self.player_stats[player_num][1], rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) elif self.players[player_num].role == PlayerRole.ATTACKER: rendered_text = self.player_font.render( "Attacker", True, (192, 0, 0)).convert_alpha() self.center_text_on_surface( self.player_stats[player_num][1], rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) if update_now: self.update_table.emit() def update_player_wins(self, player_num, update_now=True): self.player_stats[player_num][2].fill( (255, 255, 255, 255 * VIEW_TRANSPARENT)) if self.players[player_num].score > 1: rendered_text = self.player_font.render( "Wins: {0:d}".format(self.players[player_num].score), True, (255, 255, 255)).convert_alpha() else: rendered_text = self.player_font.render( "Win: {0:d}".format(self.players[player_num].score), True, (255, 255, 255)).convert_alpha() self.center_text_on_surface(self.player_stats[player_num][2], rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) if update_now: self.update_table.emit() def update_all_players(self, role=False, wins=True): for i in range(4): if wins: self.update_player_wins(i, update_now=False) if role: self.update_players_role(i, update_now=False) self.update_table.emit() def display_current_player(self, current=-1): if current >= 0: print("Player {0:d}\n".format(current)) for i in range(4): rendered_text = self.player_font.render( "Player {0:d}".format(i), True, (255, 0, 255)).convert_alpha() if i == current: self.center_text_on_surface(self.player_stats[i][0], rendered_text, (0, 64, 0, 255)) else: self.center_text_on_surface( self.player_stats[i][0], rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) self.update_table.emit() def update_team_scores(self): if self.table_status['partner reveal']: msg = "Defender: {0:d}/{2:d}, Attacker: {1:d}/{3:d}\n".format( self.table_status['defender']['wins'], self.table_status['attacker']['wins'], self.table_status['defender']['target'], self.table_status['attacker']['target']) self.write_message(msg, line=2) else: msg = "Defender: {0:d}?/{1:d}, Attacker: ?/{2:d}\n".format( self.table_status['defender']['wins'], self.table_status['defender']['target'], self.table_status['attacker']['target']) self.write_message(msg, line=2) def get_pos(self): return self.x, self.y def continue_game(self): """ This is where the FSM is. State transition should occur here. What takes place in the state should be in a function. :return: None """ # TODO: Adjust the timing of sleep if self.game_state == GameState.DEALING: self.shuffle_and_deal() self.write_message("Shuffle Complete!") self.game_state = GameState.POINT_CHECK elif self.game_state == GameState.POINT_CHECK: if self.check_reshuffle(): self.write_message('Reshuffle Initiated!', line=1) self.game_state = GameState.ENDING else: self.write_message('No Reshuffle needed!') self.game_state = GameState.BIDDING self.write_message("Start to Bid") self.prepare_bidding() elif self.game_state == GameState.BIDDING: bid_complete = self.start_bidding() if bid_complete: self.game_state = GameState.PLAYING self.update_all_players(role=True, wins=True) self.update_team_scores() elif self.game_state == GameState.PLAYING: self.play_a_round() if self.current_round == 13: self.write_message("Game Set! Press P to play again!") self.ongoing = False self.game_state = GameState.ENDING else: self.reset_game() self.game_state = GameState.DEALING def shuffle_and_deal(self): """ Shuffle and deal the discard deck to the players, which should have 52 cards. :return: None """ if self.discard_deck: for i in range(10): random.shuffle(self.discard_deck) for player in self.players: for i in range(STARTING_HAND): player.add_card(self.discard_deck.pop()) self.update_table.emit() def check_reshuffle(self): """ Detect any possible reshuffle request within the players :return: True if reshuffle requested, else False """ print("Player Point Count") for i, player in enumerate(self.players): print("Player {0:d}: {1:d}".format(i, player.get_card_points())) if player.get_card_points() < 4: self.write_message( "Low points detected in Player {0:d}! ".format(i)) return player.make_decision(self.game_state, 0) def prepare_bidding(self): # Randomly pick a starting player, whom also is the current bid winner self.current_player = random.randint(1, NUM_OF_PLAYERS) - 1 print("Starting Player: {0:d}".format(self.current_player)) self.passes = 0 self.table_status["bid"] = 11 # Lowest Bid: 1 Club by default self.first_player = True # Starting bidder "privilege" to raise the starting bid 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, delay_time=0) self.display_current_player(self.current_player) msg = 'Bid Leader: Player {0:d}'.format( (self.current_player - self.passes - 1 * (not self.first_player)) % 4) self.write_message(msg, line=2, delay_time=1) def start_bidding(self): """ The bidding procedure. :return: Whether bidding is completed """ # Highest bid: 7 NoTrump. No further check required 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 player_bid: if not self.first_player: # Starting bidder pass do not count at the start self.passes += 1 else: self.table_status["bid"] = player_bid self.passes = 0 if self.table_status["bid"] < 75: self.current_player += 1 self.current_player %= 4 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)) % 4) self.write_message(msg, line=2, update_now=False) self.display_current_player(self.current_player) if self.first_player: self.first_player = False time.sleep(0.5) return False else: self.write_message("Player {0:d} is the bid winner!".format( self.current_player), delay_time=1) msg = "Player {0:d} is calling a partner...".format( self.current_player) self.write_message(msg, delay_time=1) self.display_current_player(self.current_player) # Ask for the partner card self.table_status["partner"] = self.players[ self.current_player].make_decision(self.game_state, 1) # Setup the table status before the play starts self.table_status['partner reveal'] = False self.table_status["trump suit"] = self.table_status["bid"] % 10 self.table_status["trump broken"] = False self.table_status['played cards'] = [0, 0, 0, 0] if self.table_status['trump suit'] == 5: self.table_status["leading player"] = self.current_player else: self.table_status["leading player"] = (self.current_player + 1) % 4 self.table_status['defender'][ 'target'] = self.table_status["bid"] // 10 + 6 self.table_status['attacker'][ 'target'] = 14 - self.table_status['defender']['target'] # Set the roles of the players self.players[self.current_player].role = PlayerRole.DEFENDER self.write_message('Bidding Complete', delay_time=0) msg = 'Trump: {1:s}, Partner: {0:s}'.format( cards.get_card_string(self.table_status["partner"]), cards.get_suit_string(self.table_status['trump suit'])) self.write_message(msg, line=1, delay_time=1) return True def play_a_round(self): """ Ask each player to play a valid card and determine the winner of the round :return: None """ if not any(self.table_status["played cards"]): # Leading player starts with the leading card, which determines the leading suit self.current_player = self.table_status['leading player'] self.display_current_player(self.current_player) card = self.players[self.current_player].make_decision( self.game_state, 0) self.table_status["played cards"][self.current_player] = card self.players_playzone[self.current_player].add_card(card) elif not all(self.table_status["played cards"]): # Subsequent player make their plays, following suit if possible self.display_current_player(self.current_player) print("Player {0:d}\n".format(self.current_player)) card = self.players[self.current_player].make_decision( self.game_state, 1) self.players_playzone[self.current_player].add_card(card) self.table_status["played cards"][self.current_player] = card else: # Once all player played, find out who wins leading_card = self.table_status["played cards"][ self.table_status['leading player']] card_suits = [ card.suit() for card in self.table_status["played cards"] ] card_nums = [ card.number() for card in self.table_status["played cards"] ] follow_suits = [suit == leading_card.suit() for suit in card_suits] trumps = [ suit == self.table_status['trump suit'] for suit in card_suits ] trump_played = any(trumps) # Break trump if the trump suit is played if not self.table_status['trump broken']: if trump_played: self.table_status['trump broken'] = True self.write_message("Trump Broken!", delay_time=1) # Determine which players to check for winner, and determine winner valid_nums = [ card_nums[i] * ((follow_suits[i] and not trump_played) or trumps[i]) for i in range(4) ] winning_player = valid_nums.index(max(valid_nums)) self.write_message("Player {0:d} wins!\n".format(winning_player), delay_time=1) self.players[winning_player].score += 1 self.update_player_wins(winning_player) # Clean up the cards, update score, set the next leading player, update round history for deck in self.players_playzone: self.discard_deck.append(deck.remove_card()) if self.players[winning_player].role == PlayerRole.DEFENDER: self.table_status['defender']['wins'] += 1 elif self.players[winning_player].role == PlayerRole.ATTACKER: self.table_status['attacker']['wins'] += 1 self.table_status['leading player'] = winning_player self.table_status['round history'].append( copy.copy(self.table_status["played cards"])) self.update_team_scores() self.table_status["played cards"] = [0] * 4 self.current_round += 1 self.update_table.emit() return if not self.table_status['partner reveal']: if card.value == self.table_status['partner']: self.table_status['partner reveal'] = True self.write_message("Partner Revealed!", delay_time=1) self.reveal_all_roles(self.current_player) self.update_all_players(role=True, wins=False) self.current_player += 1 self.current_player %= 4 self.update_table.emit() time.sleep(0.5) def reveal_all_roles(self, partner): self.players[partner].role = PlayerRole.DEFENDER self.table_status['defender']['wins'] += self.players[partner].score for i in range(4): if self.players[i].role == PlayerRole.UNKNOWN: self.players[i].role = PlayerRole.ATTACKER self.table_status['attacker']['wins'] += self.players[i].score def reset_game(self): for player in self.players: while not player.is_empty(): self.discard_deck.append(player.remove_card()) player.score = 0 player.role = PlayerRole.UNKNOWN for i in range(4): self.update_players_role(i) self.update_player_wins(i) self.table_status['defender']['wins'] = 0 self.table_status['attacker']['wins'] = 0 self.table_status["played cards"] = [0] * 4 self.table_status['round history'] = [] self.current_round = 0 self.write_message("", line=1, update_now=False) self.write_message("", line=2) self.display_current_player() print(len(self.discard_deck)) self.update_table.emit()
def __init__(self, x, y, width, height, clear_colour, autoplay=False, view_all_cards=False, terminal=False): # TODO: Reduce the amount of update_table call self.update_table = Signal() self.x = x self.y = y self.width = width self.height = height self.table_font = pygame.font.SysFont("None", 25) self.player_font = pygame.font.SysFont("None", 25) # For gameplay self.game_state = GameState.DEALING self.reshuffling_players = [] self.current_round = 0 self.passes = 0 self.current_player = 0 self.first_player = False # This is for bidding purposes self.players = [] self.players_playzone = [] # Table status will be made known to the player by reference self.table_status = { 'played cards': [0, 0, 0, 0], 'leading player': 0, 'trump suit': 1, 'trump broken': False, 'round history': [], 'bid': 0, 'partner': 0, 'partner reveal': False, 'defender': { 'target': 0, 'wins': 0 }, 'attacker': { 'target': 0, 'wins': 0 } } # Prepare the surfaces for displaying self.background = pygame.Surface((self.width, self.height)) self.background.fill(clear_colour) self.background = self.background.convert() # TODO: Update the drawing of the table? # Prepare the card with dimensions w_deck = min(self.height, self.width) * 0.18 l_deck = min(self.width, self.height) * 0.7 # This is not a deck as it will never be drawn self.discard_deck = cards.prepare_playing_cards( int(w_deck * 0.6), int(w_deck * 0.6 * 97 / 71)) game_margins = 5 # Players' deck positioning playerx = ((self.width - l_deck) // 2, game_margins, (self.width - l_deck) // 2, self.width - w_deck - game_margins) playery = (self.height - w_deck - game_margins, (self.height - l_deck) // 2, game_margins, (self.height - l_deck) // 2) h_spacing = 20 v_spacing = 25 # Middle playfield for announcer and player playing deck positioning playfield_margins = 5 margins_with_w_deck = w_deck + playfield_margins + game_margins playfield_x = margins_with_w_deck playfield_y = margins_with_w_deck playfield_width = self.width - margins_with_w_deck * 2 playfield_height = self.height - margins_with_w_deck * 2 playdeckx = (playfield_x + (playfield_width - w_deck) / 2, playfield_x, playfield_x + (playfield_width - w_deck) / 2, playfield_x + playfield_width - w_deck) playdecky = (playfield_y + playfield_height - w_deck, playfield_y + (playfield_height - w_deck) / 2, playfield_y, playfield_y + (playfield_height - w_deck) / 2) # Player stats positioning stats_width = 100 self.stats_height = 100 stats_spacing = 10 self.player_stats_x = (playdeckx[0] - stats_width - stats_spacing, playdeckx[1], playdeckx[2] + w_deck + stats_spacing, playdeckx[3]) self.player_stats_y = (playdecky[0] + w_deck - self.stats_height, playdecky[1] - self.stats_height - stats_spacing, playdecky[2], playdecky[3] - w_deck - stats_spacing) self.player_stats = [[], [], [], []] # TODO: change surface to use colorkey, maybe, if the performance is tanked # Prepare all the player surfaces for i in range(NUM_OF_PLAYERS): vert = i % 2 == 1 spacing = h_spacing if vert: spacing = v_spacing reveal_mode = cards.DeckReveal.HIDE_ALL if i == 0 or view_all_cards: reveal_mode = cards.DeckReveal.SHOW_ALL if i == 0: player_class = players.MainPlayer if terminal: player_class = players.Player self.players.append( player_class(playerx[i], playery[i], l_deck, w_deck, spacing, vert_orientation=vert, deck_reveal=reveal_mode)) else: self.players.append( players.Player(playerx[i], playery[i], l_deck, w_deck, spacing, vert_orientation=vert, deck_reveal=reveal_mode, flip=(i == 1 or i == 2), draw_from_last=(i == 2 or i == 3))) self.players[i].connect_to_table(self.table_status) if i > 0: self.players[i].add_ai(ai.VivianAI(self.table_status)) self.players_playzone.append( cards.Deck(playdeckx[i], playdecky[i], w_deck, w_deck, 0)) for j in range(3): surf = pygame.Surface((stats_width, self.stats_height / 3), pygame.SRCALPHA) rendered_text = self.player_font.render( "Player {0:d}".format(i), True, (255, 0, 255)).convert_alpha() self.center_text_on_surface( surf, rendered_text, (255, 255, 255, 255 * VIEW_TRANSPARENT)) self.player_stats[i].append(surf) if autoplay: self.players[0].add_ai(ai.VivianAI(self.table_status)) # Announcer positioning and surface creation announcer_margins = 5 announcer_spacing = announcer_margins + w_deck self.announcer_x = playfield_x + announcer_spacing self.announcer_y = playfield_y + announcer_spacing self.announcer_width = playfield_width - 2 * announcer_spacing self.announcer_height = playfield_height - 2 * announcer_spacing self.announcer_line = [] for i in range(3): surf = pygame.Surface( (self.announcer_width, self.announcer_height / 3), pygame.SRCALPHA) self.announcer_line.append(surf) self.update_all_players(role=True, wins=True, clear_wins=True) self.write_message("Press P to play!") self.ongoing = False self.require_player_input = False self.terminal_play = terminal self.calling_panel = UI.CallPanel(playdeckx[0] + w_deck + 5, playdecky[0] + w_deck - 100, 220, 100) self.calling_panel.parent = self self.calling_panel.visible = False self.parent = None self.calling_panel.confirm_output.connect(self.emit_call) self.yes_button = UI.Button(playdeckx[0] + w_deck + 5, playdecky[0], 50, 25, text='yes') self.yes_button.visible = False self.yes_button.clicked.connect(lambda **z: pygame.event.post( pygame.event.Event(CALL_EVENT, call=True))) self.no_button = UI.Button(playdeckx[0] + w_deck + 5, playdecky[0] + 25 + 25, 50, 25, text='no') self.no_button.clicked.connect(lambda **z: pygame.event.post( pygame.event.Event(CALL_EVENT, call=False))) self.no_button.visible = False self.UI_elements = [ self.calling_panel, self.yes_button, self.no_button ]