Set Solver
The script solves the card game Set. You can find a complete package with documentation of this here.
#!/usr/bin/python import sys, os from optparse import OptionParser # Loads a list of cards from a file # File should be tab delineated and have one property in each field def loadFile(filename): Cards = list() f = file(filename, 'r') for line in f: line = line.strip(); # skip over comment lines if line[0] == "#": continue fields = line.split(); # Don't load a corrupt line that doesn't have four fields if len(fields) != 4: print "This line is corrupt: %s" % line continue # Create the card and add it to the list c = Card(fields[0], fields[1], fields[2], fields[3]) Cards.append(c) f.close() return Cards # Tests whether three cards are a set or not def isSet(CardA, CardB, CardC): # each property must be all the same or all different colorsASet = isPropertyASet( CardA.color, CardB.color, CardC.color ) numbersASet = isPropertyASet( CardA.number, CardB.number, CardC.number ) shapeASet = isPropertyASet( CardA.shape, CardB.shape, CardC.shape ) fillASet = isPropertyASet( CardA.fill, CardB.fill, CardC.fill ) # all properties must be a valid set return colorsASet & numbersASet & shapeASet & fillASet # Tests a set of properties to test and see if that property's # conditions are met # Returns true if they are all the same or all different, false otherwise def isPropertyASet(propA, propB, propC): # all properties are equal if (propA == propB) & (propB == propC): return True # or all properties are different if (propA != propB) & (propB != propC) & (propA != propC): return True return False # Card class, contains the properties of each card class Card: # Initializes all card properties def __init__(self, color, number, shape, fill): self.color = color self.number = number self.shape = shape self.fill = fill # Returns this card in string form def __str__(self): return "%s, %s, %s, %s" % (self.color, self.number, self.shape, self.fill) # Determines if a card is equal to another card def __eq__(A, B): return A.color == B.color & A.number == B.number & A.shape == B.shape & A.fill == B.fill if __name__ == '__main__': parser = OptionParser() parser.add_option("-i", "--infile", dest="infile", help="The input file", metavar="INFILE") (options, args) = parser.parse_args() if options.infile: InFile = options.infile else: print >> sys.stderr, "Error: no input file to load!" parser.print_help() sys.exit(0) # Load and list all cards Cards = loadFile( InFile ) print "Cards:" for i in range(0, len(Cards)): print "\tCard %s: %s" % ( i, Cards[i] ) Matches = list() # upper triangular for loop pairing up cards for CardA in range(0, len(Cards)-2): for CardB in range(CardA+1, len(Cards)-1): for CardC in range(CardB+1, len(Cards)): if isSet(Cards[CardA], Cards[CardB], Cards[CardC]): Matches.append("%s-%s-%s" % (CardA, CardB, CardC)) # print all sets print "Sets:" for match in Matches: print "\t%s" % match
Example card file:
# ANSWERS: 0-3-10, 1-6-9, 2-3-8, 2-10-11, 4-5-8, 6-7-10 Red 2 Diamond Full Green 1 Diamond Empty Green 3 Squiggle Full Green 3 Squiggle Lines Purple 1 Oval Empty Red 2 Diamond Empty Green 3 Diamond Full Red 3 Squiggle Lines Green 3 Squiggle Empty Green 2 Diamond Lines Purple 3 Oval Empty Red 3 Diamond Lines