Skip to content

Instantly share code, notes, and snippets.

@christianp
Created February 22, 2012 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save christianp/1883965 to your computer and use it in GitHub Desktop.
Save christianp/1883965 to your computer and use it in GitHub Desktop.
A python3 version of the game Mad Abel
from itertools import product,combinations,count
from random import shuffle,randrange
from time import sleep
def nicelist(l):
if len(l)<=1:
return ''.join(l)
else:
return ', '.join(l[:-1])+' and '+l[-1]
class BaseCard:
suits = ['hearts','spades','diamonds','clubs']
sorts = ['Ace','2','3','4','5','6','7','8','9','10','Jack','Queen','King']
def __init__(self,a=0,b=0):
self.a = a
self.b = b
def __eq__(c1,c2):
return c1.a==c2.a and c1.b==c2.b
def __hash__(self):
return self.a*4+self.b
def __repr__(self):
return '%s of %s' % (self.sorts[self.a],self.suits[self.b])
def makeZCard(n):
class Card(BaseCard):
sorts = [BaseCard.sorts[n-1]]+BaseCard.sorts[:n-1]
def __add__(c1,c2):
return Card( (c1.a+c2.a) % n, (c1.b+c2.b) % 4)
def makeDeck():
return [Card(a,b) for a,b in product(range(n),range(4))]
return Card
class D6Card(BaseCard):
mult = [[0,1,2,3,4,5],[1,0,5,4,3,2],[2,4,3,0,5,1],[3,5,0,2,1,4],[4,2,1,5,0,3],[5,3,4,1,2,0]]
sorts = [BaseCard.sorts[5]]+BaseCard.sorts[:5]
def __add__(c1,c2):
a = D6Card.mult[c2.a][c1.a]
b = (c1.b+c2.b) % 4
return D6Card(a,b)
def makeDeck():
return [D6Card(a,b) for a,b in product(range(6),range(4))]
class Player:
def __init__(self,name):
self.hand = []
self.name = name
def go(self,target,idCard):
return []
def __repr__(self):
return self.name
class HumanPlayer(Player):
def go(self,target,idCard):
print('Your hand:')
for i,c in enumerate(self.hand):
print('%i. %s' % (i+1,c))
inp = input('\nWhich cards do you play? ')
if inp=='take':
return []
return [self.hand[int(i)-1] for i in inp.split(' ') if len(i)]
class AutoPlayer(Player):
def go(self,target,idCard):
for i in range(4,-1,-1):
for cards in combinations(self.hand,i):
if sum(cards,idCard)==target:
return cards
return []
class Game:
def __init__(self,Card,reporting=True):
self.reporting = reporting
self.Card = Card
self.idCard = Card()
self.deck = Card.makeDeck()
shuffle(self.deck)
self.pile = []
self.play(self.deal(2)) #deal two cards onto the pile
self.players = []
def addPlayers(self,*players):
for player in players:
self.players.append(player)
player.hand = self.deal(7)
def deal(self,n):
if len(self.deck)<n:
top = self.pile[-2:]
bottom = self.pile[:-2]
bottom.reverse()
self.deck = bottom + self.deck
b=self.deck[-n:]
del self.deck[-n:]
return b
def play(self,cards):
self.pile += cards
self.target = sum(self.pile[-2:],self.idCard)
def report(self,msg,delay=0.2):
if self.reporting:
print(msg)
sleep(delay)
def describeTarget(self):
self.report('The %s and the %s are on the top of the pile.' % (self.pile[-1],self.pile[-2]))
def run(self):
start = randrange(len(self.players))
for i in count():
player = self.players[(i+start) % len(self.players)]
self.report("Turn %i. %s's go." % (i+1,player))
self.describeTarget()
cards = player.go(self.target,self.idCard)
while len(cards)>0 and sum(cards,self.idCard)!=self.target:
self.report("\nThose cards don't sum to the target. Try again.")
self.describeTarget()
cards = player.go(self.target,self.idCard)
if len(cards)==0:
self.report('^^ %s draws two cards from the deck' % player)
player.hand += self.deal(2)
else:
self.report('>> %s plays %s' % (player, nicelist(['the '+str(c) for c in cards])))
self.play(cards)
player.hand = [c for c in player.hand if not c in cards]
if len(player.hand)==0:
self.report('!! %s has no cards left!\n\n%s wins!' % (player,player))
return player
self.report('\n',1)
def demo():
#size=int(input("How many cards per suit? "))
game = Game(Card=D6Card)
game.addPlayers(
AutoPlayer('Bot'),
HumanPlayer(input('What is your name? '))
)
game.run()
if __name__ == '__main__':
demo()
@christianp
Copy link
Author

The rules:

From a deck of cards, take those numbered ace to N of all four suits, and throw the rest away.
Deal 4 cards to each player, and two cards face-up in a pile on the table. Put the rest of the deck face-down on the table.

This is a game based on adding cards together.

The sum of a set of cards is:

  • the sum of the face values (modulo N)
  • the sum of the suits (modulo 4)

The suits have the following values:

  • hearts - 0
  • spades - 1
  • diamonds - 2
  • clubs - 3

So in the game where face values go up to 5, the sum of the 3 of diamonds and the 4 of clubs is the 2 of spades.

The target is the sum of the top two cards on the pile. Players take turns to make up the sum using any combination of the cards in their hands. If a player can't make the target, they draw two cards from the deck and the next player takes their turn.

The winner is the first person to get rid of all their cards.

@christianp
Copy link
Author

Now plays on the dihedral group of order 6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment