Advertisement
Guest User

Untitled

a guest
Sep 2nd, 2015
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.29 KB | None | 0 0
  1. Player X: //// Player O: /////
  2. ________________
  3. / X / / / O /|
  4. /___/___/___/___/ |
  5. / O / X / / X / |
  6. /___/___/___/___/ |
  7. / / O / X / O / |
  8. /___/___/___/___/ |
  9. / / / / O / |
  10. /___/___/___/___/ |
  11. | |________|_______|
  12. | / / /|O / /|
  13. | /___/___/_|_/___/ |
  14. | / X / X / O|/ X / |
  15. | /___/___/___|___/ |
  16. | / / O / O /| / |
  17. | /___/___/___/_|_/ |
  18. | / / / O / |/ |
  19. |/___/___/___/___| |
  20. | |________|_______|
  21. | / X / O /| / /|
  22. | /___/___/_|_/___/ |
  23. | / X / X / O|/ / |
  24. | /___/___/___|___/ |
  25. | / / O / X /| / |
  26. | /___/___/___/_|_/ |
  27. | / / / / X|/ |
  28. |/___/___/___/___| |
  29. | |________|_______|
  30. | / O / /| / /
  31. | /___/___/_|_/___/
  32. | / X / X / X|/ X /
  33. | /___/___/___|___/
  34. | / O / O / /| /
  35. | /___/___/___/_|_/
  36. | / O / / / X|/
  37. |/___/___/___/___|
  38. Player O's turn...
  39.  
  40. """
  41. Classes and Functions:
  42. Connect3D:
  43. _get_winning_player
  44. play
  45. make_move
  46. shuffle
  47. update_score
  48. show_score
  49. draw
  50. reset
  51. DirectionCalculation
  52. PointConversion:
  53. to_3d
  54. to_int
  55. SwapGridData:
  56. x
  57. y
  58. z
  59. DrawGrid
  60. calculate_grid_size
  61. split_list
  62. join_list
  63. """
  64. import itertools, operator
  65. from collections import defaultdict
  66. import random
  67.  
  68.  
  69. class Connect3D(object):
  70. """Class to store the Connect3D game data.
  71. The data is stored in a 1D list, but is converted to a 3D representation for the user.
  72.  
  73. Functions:
  74. _get_winning_player
  75. play
  76. make_move
  77. shuffle
  78. update_score
  79. show_score
  80. draw
  81. reset
  82. """
  83. def __init__(self, grid_size=4, _raw_data=None):
  84. """Set up the grid and which player goes first.
  85.  
  86. Parameters:
  87. grid_size:
  88. How long each side of the grid should be.
  89. The game works best with even numbers, 4 is recommended.
  90. Default: 4
  91. Type: int
  92.  
  93. _raw_data:
  94. Passed in from __repr__, contains the grid data and current player.
  95. Default: None
  96. Type: str
  97. Format: 'joined(grid_data).current_player'
  98. """
  99.  
  100. self.current_player = random.randint(0, 1)
  101.  
  102. #Read from _raw_data
  103. if _raw_data is not None:
  104. split_data = _raw_data.split('.')
  105. self.grid_data = list(i if i != ' ' else '' for i in split_data[0])
  106. self.grid_size = calculate_grid_size(self.grid_data)
  107. if len(self.grid_data) != pow(self.grid_size, 3):
  108. self.grid_data = self.grid_data[:pow(self.grid_size, 3)]
  109.  
  110. if len(split_data) > 1:
  111. self.current_player = int(int(split_data[1]))
  112.  
  113. #Set up class
  114. else:
  115. try:
  116. self.grid_size = int(grid_size)
  117. except TypeError:
  118. raise TypeError('grid_size must be an integer')
  119. self.grid_data = ['' for i in range(pow(grid_size, 3))]
  120.  
  121.  
  122. self.grid_size_squared = pow(self.grid_size, 2)
  123.  
  124. #Calculate the edge numbers for each direction
  125. self.direction_edges = {}
  126. self.direction_edges['U'] = range(self.grid_size_squared)
  127. self.direction_edges['D'] = range(self.grid_size_squared*(self.grid_size-1), self.grid_size_squared*self.grid_size)
  128. self.direction_edges['R'] = [i*self.grid_size+self.grid_size-1 for i in range(self.grid_size_squared)]
  129. self.direction_edges['L'] = [i*self.grid_size for i in range(self.grid_size_squared)]
  130. self.direction_edges['F'] = [i*self.grid_size_squared+j+self.grid_size_squared-self.grid_size for i in range(self.grid_size) for j in range(self.grid_size)]
  131. self.direction_edges['B'] = [i*self.grid_size_squared+j for i in range(self.grid_size) for j in range(self.grid_size)]
  132. self.direction_edges[' '] = []
  133.  
  134. #Calculate the addition needed to move in each direction
  135. self.direction_maths = {}
  136. self.direction_maths['D'] = self.grid_size_squared
  137. self.direction_maths['R'] = 1
  138. self.direction_maths['F'] = self.grid_size
  139. self.direction_maths['U'] = -self.direction_maths['D']
  140. self.direction_maths['L'] = -self.direction_maths['R']
  141. self.direction_maths['B'] = -self.direction_maths['F']
  142. self.direction_maths[' '] = 0
  143.  
  144.  
  145. def __repr__(self):
  146. """Format the data to allow it to be imported again as a new object."""
  147. grid_data_joined = ''.join(str(i).ljust(1) for i in self.grid_data)
  148. return "Connect3D(_raw_data='{}.{}')".format(grid_data_joined, self.current_player)
  149.  
  150. def _get_winning_player(self):
  151. """Return a list of the player(s) with the highest points.
  152.  
  153. >>> C3D = Connect3D()
  154. >>> C3D.update_score()
  155.  
  156. When X has a higher score.
  157. >>> C3D.current_points['X'] = 5
  158. >>> C3D.current_points['O'] = 1
  159. >>> C3D._get_winning_player()
  160. ['X']
  161.  
  162. When both scores are the same.
  163. >>> C3D.current_points['O'] = 5
  164. >>> C3D._get_winning_player()
  165. ['O', 'X']
  166.  
  167. When there are no winners.
  168. >>> C3D = Connect3D()
  169. >>> C3D.update_score()
  170. >>> C3D._get_winning_player()
  171. []
  172. """
  173. self.update_score()
  174. sorted_points = sorted(self.current_points.iteritems(), key=operator.itemgetter(1), reverse=True)
  175. highest_points = sorted([k for k, v in self.current_points.iteritems() if v == sorted_points[0][1]])
  176.  
  177. return highest_points
  178.  
  179.  
  180. def play(self, player_symbols='XO', grid_shuffle_chance=None):
  181. """Start or continue a game.
  182.  
  183. Parameters:
  184. player_symbols:
  185. The two characters to represent each player.
  186. Length: 2
  187. Default: 'XO'
  188. Type: str/list/tuple/int
  189.  
  190. grid_shuffle_chance:
  191. Percentage chance to shuffle the grid after each turn.
  192. Default: None (use default shuffle chance)
  193. Type: int/float
  194. """
  195. #Check there are two symbols
  196. if isinstance(player_symbols, (tuple, list)):
  197. player_symbols = ''.join(player_symbols)
  198. player_symbols = str(player_symbols)
  199. same_symbols = len(set(player_symbols)) == 1
  200. if len(player_symbols) != 2 or same_symbols:
  201. raise ValueError('two{} symbols are needed'.format(' different' if len(set(player_symbols)) == 1 else ''))
  202.  
  203. self.current_player = int(not self.current_player)
  204.  
  205. #Game loop
  206. while True:
  207.  
  208. #Switch current player
  209. self.current_player = int(not self.current_player)
  210.  
  211. self.update_score()
  212. self.show_score()
  213. was_flipped = self.shuffle(chance=grid_shuffle_chance)
  214. self.draw()
  215. if was_flipped:
  216. print "Grid was flipped!"
  217.  
  218. #Check if no spaces are left
  219. if '' not in self.grid_data:
  220. winning_player = self._get_winning_player()
  221. if len(winning_player) == 1:
  222. print 'Player {} won!'.format(winning_player[0])
  223. else:
  224. print 'The game was a draw!'
  225.  
  226. #Ask to play again and check if answer is a variant of 'yes' or 'ok'
  227. print 'Play again?'
  228. play_again = raw_input().lower()
  229. if any(i in play_again for i in ('y', 'k')):
  230. self.reset()
  231. else:
  232. return
  233. break
  234.  
  235.  
  236. #Player takes a move, function returns True if it updates the grid, otherwise loop again
  237. print "Player {}'s turn...".format(player_symbols[self.current_player])
  238. while not self.make_move(player_symbols[self.current_player], raw_input().replace(',', ' ').replace('.', ' ').split()):
  239. print "Grid cell is not available, try again."
  240.  
  241.  
  242. def make_move(self, id, *args):
  243. """Update the grid data with a new move.
  244.  
  245. Parameters:
  246. id:
  247. ID to write to the grid.
  248. Type: str
  249.  
  250. args:
  251. Where to place the ID.
  252. Can be input as an integer (grid cell number), 3 integers, a tuple or list (3D coordinates)
  253. Type: int/tuple/list
  254.  
  255. >>> C3D = Connect3D(2)
  256.  
  257. >>> C3D.make_move('a', 1)
  258. True
  259. >>> C3D.make_move('b', 1)
  260. False
  261. >>> C3D.make_move('c', -1)
  262. False
  263. >>> C3D.make_move('d', 2, 2, 2)
  264. True
  265. >>> C3D.make_move('e', [1, 1, 2])
  266. True
  267. >>> C3D.make_move('f', (1, 1, 3))
  268. False
  269.  
  270. >>> C3D.grid_data
  271. ['', 'a', '', '', 'e', '', '', 'd']
  272. >>> C3D.draw()
  273. ________
  274. / / a /|
  275. /___/___/ |
  276. / / / |
  277. /___/___/ |
  278. | |____|___|
  279. | / e /| /
  280. | /___/_|_/
  281. | / / d|/
  282. |/___/___|
  283. """
  284.  
  285. #Convert points to the grid cell ID
  286. if len(args) == 1:
  287. if not str(args[0]).replace('-','').isdigit():
  288. if len(args[0]) == 1:
  289. try:
  290. i = int(args[0][0])
  291. except ValueError:
  292. return False
  293. else:
  294. i = PointConversion(self.grid_size, args[0]).to_int()
  295. else:
  296. i = int(args[0])
  297. else:
  298. i = PointConversion(self.grid_size, tuple(args)).to_int()
  299.  
  300. #Add to grid if cell is empty
  301. if 0 <= i <len(self.grid_data) and not self.grid_data[i] and i is not None:
  302. self.grid_data[i] = id
  303. return True
  304. else:
  305. return False
  306.  
  307.  
  308.  
  309. def shuffle(self, chance=None, second_chance=None, repeats=None, no_shuffle=[]):
  310. """Mirror the grid in the X, Y, or Z axis.
  311.  
  312. Each time one of the directions is flipped, there is a 50% chance of it happening again.
  313. This means it has the same overall chance to flip, but it is not limited to a single axis.
  314.  
  315. Parameters:
  316. chance:
  317. Percent chance of a flip happening.
  318. Default: 10
  319. Type: int/float
  320.  
  321. second_chance:
  322. Percent chance of subsequent flips happening after the first.
  323. Default: 50
  324. Type: int/float
  325.  
  326. repeats:
  327. Number of attempts to flip at the above chance.
  328. Default: 3
  329. Type: int
  330.  
  331. no_shuffle:
  332. List of directions already flipped so it won't reverse anything.
  333. Type: list
  334. """
  335. #Set defaults
  336. if chance is None:
  337. chance = 10
  338. if second_chance is None:
  339. second_chance = 50
  340. if repeats is None:
  341. repeats = 3
  342.  
  343.  
  344. #Calculate range of random numbers
  345. chance = min(100, chance)
  346. if chance > 0:
  347. chance = int(round(300/chance))-1
  348. else:
  349. chance = 0
  350.  
  351. #Attempt to flip grid
  352. for i in range(repeats):
  353. shuffle_num = random.randint(0, chance)
  354. if shuffle_num in (0, 1, 2) and shuffle_num not in no_shuffle:
  355. no_shuffle.append(shuffle_num)
  356. if shuffle_num == 0:
  357. self.grid_data = SwapGridData(self.grid_data).x()
  358. if shuffle_num == 1:
  359. self.grid_data = SwapGridData(self.grid_data).y()
  360. if shuffle_num == 2:
  361. self.grid_data = SwapGridData(self.grid_data).z()
  362. if self.shuffle(chance=second_chance, no_shuffle=no_shuffle) or not not no_shuffle:
  363. return True
  364.  
  365.  
  366.  
  367. def update_score(self):
  368. """Recalculate the score.
  369.  
  370. There are 26 total directions from each point, or 13 lines, calculated in the DirectionCalculation() class.
  371. For each of the 13 lines, look both ways and count the number of values that match the current player.
  372.  
  373. This will find any matches from one point, so it's simple to then iterate through every point.
  374. A hash of each line is stored to avoid duplicates.
  375. """
  376.  
  377. try:
  378. self.grid_data_last_updated
  379. except AttributeError:
  380. self.grid_data_last_updated = None
  381.  
  382. if self.grid_data_last_updated != hash(tuple(self.grid_data)):
  383.  
  384. #Store hash of grid_data in it's current state to avoid unnecessarily running the code again when there's been no changes
  385. self.grid_data_last_updated = hash(tuple(self.grid_data))
  386.  
  387.  
  388. self.current_points = defaultdict(int)
  389. all_matches = set()
  390.  
  391. #Loop through each point
  392. for starting_point in range(len(self.grid_data)):
  393.  
  394. current_player = self.grid_data[starting_point]
  395.  
  396. if current_player:
  397.  
  398. for i in DirectionCalculation().opposite_direction:
  399.  
  400. #Get a list of directions and calculate movement amount
  401. possible_directions = [list(i)]
  402. possible_directions += [[j.replace(i, '') for i in possible_directions[0] for j in DirectionCalculation().direction_group.values() if i in j]]
  403. direction_movement = sum(self.direction_maths[j] for j in possible_directions[0])
  404.  
  405. #Build list of invalid directions
  406. invalid_directions = [[self.direction_edges[j] for j in possible_directions[k]] for k in (0, 1)]
  407. invalid_directions = [join_list(j) for j in invalid_directions]
  408.  
  409. num_matches = 1
  410. list_match = [starting_point]
  411.  
  412. #Use two loops for the opposite directions
  413. for j in (0, 1):
  414.  
  415. current_point = starting_point
  416.  
  417. while current_point not in invalid_directions[j] and 0 < current_point < len(self.grid_data):
  418. current_point += direction_movement * int('-'[:j] + '1')
  419. if self.grid_data[current_point] == current_player:
  420. num_matches += 1
  421. list_match.append(current_point)
  422. else:
  423. break
  424.  
  425. #Add a point if enough matches
  426. if num_matches == self.grid_size:
  427.  
  428. list_match = hash(tuple(sorted(list_match)))
  429. if list_match not in all_matches:
  430. all_matches.add(list_match)
  431. self.current_points[current_player] += 1
  432.  
  433.  
  434.  
  435.  
  436. def show_score(self, digits=False, marker='/'):
  437. """Print the current points.
  438.  
  439. Parameters:
  440. digits:
  441. If the score should be output as a number, or as individual marks.
  442. Default: False
  443. Type: bool
  444. marker:
  445. What each point should be displayed as.
  446. Default: '/'
  447. Type: str
  448.  
  449. >>> C3D = Connect3D()
  450. >>> C3D.update_score()
  451. >>> C3D.current_points['X'] = 5
  452. >>> C3D.current_points['O'] = 1
  453.  
  454. >>> C3D.show_score(False, '/')
  455. Player X: ///// Player O: /
  456. >>> C3D.show_score(True)
  457. Player X: 5 Player O: 1
  458. """
  459. self.update_score()
  460. multiply_value = 1 if digits else marker
  461. print 'Player X: {x} Player O: {o}'.format(x=multiply_value*(self.current_points['X']), o=multiply_value*self.current_points['O'])
  462.  
  463.  
  464. def draw(self):
  465. """Pass the grid data to the draw function."""
  466. DrawGrid(self.grid_data)
  467.  
  468.  
  469. def reset(self):
  470. """Empty the grid without creating a new Connect3D object."""
  471. self.grid_data = ['' for i in range(pow(self.grid_size, 3))]
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480. class DirectionCalculation(object):
  481. """Calculate which directions are possible to move in, based on the 6 directions.
  482. Any combination is fine, as long as it doesn't go back on itself, hence why X, Y and Z have been given two
  483. values each, as opposed to just using six values.
  484. Because the code to calculate score will look in one direction then reverse it, the list then needs to be
  485. trimmed down to remove any duplicate directions (eg. up/down and upright/downleft are both duplicates)
  486.  
  487. The code will output the following results, it is possible to use these instead of the class.
  488. direction_group = {'Y': 'UD', 'X': 'LR', 'Z': 'FB', ' ': ' '}
  489. opposite_direction = ('B', 'D', 'DF', 'LDB', 'DB', 'L', 'LUB', 'LUF', 'LF', 'RU', 'LB', 'LDF', 'RD')
  490. """
  491.  
  492. direction_group = {}
  493. direction_group['X'] = 'LR'
  494. direction_group['Y'] = 'UD'
  495. direction_group['Z'] = 'FB'
  496. direction_group[' '] = ' '
  497.  
  498. #Come up with all possible directions
  499. all_directions = set()
  500. for x in [' ', 'X']:
  501. for y in [' ', 'Y']:
  502. for z in [' ', 'Z']:
  503. x_directions = list(direction_group[x])
  504. y_directions = list(direction_group[y])
  505. z_directions = list(direction_group[z])
  506. for i in x_directions:
  507. for j in y_directions:
  508. for k in z_directions:
  509. all_directions.add((i+j+k).replace(' ', ''))
  510.  
  511. #Narrow list down to remove any opposite directions
  512. opposite_direction = all_directions.copy()
  513. for i in all_directions:
  514. if i in opposite_direction:
  515. new_direction = ''
  516. for j in list(i):
  517. for k in direction_group.values():
  518. if j in k:
  519. new_direction += k.replace(j, '')
  520. opposite_direction.remove(new_direction)
  521.  
  522.  
  523.  
  524.  
  525.  
  526. class PointConversion(object):
  527. """Used to convert the cell ID to 3D coordinates or vice versa.
  528. Mainly used for inputting the coordinates to make a move.
  529.  
  530. The cell ID is from 0 to grid_size^3, and coordinates are from 1 to grid_size.
  531. This means an ID of 0 is actually (1,1,1), and 3 would be (4,1,1).
  532.  
  533. - X -
  534. __1___2_
  535. / 1/ 0 / 1 /|
  536. Y /___/___/ |
  537. / 2/ 2 / 3 / |
  538. /___/___/ |
  539. | |____|___|
  540. | 1| / 4 /|5 /
  541. Z | /___/_|_/
  542. | 2| / 6 / 7|/
  543. |/___/___|
  544.  
  545. Parameters:
  546. grid_size:
  547. Size of the grid.
  548. Type: int
  549.  
  550. i:
  551. Cell ID or coordinates.
  552. Type int/tuple/list
  553.  
  554. Functions:
  555. to_3d
  556. to_int
  557. """
  558. def __init__(self, grid_size, i):
  559. self.grid_size = grid_size
  560. self.i = i
  561.  
  562. def to_3d(self):
  563. """Convert cell ID to a 3D coordinate.
  564.  
  565. >>> grid_size = 4
  566. >>> cell_id = 16
  567.  
  568. >>> PointConversion(grid_size, cell_id).to_3d()
  569. (1, 1, 2)
  570. """
  571. cell_id = int(self.i)
  572. z = cell_id / pow(self.grid_size, 2)
  573. cell_id %= pow(self.grid_size, 2)
  574. y = cell_id / self.grid_size
  575. x = cell_id % self.grid_size
  576. return tuple(cell_id+1 for cell_id in (x, y, z))
  577.  
  578. def to_int(self):
  579. """Convert 3D coordinates to the cell ID.
  580.  
  581. >>> grid_size = 4
  582. >>> coordinates = (4,2,3)
  583.  
  584. >>> PointConversion(grid_size, coordinates).to_int()
  585. 39
  586. """
  587. x, y, z = [int(i) for i in self.i]
  588. if all(i > 0 for i in (x, y, z)):
  589. return (x-1)*pow(self.grid_size, 0) + (y-1)*pow(self.grid_size, 1) + (z-1)*pow(self.grid_size, 2)
  590. return None
  591.  
  592.  
  593.  
  594. class SwapGridData(object):
  595. """Use the size of the grid to calculate how flip it on the X, Y, or Z axis.
  596. The flips keep the grid intact but change the perspective of the game.
  597.  
  598. Parameters:
  599. grid_data:
  600. 2D list of grid cells, amount must be a cube number.
  601. Type: list/tuple
  602.  
  603. Functions:
  604. x
  605. y
  606. z
  607. """
  608. def __init__(self, grid_data):
  609. self.grid_data = list(grid_data)
  610. self.grid_size = calculate_grid_size(self.grid_data)
  611.  
  612. def x(self):
  613. """Flip on the X axis.
  614.  
  615. >>> SwapGridData(range(8)).x()
  616. [1, 0, 3, 2, 5, 4, 7, 6]
  617. >>> DrawGrid(SwapGridData(range(8)).x())
  618. ________
  619. / 1 / 0 /|
  620. /___/___/ |
  621. / 3 / 2 / |
  622. /___/___/ |
  623. | |____|___|
  624. | / 5 /|4 /
  625. | /___/_|_/
  626. | / 7 / 6|/
  627. |/___/___|
  628. """
  629. return join_list(x[::-1] for x in split_list(self.grid_data, self.grid_size))
  630.  
  631. def y(self):
  632. """Flip on the Y axis.
  633.  
  634. >>> SwapGridData(range(8)).y()
  635. [2, 3, 0, 1, 6, 7, 4, 5]
  636. >>> DrawGrid(SwapGridData(range(8)).y())
  637. ________
  638. / 2 / 3 /|
  639. /___/___/ |
  640. / 0 / 1 / |
  641. /___/___/ |
  642. | |____|___|
  643. | / 6 /|7 /
  644. | /___/_|_/
  645. | / 4 / 5|/
  646. |/___/___|
  647. """
  648. group_split = split_list(self.grid_data, pow(self.grid_size, 2))
  649. return join_list(join_list(split_list(x, self.grid_size)[::-1]) for x in group_split)
  650.  
  651. def z(self):
  652. """Flip on the Z axis.
  653.  
  654. >>> SwapGridData(range(8)).z()
  655. [4, 5, 6, 7, 0, 1, 2, 3]
  656. >>> DrawGrid(SwapGridData(range(8)).z())
  657. ________
  658. / 4 / 5 /|
  659. /___/___/ |
  660. / 6 / 7 / |
  661. /___/___/ |
  662. | |____|___|
  663. | / 0 /|1 /
  664. | /___/_|_/
  665. | / 2 / 3|/
  666. |/___/___|
  667. """
  668. return join_list(split_list(self.grid_data, pow(self.grid_size, 2))[::-1])
  669.  
  670.  
  671.  
  672.  
  673.  
  674. def DrawGrid(grid_data):
  675. """Use the grid_data to output a grid of the correct size.
  676. Each value in grid_data must be 1 character or formatting will be wrong.
  677.  
  678. >>> grid_data = range(8)
  679.  
  680. >>> DrawGrid(grid_data)
  681. ________
  682. / 0 / 1 /|
  683. /___/___/ |
  684. / 2 / 3 / |
  685. /___/___/ |
  686. | |____|___|
  687. | / 4 /|5 /
  688. | /___/_|_/
  689. | / 6 / 7|/
  690. |/___/___|
  691.  
  692. """
  693. grid_size = calculate_grid_size(grid_data)
  694. k = 0
  695.  
  696. grid_range = range(grid_size)
  697. grid_output = []
  698. for j in grid_range:
  699.  
  700. row_top = ' '*(grid_size*2+1) + '_'*(grid_size*4)
  701. if j:
  702. row_top = '|' + row_top[:grid_size*2-1] + '|' + '_'*(grid_size*2) + '|' + '_'*(grid_size*2-1) + '|'
  703. grid_output.append(row_top)
  704.  
  705. for i in grid_range:
  706. row_display = ' '*(grid_size*2-i*2) + '/' + ''.join((' ' + str(grid_data[k+x]).ljust(1) + ' /') for x in grid_range)
  707. k += grid_size
  708. row_bottom = ' '*(grid_size*2-i*2-1) + '/' + '___/'*grid_size
  709.  
  710. if j != grid_range[-1]:
  711. row_display += ' '*(i*2) + '|'
  712. row_bottom += ' '*(i*2+1) + '|'
  713. if j:
  714. row_display = row_display[:grid_size*4+1] + '|' + row_display[grid_size*4+2:]
  715. row_bottom = row_bottom[:grid_size*4+1] + '|' + row_bottom[grid_size*4+2:]
  716.  
  717. row_display = '|' + row_display[1:]
  718. row_bottom = '|' + row_bottom[1:]
  719.  
  720. grid_output += [row_display, row_bottom]
  721.  
  722. print 'n'.join(grid_output)
  723.  
  724. def calculate_grid_size(grid_data):
  725. """Cube root the length of grid_data to find the grid size."""
  726. return int(round(pow(len(grid_data), 1.0/3.0), 0))
  727.  
  728. def split_list(x, n):
  729. """Split a list by n characters."""
  730. n = int(n)
  731. return [x[i:i+n] for i in range(0, len(x), n)]
  732.  
  733. def join_list(x):
  734. """Convert nested lists into one single list."""
  735. return [j for i in x for j in i]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement