Genetic Turmit Evolver
python
c
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

turmit.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. from .rpnlib import *
  2. class Turmit(object):
  3. ''' @brief Represent a turmit that act given an RPN expression with an
  4. infinite looping stack with variable stack size.
  5. '''
  6. def __init__(self, stack_size=8, **kwargs):
  7. ''' @brief Instanciated a new Turmit with a programm and a memory stack
  8. @param stack_size int : stack_size
  9. @param prog str | RpnExpr | None : turmit programm if None generate
  10. it randomlt
  11. @param prog_size int : if prog is generated randomly it will make
  12. this size
  13. @param max_int int : maximum integer value + 1
  14. @param signed_int bool : if True integers are signed
  15. @throw ValueError for bad option value
  16. @throw RuntimError for bad arguments
  17. '''
  18. if stack_size < 2:
  19. msg = 'Stack size has to be >= 2 but %d given' % (stack_size)
  20. raise ValueError(msg)
  21. ## @brief List that represent a stack
  22. self._stack = [ 0 for _ in range(stack_size)]
  23. ## @brief Stack head index
  24. self._cur = stack_size - 1
  25. ## @brief Stores turmit direction
  26. self._dir = 0
  27. ## @brief Stores turmit program
  28. self._prog = None
  29. self._prog_sz = 42
  30. ## @brief Stores maximum int value + 1
  31. # @note This limit is handled by @ref rpnlib.RpnOp()
  32. self._max_int = 0x10000
  33. ## @brief If True integers are signed
  34. # @note This limit is handled by @ref rpnlib.RpnOp()
  35. self._signed_int = True
  36. if 'max_int' in kwargs:
  37. v = kwargs['max_int']
  38. if v < 1:
  39. raise ValueError('Maximum int have to be >= 1 but %d found' % v)
  40. self._max_int = kwargs['max_int']
  41. del(kwargs['max_int'])
  42. if 'signed_int' in kwargs:
  43. self._signed_int = bool(kwargs['signed_int'])
  44. del(kwargs['signed_int'])
  45. if 'prog_size' in kwargs:
  46. v = kwargs['prog_size']
  47. if v < 2:
  48. raise ValueError('Prog_size have to be >= 2 but %d found' % v)
  49. self._prog_sz = v
  50. del(kwargs['prog_size'])
  51. if 'prog' in kwargs:
  52. v = kwargs['prog']
  53. if isinstance(v, str):
  54. v = RpnExpr.from_string(v)
  55. if isinstance(v, RpnExpr):
  56. self._prog = v
  57. else:
  58. msg = 'Str or RpnExpr expected but %s found' % (type(v))
  59. raise TypeError(msg)
  60. del(kwargs['prog'])
  61. if len(kwargs) > 0:
  62. msg = 'Unexpected arguments : [%s]' % ', '.join(kwargs.keys())
  63. raise RuntimeError(msg)
  64. if self._prog is None:
  65. self._prog = RpnExpr.random(self._prog_sz)
  66. def __call__(self, **context):
  67. ''' @brief Exec the RPN expression and return the stack head
  68. @param context dict : dict with variable values (see @ref rpnlib._var_list)
  69. @return stack head after RPN
  70. '''
  71. self.__ip = 0
  72. while self.__ip < len(self._prog):
  73. sym = self._prog[self.__ip]
  74. if sym.optype == RpnSymbol.VALUE:
  75. self._push(sym.value)
  76. elif sym.optype == RpnSymbol.VARIABLE:
  77. self._push(context[sym.value.lower()])
  78. elif sym.optype == RpnSymbol.OPERATION:
  79. getattr(self, sym.value.lower())()
  80. self.__ip += 1
  81. return self.shead
  82. @property
  83. def shead(self):
  84. ''' @brief Stack head attribute '''
  85. return self._stack[self._cur]
  86. def _pop(self):
  87. ''' @brief Pops a value from the stack
  88. @note If stack head is 0, set the stack head to len(self._stack)
  89. - 1
  90. @return popped value
  91. '''
  92. res = self._stack[self._cur]
  93. if self._cur == 0:
  94. self._cur = len(self._stack) - 1
  95. else:
  96. self._cur -= 1
  97. return res
  98. def _push(self, val):
  99. ''' @brief Pushes a value on the stack
  100. @note If no space left on the stack, the head is set to 0
  101. @param val int : value to push
  102. '''
  103. self._cur += 1
  104. if self._cur >= len(self._stack) or abs(self._cur) >= len(self._stack):
  105. self._cur = 0
  106. self._stack[self._cur] = self._cast_int(val)
  107. def _cast_int(self, val):
  108. ''' @brief Transform integer given Turmit max int and signed_int
  109. attr
  110. @param val int : integer to transform
  111. @return integer
  112. '''
  113. val = int(val)
  114. if self._max_int is not None:
  115. val %= self._max_int
  116. if not self._signed_int and val < 0:
  117. val = self._max_int - val
  118. return val
  119. @RpnOp
  120. def mem_sz(self, new_sz):
  121. ''' @brief Update memory stack size
  122. '''
  123. if new_sz < 2:
  124. new_sz = 2
  125. stksz = len(self._stack)
  126. new_sz %= 0xFFF
  127. if new_sz > stksz:
  128. self._stack += [ 0 for _ in range(new_sz - stksz) ]
  129. elif new_sz < stksz:
  130. self._stack = self._stack[0:new_sz]
  131. if self._cur >= new_sz:
  132. self._cur = 0
  133. @RpnOp
  134. def add(self, a, b):
  135. ''' @brief Adds one value to another
  136. @param a int : value
  137. @param b int : value to add to a
  138. @return a + b
  139. '''
  140. return a + b
  141. @RpnOp
  142. def sub(self, a, b):
  143. ''' @brief Substitutes a value to another
  144. @param a int : value
  145. @param b int : value to substitute to a
  146. @return a - b
  147. '''
  148. return a - b
  149. @RpnOp
  150. def bin_and(self, a, b):
  151. ''' @brief Binary and
  152. @param a int : value
  153. @param b int : value
  154. @return a & b
  155. '''
  156. return a & b
  157. @RpnOp
  158. def dup(self, a):
  159. ''' @brief Duplicates stack head
  160. @param a int : value
  161. @return a
  162. '''
  163. self._push(a)
  164. return a
  165. @RpnOp
  166. def lshift(self, a, b):
  167. ''' @brief Left shifts a of b
  168. @param a int : value
  169. @param b int : value
  170. @return a << b
  171. '''
  172. return a << b
  173. @RpnOp
  174. def mod(self, a, b):
  175. ''' @brief Gives a modulo b
  176. @param a int : value
  177. @param b int : value
  178. @return a % b
  179. '''
  180. return a % b
  181. @RpnOp
  182. def mul(self, a, b):
  183. ''' @brief Multiplies a with b
  184. @param a int : value
  185. @param b int : value
  186. @return a * b
  187. '''
  188. return a * b
  189. @RpnOp
  190. def bin_or(self, a, b):
  191. ''' @brief Binary or
  192. @param a int : value
  193. @param b int : value
  194. @return a | b
  195. '''
  196. return a | b
  197. @RpnOp
  198. def bin_xor(self, a, b):
  199. ''' @brief Binary xor
  200. @param a int : value
  201. @param b int : value
  202. @return a ^ b
  203. '''
  204. return a ^ b
  205. @RpnOp
  206. def pop(self, a):
  207. ''' @brief Pops a, head of the stack
  208. @param a int : value
  209. '''
  210. pass
  211. @RpnOp
  212. def jmp(self, a):
  213. ''' @brief Increments IP
  214. '''
  215. self.__ip += a