From 49df4a6bb101e3a27cada60bb4d3d9f57184dbff Mon Sep 17 00:00:00 2001 From: dgw Date: Thu, 18 Feb 2016 00:26:31 -0600 Subject: [PATCH 1/2] Move WIP 'uno' calling code to new branch Includes a few improvements over what was just removed from master, like a message explaining that a D2 has occurred and better guarding against a player spamming 'uno' to get more cards. --- unobot.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/unobot.py b/unobot.py index 7ac4895..0b67a66 100644 --- a/unobot.py +++ b/unobot.py @@ -63,6 +63,7 @@ 'DONT_HAVE': "You don't have that card!", 'DOESNT_PLAY': "That card can't be played now.", 'UNO': "UNO! %s has ONE card left!", + 'UNO_LIED': "%s draws two cards for lying about having UNO!", 'WIN': "We have a winner: %s!!! This game took %s", 'DRAWN_ALREADY': "You've already drawn, either play or pass.", 'DRAWN_CARD': "You drew: %s", @@ -128,6 +129,7 @@ def __init__(self, trigger): self.way = 1 self.drawn = NO self.smallestHand = DECK_SIZE + self.unoCalled = NO self.deck = [] self.startTime = None @@ -255,6 +257,21 @@ def play(self, bot, trigger): return WIN self.show_on_turn(bot) + def call_uno(self, bot, trigger): + caller = trigger.nick + if self.unoCalled: + return # UNO was already called this turn + if caller != self.playerOrder[self.currentPlayer]: + return # it isn't this player's turn + self.unoCalled = YES + caller = trigger.nick + with lock: + if len(self.players[caller]) != 1: + bot.say(STRINGS['UNO_LIED'] % caller) + z = [self.get_card(), self.get_card()] + self.players[caller].extend(z) + bot.notice(STRINGS['DRAWN_CARD'] % self.render_cards(bot, z, caller), caller) + def draw(self, bot, trigger): if not self.deck: return @@ -479,6 +496,7 @@ def inc_player(self): self.currentPlayer = 0 if self.currentPlayer < 0: self.currentPlayer = len(self.players) - 1 + self.unoCalled = NO # Reset flag on every turn def remove_player(self, bot, player): if len(self.players) == 1: @@ -606,6 +624,11 @@ def play(self, bot, trigger): bot.say(STRINGS['WIN'] % (winner, game_duration)) self.game_ended(bot, trigger, winner) + def call_uno(self, bot, trigger): + if trigger.sender not in self.games: + return + self.games[trigger.sender].call_uno(bot, trigger) + def draw(self, bot, trigger): if trigger.sender not in self.games: return @@ -881,6 +904,13 @@ def unoplay(bot, trigger): unobot.play(bot, trigger) +@module.rule('^uno!?$') +@module.priority('high') +@module.require_chanmsg +def unocalled(bot, trigger): + unobot.call_uno(bot, trigger) + + @module.commands('draw') @module.priority('medium') @module.require_chanmsg From c1d9dbbfe80ca54adf1db62a7f7c5d2d76f17646 Mon Sep 17 00:00:00 2001 From: dgw Date: Wed, 8 Apr 2020 19:09:21 -0500 Subject: [PATCH 2/2] Resume work on UNO calling There's no penalty for lying about having UNO. Reworked how the logic works, but it's not completely tested. However, we now have calling, challenging, penalty cards for a valid call-out if someone is caught forgetting to call UNO... Reasonably done. --- unobot.py | 65 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/unobot.py b/unobot.py index 0b67a66..994aa63 100644 --- a/unobot.py +++ b/unobot.py @@ -63,7 +63,9 @@ 'DONT_HAVE': "You don't have that card!", 'DOESNT_PLAY': "That card can't be played now.", 'UNO': "UNO! %s has ONE card left!", - 'UNO_LIED': "%s draws two cards for lying about having UNO!", + 'CHALLENGE_FALSE': "Challenging failure to call UNO does not make sense at this time.", + 'CHALLENGE_TRUE': "%s caught %s forgetting to call UNO! Two penalty cards dealt.", + 'CHALLENGE_NONE': "%s holds more than one card. Challenge is void.", 'WIN': "We have a winner: %s!!! This game took %s", 'DRAWN_ALREADY': "You've already drawn, either play or pass.", 'DRAWN_CARD': "You drew: %s", @@ -251,26 +253,41 @@ def play(self, bot, trigger): self.inc_player() self.card_played(bot, playcard) - if len(self.players[self.playerOrder[pl]]) == 1: - bot.say(STRINGS['UNO'] % self.playerOrder[pl]) - elif len(self.players[self.playerOrder[pl]]) == 0: + if len(self.players[self.playerOrder[pl]]) == 0: return WIN self.show_on_turn(bot) def call_uno(self, bot, trigger): + if not self.dealt: + return + caller = trigger.nick - if self.unoCalled: - return # UNO was already called this turn - if caller != self.playerOrder[self.currentPlayer]: - return # it isn't this player's turn - self.unoCalled = YES - caller = trigger.nick - with lock: - if len(self.players[caller]) != 1: - bot.say(STRINGS['UNO_LIED'] % caller) + if caller not in (self.playerOrder[self.currentPlayer], self.playerOrder[self.previousPlayer]): + # only the current or previous player can call UNO + bot.say(STRINGS['ON_TURN'] % self.playerOrder[self.currentPlayer]) + return + if self.unoCalled == caller: + # UNO was already called this turn + return + self.unoCalled = caller + bot.say(STRINGS['UNO'] % caller) + + def challenge_uno(self, bot, trigger): + if not self.dealt: + return + + prev = self.playerOrder[self.previousPlayer] + if len(self.players[prev]) == 1: + if self.unoCalled == prev: + bot.say(STRINGS['CHALLENGE_FALSE']) + return + else: + bot.say(STRINGS['CHALLENGE_TRUE'] % (trigger.nick, prev)) z = [self.get_card(), self.get_card()] - self.players[caller].extend(z) - bot.notice(STRINGS['DRAWN_CARD'] % self.render_cards(bot, z, caller), caller) + self.players[prev].extend(z) + bot.notice(STRINGS['DRAWN_CARD'] % self.render_cards(bot, z, prev), prev) + else: + bot.say(STRINGS['CHALLENGE_NONE'] % prev) def draw(self, bot, trigger): if not self.deck: @@ -496,7 +513,9 @@ def inc_player(self): self.currentPlayer = 0 if self.currentPlayer < 0: self.currentPlayer = len(self.players) - 1 - self.unoCalled = NO # Reset flag on every turn + if self.unoCalled != self.previousPlayer: + # Reset once it's too late to challenge a missed UNO call + self.unoCalled = NO def remove_player(self, bot, player): if len(self.players) == 1: @@ -629,6 +648,11 @@ def call_uno(self, bot, trigger): return self.games[trigger.sender].call_uno(bot, trigger) + def challenge_uno(self, bot, trigger): + if trigger.sender not in self.games: + return + self.games[trigger.sender].challenge_uno(bot, trigger) + def draw(self, bot, trigger): if trigger.sender not in self.games: return @@ -907,10 +931,17 @@ def unoplay(bot, trigger): @module.rule('^uno!?$') @module.priority('high') @module.require_chanmsg -def unocalled(bot, trigger): +def unocall(bot, trigger): unobot.call_uno(bot, trigger) +@module.commands('unofail') +@module.priority('medium') +@module.require_chanmsg +def unofail(bot, trigger): + unobot.challenge_uno(bot, trigger) + + @module.commands('draw') @module.priority('medium') @module.require_chanmsg