patternpythonModerate
Class for sorting pool balls
Viewed 0 times
sortingballsforpoolclass
Problem
I have written this code for fun. I'd like to hear your suggestions about how to make it more compact and pythonic.
```
from random import shuffle
class Pool(object):
"""
Simple object that allows to sort
"""
def __init__(self):
"""
During initalization the final grid containing
ordered balls is created
1 is placeholder for Solid balls
0 is placeholder for Striped balls
"""
self.grid = [[1],[0,0],[1,0,1],[0,1,0,0],[1,0,1,0,1]]
def create_ball_set(self):
"""
This function returns a list containing
a shuffled pool balls set
"""
balls = []
[balls.append([number]) for number in range(1, 16)]
for ball in balls:
if ball[0] < 9:
ball.append("Solid")
else:
ball.append("Striped")
shuffle(balls)
return balls
def sort_ball_set(self, unsorted_balls):
"""
This function returns a
list of sorted balls from a list of
shuffled balls
"""
# Ball 1 always goes in 1st place
self.grid[0][0] = unsorted_balls.pop(unsorted_balls.index([1, 'Solid']))
# Ball 8 always goes in the 2nd row, in the middle
self.grid[2][1] = unsorted_balls.pop(unsorted_balls.index([8, 'Solid']))
# Creating an empty list for solid balls
unsorted_solid_balls = []
# Same thing but for striped balls
unsorted_striped_balls = []
# Now it is time to divide solid balls from striped ones
for ball in unsorted_balls:
if ball[1] == 'Solid':
unsorted_solid_balls.append(ball)
elif ball[1] == 'Striped':
unsorted_striped_balls.append(ball)
# Once the balls are divided it is time to put them in the grid
for grid_row_index, grid_row in enumerate(self.grid):
for grid_col_index, grid_col_value in enumerate(grid_row):
```
from random import shuffle
class Pool(object):
"""
Simple object that allows to sort
"""
def __init__(self):
"""
During initalization the final grid containing
ordered balls is created
1 is placeholder for Solid balls
0 is placeholder for Striped balls
"""
self.grid = [[1],[0,0],[1,0,1],[0,1,0,0],[1,0,1,0,1]]
def create_ball_set(self):
"""
This function returns a list containing
a shuffled pool balls set
"""
balls = []
[balls.append([number]) for number in range(1, 16)]
for ball in balls:
if ball[0] < 9:
ball.append("Solid")
else:
ball.append("Striped")
shuffle(balls)
return balls
def sort_ball_set(self, unsorted_balls):
"""
This function returns a
list of sorted balls from a list of
shuffled balls
"""
# Ball 1 always goes in 1st place
self.grid[0][0] = unsorted_balls.pop(unsorted_balls.index([1, 'Solid']))
# Ball 8 always goes in the 2nd row, in the middle
self.grid[2][1] = unsorted_balls.pop(unsorted_balls.index([8, 'Solid']))
# Creating an empty list for solid balls
unsorted_solid_balls = []
# Same thing but for striped balls
unsorted_striped_balls = []
# Now it is time to divide solid balls from striped ones
for ball in unsorted_balls:
if ball[1] == 'Solid':
unsorted_solid_balls.append(ball)
elif ball[1] == 'Striped':
unsorted_striped_balls.append(ball)
# Once the balls are divided it is time to put them in the grid
for grid_row_index, grid_row in enumerate(self.grid):
for grid_col_index, grid_col_value in enumerate(grid_row):
Solution
I think it is usually better to take advantage of the built-in functions. Python lists already have a
One way to achieve that is with a custom
This is very succinct, but you could also promote the lambda key function to a proper function:
Another alternative is to make a
Here, the
Whichever way you go, once you have a correctly sorted list of balls, you can use a function that successively takes one more ball, something like:
Which you can use like this:
sort function, so you would expect a list of pool balls to be sortable by the start arrangement (a list of tuples/lists is already sortable, Python compares them element wise).One way to achieve that is with a custom
key function:order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
# Simplified balls list, as the fill style is not really needed for this
balls = [[n] for n in range(1, 16)]
balls.sort(key=lambda ball: order.index(ball[0]))This is very succinct, but you could also promote the lambda key function to a proper function:
def pool_start_order(ball):
order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
return order.index(ball[0])
balls = [[n] for n in range(1, 16)]
balls.sort(key=pool_start_order)Another alternative is to make a
PoolBall class, that is sortable, something like this:class PoolBall(object):
order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
def __init__(self, number):
assert 1 <= number <= 15
self.number = number
self.fill = 'Solid' if number <= 8 else 'Striped'
self.order = PoolBall.order.index(number)
def __lt__(self, other):
return self.order < other.order
def __eq__(self, other):
return self.number == other.number
def __str__(self):
return "{self.number} {self.fill}".format(self=self)
def __repr__(self):
return "{self.__class__.__name__}({self.number})".format(self=self)
balls = [PoolBall(i) for i in range(1, 16)]
balls.sort()Here, the
__str__ and __repr__ are just there for pretty printing.Whichever way you go, once you have a correctly sorted list of balls, you can use a function that successively takes one more ball, something like:
def pyramid_arrangement(balls):
"""
Given a list of balls, arranges them in a pyramid shape.
Yields each row.
Leaves the balls list empty.
"""
take = 1
while balls:
yield [balls.pop() for _ in range(take)]
take += 1Which you can use like this:
if __name__ == "__main__":
balls = [PoolBall(i) for i in range(1, 16)]
balls.sort(reverse=True)
for row in pyramid_arrangement(balls):
print rowCode Snippets
order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
# Simplified balls list, as the fill style is not really needed for this
balls = [[n] for n in range(1, 16)]
balls.sort(key=lambda ball: order.index(ball[0]))def pool_start_order(ball):
order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
return order.index(ball[0])
balls = [[n] for n in range(1, 16)]
balls.sort(key=pool_start_order)class PoolBall(object):
order = [1, 13, 11, 7, 8, 6, 9, 5, 14, 15, 2, 12, 3, 10, 4]
def __init__(self, number):
assert 1 <= number <= 15
self.number = number
self.fill = 'Solid' if number <= 8 else 'Striped'
self.order = PoolBall.order.index(number)
def __lt__(self, other):
return self.order < other.order
def __eq__(self, other):
return self.number == other.number
def __str__(self):
return "{self.number} {self.fill}".format(self=self)
def __repr__(self):
return "{self.__class__.__name__}({self.number})".format(self=self)
balls = [PoolBall(i) for i in range(1, 16)]
balls.sort()def pyramid_arrangement(balls):
"""
Given a list of balls, arranges them in a pyramid shape.
Yields each row.
Leaves the balls list empty.
"""
take = 1
while balls:
yield [balls.pop() for _ in range(take)]
take += 1if __name__ == "__main__":
balls = [PoolBall(i) for i in range(1, 16)]
balls.sort(reverse=True)
for row in pyramid_arrangement(balls):
print rowContext
StackExchange Code Review Q#160535, answer score: 10
Revisions (0)
No revisions yet.