I wrote a small script that finds the solution to the cracker barrel peg game / triangle game.GistA small script that finds the solution tothe cracker barrel peg game / triangle game.Instructions along with one of the game's solution can be found here:http://www.joenord.com/puzzles/peggame/It finds the solution by repeatedly playing games and making randomdecisions until a game leaves one peg. The slot's are numbered0 - 14 in sequential order (Top to Bottom, Left to Right)    /0\   /1 2\  /3 4 5\  etc etcAnother objective of this game is to leave the board with8 pegs and no possible jumps. To find that solution change thefinal if statement as follows:if triangle.total_peg() == 8:Language python 2.7import randomclass Slot:        Represents a single slot opening of the triangle game.    This class holds the slot number, it's possible jump    dictionary and helper functions around maintaining slots.        def __init__(self, num, jump_dict):        self.num = num        self.jump_dict = jump_dict        self.peg = True    def has_peg(self):        return self.peg    def add_peg(self):        self.peg = True    def remove_peg(self):        self.peg = False    def possible_jump(self, board):         Determine possible jumps for a given peg        :param board: The board to check possible jumps against        :return: Dictionary of possible jumps                assert self.has_peg()        possible_jump_dict = {}        for jump_over in self.jump_dict:            jump_to = self.jump_dict[jump_over]            if board[jump_over].has_peg() and not board[jump_to].has_peg():                possible_jump_dict[jump_over] = jump_to        return possible_jump_dictclass Triangle:        Represents a single board of the triangle game        def __init__(self):                Initializes the board for a new game.        The board consists of slot 15 objects                self.board = [Slot(0, {1: 3, 2: 5}),                      Slot(1, {3: 6, 4: 8}),                      Slot(2, {4: 7, 5: 9}),                      Slot(3, {4: 5, 1: 0, 6: 10, 7: 12}),                      Slot(4, {7: 11, 8: 13}),                      Slot(5, {2: 0, 4: 3, 8: 12, 9: 14}),                      Slot(6, {3: 1, 7: 8}),                      Slot(7, {4: 2, 8: 9}),                      Slot(8, {4: 1, 7: 6, }),                      Slot(9, {5: 2, 8: 7}),                      Slot(10, {6: 3, 11: 12}),                      Slot(11, {7: 4, 12: 13}),                      Slot(12, {11: 10, 7: 3, 8: 5, 13: 14}),                      Slot(13, {12: 11, 8: 4}),                      Slot(14, {13: 12, 9: 5})]        self.jump_history = []    def jump(self, jump_from, jump_over, jump_to):        Executes a jump action        :param jump_from: Peg number to jump from        :param jump_over: Peg number to be jumped over and removed        :param jump_to: Empty slot number for the peg to jump into                self.board[jump_from].remove_peg()        self.board[jump_over].remove_peg()        self.board[jump_to].add_peg()        self.jump_history.append([jump_from, jump_over, jump_to])    def total_peg(self):        return sum(slot.has_peg() for slot in self.board)    def random_jump(self):         Selects a random slot that contains a peg and then randomly        selects one of it's possible jumps.        :return: Tuple containing a single slot and it's jump coordinates                slot_choice = [i for i in range(15)]        random.shuffle(slot_choice)        for slot in slot_choice:            if self.board[slot].has_peg():                possible_jump = self.board[slot].possible_jump(self.board)                if possible_jump:                    jump_over = random.choice(possible_jump.keys())                    jump_to = possible_jump[jump_over]                    return slot, jump_over, jump_to        return None    def remove_first_peg(self):                The first action of every game is to remove a peg from a full board        This function randomly removes one peg from a full board                first_peg = random.choice(self.board)        first_peg.remove_peg()        self.jump_history.append([first_peg.num])    def play_one_game(self):        self.remove_first_peg()        while True:            next_jump = self.random_jump()            if next_jump:                self.jump(*next_jump)            else:                breakdef main():    total_games = 0    # Keep playing games until a single peg is left on the board    while True:        total_games += 1        triangle = Triangle()        triangle.play_one_game()        if triangle.total_peg() == 1:            break    print '***Game #' + str(total_games) + ' Report***'    for slot in triangle.board:        print str(slot.num) + ' ' + str(slot.has_peg())    print 'Jump History:'    print triangle.jump_history    print 'Total Pegs Remaining: ' + str(triangle.total_peg())if __name__ == __main__:    main()I'm looking for any critiques, from style to class structure to variable names.
Solution to the cracker barrel peg game / triangle game
python;game
Your documentation (good work on including it, by the way) mentions that this is Python 2.7. In that case, your classes should be new-style and inherit from object (see e.g. What is the difference between old style and new style classes in Python?)While I mention the documentation, it would be nice to cover the format of jump_dict, e.g.:...:param jump_dict: The possible jumps from the slot, in    the form {jump_over: jump_to}.... Having the board laid out within Board.__init__ seems a little inflexible; have a go at making the number of rows an instantiation argument, defaulting to the current 5, and see if you can write some code to calculate what slots must be provided (and linked to which others) for a given size.I think the structure might end up being a bit neater if you switch the dictionaries, too - if each Slot stored the slots it can be jumped to from the logic gets simpler. Really, it's the empty slots that are key here, not the full ones!There is duplication of information here:def jump(self, jump_from, jump_over, jump_to):you define three parameters, when any two would be sufficient to determine the third (e.g. if you know where you're jumping _from and _to, you can work out where you're jumping _over).Finally, the random method of solving the puzzle isn't ideal. At the very least I would try to decouple the random solver from the other methods, making it easier to slot in something a bit smarter when you can. For example, imagine:def play_one_game(self, method='random'):What would need to change to make this run while providing for alternative values of method later?