Sunday, July 29, 2012

I continued my attempt at improving at Python by checking with others who are willing to look over code and suggest improvements. They provided most of the code below.

One change  in their updated solution is to use lazy evaluation with yield and itemgetter. A nice change to the list comprehension allowed the removal of the len and range and just iterated over each player in the player list to make tuples. The names were clarified to playerRolls and playerGroups instead of referencing a data structure.  The flag to repeat rolls for ties with a while loop has been cleaned out in favor of recursion down each branch.

I modified the previous code by putting it in a function and adding a roll parameter to let me test their code. The pattern of ordering of player's rolling has been changed. It is like a depth first tree traversal now rather than breadth first.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from itertools import groupby
from operator import itemgetter
from random import randint
from collections import deque
 
def rank_players(playerList, roll):
    playerRolls = [(player, roll()) for player in playerList]
    playerGroups = groupby(
        sorted(playerRolls, key=itemgetter(1), reverse=True),
        itemgetter(1))
    for key, group in playerGroups:
        grouped_players = list(group)
        if len(grouped_players) > 1:
            print('tied, need to reroll',grouped_players)
            for player in rank_players(zip(*grouped_players)[0], roll):
                yield player
        else:
            print('rolled ',grouped_players[0])
            yield grouped_players[0]
 
rollData = deque([ 6, 4, 4, 4, 3, 3, 3, 2, 2, 2, 3, 3, 3, 4, 5, 6 ])
order = rank_players(['one','two','three','four'], lambda: rollData.popleft())
print(list(order))
 

Saturday, July 14, 2012

Python review

I'm starting to forget some python. I've also wanted to work on an old problem encountered at school. So, tonight I'm going to work on it with python.

This particular roadblock to completing the old assignment wasn't that difficult, but for some reason we weren't able to write a solution I felt comfortable with. In the end, the simplest thing to do would've been to randomly pick a permutation of a list. Python provides a shuffle function to do this.

from random import shuffle
x = ['player t', 'player u', 'player v', 'player w', 'player x', 'player y', 'player z']
shuffle(x)
print(x)

Some how we ended up wanting to do a more complicated system to order a list of players. It was about 5 years ago, but I believe the reason was to more faithfully simulate our interpretation of how the game assigned for homework was to be played.The decision was made to go through this sequence:
  1. Each player would roll a die. 
  2. Ties result in another set of rolls to break the tie. But any higher values still count towards ranking ahead of lower values.
  3. For players who did not tie, their relative position would be determined by how high their roll was.
For example, we could have three players, X, Y, Z. If X and Y both rolled a 6 and Z rolled a 1, Z would be assigned the last spot and X and Y would roll again. If X got 5 and Y got 4 for their second rolls, the final order would be X, Y, Z. The follow diagram illustrates that example:

Looking back at it now, it seems to be like a tree expansion. Tree nodes would represent groups of players. For example, the root would be all unsorted players. Visiting the node would generate children by having each player roll their die. A child node of the root could be the players who tied the first round of rolls. Leaves would be players who did not tie. After all the nodes are expanded into leaves, an inorder traversal of the tree would result in the ranking.


from random import randint
from itertools import groupby
 
tree = [['player t', 'player u', 'player v', 'player w', 'player x', 'player y', 'player z']] 
nextGeneration = []
keepPlaying = True
while keepPlaying:
    keepPlaying = False
    for node in tree:
        if len(node) == 1:
            nextGeneration.append(node)
        else:
            keepPlaying  = True
            rolls = [randint(1,6) for i in range(len(node))]
            turn = sorted(zip(rolls,node), reverse=True)
            print 'players roll:', turn
            for key, group in groupby(turn, lambda x: x[0]):
                nextGeneration.append(list(i[1] for i in group))
    tree = nextGeneration
    nextGeneration = []
print([item for sublist in tree for item in sublist])


If I recall correctly,this is what we wanted to do about 5 years ago in school. I don't see much use for it now though other than as an exercise in python. I need to think about how to test it more and make it more testable. A gui might help debug it and make what is happening clearer. At least I learned a little bit about groupby, sorted, zip, and list comprehensions.