Newer
Older
CubeSolver / Code Stuff / packages / move.py
  1. import ast
  2. import copy
  3. import csv
  4.  
  5.  
  6. class Move:
  7. moveType = None # i.e spin, extension, delay etc
  8. index = None # stores the index on which the move acts on
  9. # (in this case the side of the machine or the index of the LED)
  10. position = None # which position to goto (angle or retraction since I've reused the variable)
  11. delay = None # only used for delay moves
  12. colour = None # colour set to LEDs during the move
  13.  
  14. # Validation dicts. Used to check weather the data that is given is valid
  15. _validMoves = {'spin', 'extension', 'delay', 'stop', 'led', 'photo'}
  16. _validSides = {'b': 0, 'r': 1, 'f': 2, 'l': 3, 0: 0, 1: 1, 2: 2, 3: 3}
  17. _validAngles = {0, 1, 2, 3}
  18. _validPositions = {'f', 'e', 'r'}
  19.  
  20. def __init__(self, _move_type, _index=None, _position=None, _colour=None, _delay=0.0):
  21. if _move_type in self._validMoves:
  22. self.moveType = _move_type
  23. else:
  24. raise ValueError("Invalid Move Type")
  25.  
  26. if _move_type == 'spin':
  27. try:
  28. self.index = self._validSides.get(_index)
  29. except KeyError:
  30. raise ValueError("Invalid Side Num")
  31.  
  32. if int(_position) in range(4):
  33. self.position = int(_position)
  34. else:
  35. raise ValueError("Invalid position num")
  36.  
  37. elif _move_type == 'extension':
  38. try:
  39. self.index = self._validSides.get(_index)
  40. except KeyError:
  41. raise ValueError("Invalid Side Num")
  42. if _position in self._validPositions:
  43. self.position = _position
  44. else:
  45. raise ValueError("Position must be either f, e or r")
  46.  
  47. elif _move_type == 'delay':
  48. self.delay = _delay
  49. elif _move_type == 'stop': # stops the servos 'pushing' when they are not being activated anymore
  50. self.index = _index
  51. elif _move_type == 'led':
  52. if _index in range(-1, 8):
  53. self.index = _index # in this case, index is the index of the LED
  54. else:
  55. raise ValueError("Invalid LED Index")
  56. # todo error checking
  57. self.colour = _colour
  58.  
  59. def execute(self, _machine):
  60. if self.moveType == 'spin':
  61. _machine.goto(self.index, self.position)
  62.  
  63. elif self.moveType == 'extension':
  64. if self.position == 'e':
  65. _machine.extend(self.index)
  66. elif self.position == 'r':
  67. _machine.retract(self.index)
  68. elif self.position == 'f':
  69. _machine.full_extend(self.index)
  70.  
  71. elif self.moveType == 'delay':
  72. return {'type': 'delay', 'content': self.delay}
  73.  
  74. elif self.moveType == 'stop':
  75. # todo check if this works
  76. _machine.set_angle(self.index, None)
  77. _machine.set_angle(self.index + 4, None)
  78.  
  79. elif self.moveType == 'led':
  80. _machine.set_leds(self.index, self.colour)
  81.  
  82. elif self.moveType == 'photo':
  83. _machine.take_photo()
  84. return {'type': 'none'}
  85.  
  86.  
  87. class MoveList:
  88. moves: list[Move] = []
  89. moves2 = None
  90. counter = 1
  91. machine = None
  92. waitSeconds = 0
  93. _running = False
  94.  
  95. def __init__(self, _machine, _moves: list[Move] = None, csv_path=None):
  96. self.machine = _machine
  97. if _moves is None:
  98. self.read_from_csv(csv_path)
  99. else:
  100. self.moves = _moves
  101.  
  102. def read_from_csv(self, csv_path):
  103. with open(csv_path, newline='') as csvfile:
  104. csv_reader = csv.DictReader(csvfile, delimiter=',', quotechar='|')
  105. for row in csv_reader:
  106. row_d = dict(row)
  107. # bit of a mess here to ensure all values are cast correctly
  108. move_type = row_d['move_type']
  109. if not move_type:
  110. raise ValueError("move_type passed empty")
  111. index = None
  112. if row_d['index']:
  113. index = int(row_d['index'])
  114. position = None
  115. if row_d['position']:
  116. try:
  117. position = int(row_d['position'])
  118. except ValueError:
  119. position = row_d['position']
  120. colour = None
  121. if row_d['colour'] is not None:
  122. colour = row_d['colour']
  123. delay = 0
  124. if row_d['delay']:
  125. delay = float(row_d['delay'])
  126.  
  127. self.moves.append(Move(
  128. move_type, index, position, colour, delay)
  129. )
  130.  
  131. def add_move(self, _move_type, _index=None, _position=None, _colour=None, _delay=0.0):
  132. self.moves.append(Move(_move_type, _index, _position, _colour, _delay))
  133.  
  134. def send_list_request(self):
  135. self.machine.execute_move_list(self.moves)
  136.  
  137. def execute(self):
  138. # dynamically executes the moves each time tick() is called
  139. self.moves2 = copy.copy(self.moves)
  140. self._running = True
  141.  
  142. def tick(self):
  143. if self._running:
  144. self.waitSeconds -= .05
  145. if self.waitSeconds <= 0:
  146. while True:
  147. move_delay = 0
  148. try:
  149. move_response = self.moves2[0].execute(self.machine)
  150. except IndexError:
  151. self._running = False
  152. self.counter -= 1
  153. if self.counter != 0:
  154. self.execute()
  155. break
  156. self.moves2.pop(0)
  157. if move_response['type'] == 'delay':
  158. move_delay = move_response['value']
  159. self.waitSeconds = move_delay
  160. elif move_response['type'] == 'camera':
  161. # hand down the response to be further handled
  162. return move_response