1
0

900_array2d.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. from array2d import array2d
  2. from vmath import vec2i
  3. def exit_on_error():
  4. raise KeyboardInterrupt
  5. # test error args for __init__
  6. try:
  7. a = array2d(0, 0)
  8. exit_on_error()
  9. except ValueError:
  10. pass
  11. # test callable constructor
  12. a = array2d[tuple[int, int]](2, 4, lambda pos: (pos.x, pos.y))
  13. assert a.width == a.n_cols == 2
  14. assert a.height == a.n_rows == 4
  15. assert a.shape == vec2i(2, 4)
  16. assert a.numel == 8
  17. assert a.tolist() == [
  18. [(0, 0), (1, 0)],
  19. [(0, 1), (1, 1)],
  20. [(0, 2), (1, 2)],
  21. [(0, 3), (1, 3)]]
  22. assert a[0, :].tolist() == [[(0, 0)], [(0, 1)], [(0, 2)], [(0, 3)]]
  23. assert a[1, :].tolist() == [[(1, 0)], [(1, 1)], [(1, 2)], [(1, 3)]]
  24. assert a[:, 0].tolist() == [[(0, 0), (1, 0)]]
  25. assert a[:, -1].tolist() == [[(0, 3), (1, 3)]]
  26. # test is_valid
  27. assert a.is_valid(0, 0) and a.is_valid(vec2i(0, 0))
  28. assert a.is_valid(1, 3) and a.is_valid(vec2i(1, 3))
  29. assert not a.is_valid(2, 0) and not a.is_valid(vec2i(2, 0))
  30. assert not a.is_valid(0, 4) and not a.is_valid(vec2i(0, 4))
  31. assert not a.is_valid(-1, 0) and not a.is_valid(vec2i(-1, 0))
  32. assert not a.is_valid(0, -1) and not a.is_valid(vec2i(0, -1))
  33. # test get
  34. assert a.get(0, 0, -1) == (0, 0)
  35. assert a.get(1, 3) == (1, 3)
  36. assert a.get(2, 0) is None
  37. assert a.get(0, 4, 'S') == 'S'
  38. # test index
  39. assert a.index((0, 0)) == vec2i(0, 0)
  40. assert a.index((1, 3)) == vec2i(1, 3)
  41. # test __getitem__
  42. assert a[0, 0] == (0, 0)
  43. assert a[1, 3] == (1, 3)
  44. try:
  45. a[2, 0]
  46. exit_on_error()
  47. except IndexError:
  48. pass
  49. # test __setitem__
  50. a = array2d[int](2, 4, default=0)
  51. a[0, 0] = 5
  52. assert a[0, 0] == 5
  53. a[1, 3] = 6
  54. assert a[1, 3] == 6
  55. try:
  56. a[0, -1] = 7
  57. exit_on_error()
  58. except IndexError:
  59. pass
  60. # test tolist
  61. a_list = [[5, 0], [0, 0], [0, 0], [0, 6]]
  62. assert a_list == a.tolist()
  63. # test __eq__
  64. x = array2d(2, 4, default=0)
  65. b = array2d(2, 4, default=0)
  66. assert (x == b).all()
  67. b[0, 0] = 1
  68. assert (x != b).any()
  69. # test __repr__
  70. assert repr(a) == f'array2d(2, 4)'
  71. # test map
  72. c = a.map(lambda x: x + 1)
  73. assert c.tolist() == [[6, 1], [1, 1], [1, 1], [1, 7]]
  74. assert a.tolist() == [[5, 0], [0, 0], [0, 0], [0, 6]]
  75. assert c.width == c.n_cols == 2
  76. assert c.height == c.n_rows == 4
  77. assert c.numel == 8
  78. # test copy
  79. d = c.copy()
  80. assert (d == c).all() and d is not c
  81. # test fill_
  82. d[:, :] = -3 # d.fill_(-3)
  83. assert (d == array2d(2, 4, default=-3)).all()
  84. # test apply
  85. d.apply(lambda x: x + 3)
  86. assert (d == array2d(2, 4, default=0)).all()
  87. # test copy_
  88. a[:, :] = d
  89. assert (a == d).all() and a is not d
  90. x = array2d(2, 4, default=0)
  91. x[:, :] = d
  92. assert (x == d).all() and x is not d
  93. # test alive_neighbors
  94. a = array2d[int](3, 3, default=0)
  95. a[1, 1] = 1
  96. """ Moore von Neumann
  97. 0 0 0 1 1 1 0 1 0
  98. 0 1 0 1 0 1 1 0 1
  99. 0 0 0 1 1 1 0 1 0
  100. """
  101. moore_result = array2d(3, 3, default=1)
  102. moore_result[1, 1] = 0
  103. von_neumann_result = array2d(3, 3, default=0)
  104. von_neumann_result[0, 1] = von_neumann_result[1, 0] = von_neumann_result[1, 2] = von_neumann_result[2, 1] = 1
  105. _0 = a.count_neighbors(1, 'Moore')
  106. assert _0 == moore_result
  107. _1 = a.count_neighbors(1, 'von Neumann')
  108. assert _1 == von_neumann_result
  109. MOORE_KERNEL = array2d[int].fromlist([[1, 1, 1], [1, 0, 1], [1, 1, 1]])
  110. VON_NEUMANN_KERNEL = array2d.fromlist([[0, 1, 0], [1, 0, 1], [0, 1, 0]])
  111. moore_conv_result = a.convolve(MOORE_KERNEL, 0)
  112. assert (moore_conv_result == moore_result).all()
  113. von_neumann_conv_result = a.convolve(VON_NEUMANN_KERNEL, 0)
  114. assert (von_neumann_conv_result == von_neumann_result).all()
  115. # test slice get
  116. a = array2d(5, 5, default=0)
  117. b = array2d(3, 2, default=1)
  118. assert a[1:4, 1:4] == array2d(3, 3, default=0)
  119. assert a[1:4, 1:3] == array2d(3, 2, default=0)
  120. assert (a[1:4, 1:3] != b).any()
  121. a[1:4, 1:3] = b
  122. assert (a[1:4, 1:3] == b).all()
  123. """
  124. 0 0 0 0 0
  125. 0 1 1 1 0
  126. 0 1 1 1 0
  127. 0 0 0 0 0
  128. 0 0 0 0 0
  129. """
  130. assert a.count(1) == 3*2
  131. assert a.get_bounding_rect(1) == (1, 1, 3, 2)
  132. assert a.get_bounding_rect(0) == (0, 0, 5, 5)
  133. try:
  134. a.get_bounding_rect(2)
  135. exit_on_error()
  136. except ValueError:
  137. pass
  138. a = array2d(3, 2, default='?')
  139. # int/float/str/bool/None
  140. for value in [0, 0.0, '0', False, None]:
  141. a[0:2, 0:1] = value
  142. assert a[2, 1] == '?'
  143. assert a[0, 0] == value
  144. a[:, :] = 3
  145. assert a == array2d(3, 2, default=3)
  146. try:
  147. a[:, :] = array2d(1, 1)
  148. exit_on_error()
  149. except ValueError:
  150. pass
  151. # test __iter__
  152. a = array2d(3, 4, default=1)
  153. for xy, val in a:
  154. assert a[xy] == x
  155. # test convolve
  156. a = array2d[int].fromlist([[1, 0, 2, 4, 0], [3, 1, 0, 5, 1]])
  157. """
  158. 1 0 2 4 0
  159. 3 1 0 5 1
  160. """
  161. assert a.tolist() == [[1, 0, 2, 4, 0], [3, 1, 0, 5, 1]]
  162. kernel = array2d[int](3, 3, default=1)
  163. res = a.convolve(kernel, -1)
  164. """
  165. 0 4 9 9 5
  166. 0 4 9 9 5
  167. """
  168. assert res.tolist() == [[0, 4, 9, 9, 5], [0, 4, 9, 9, 5]]
  169. mask = res == 9
  170. assert mask.tolist() == [
  171. [False, False, True, True, False],
  172. [False, False, True, True, False]
  173. ]
  174. assert res[mask] == [9, 9, 9, 9]
  175. mask = res != 9
  176. assert mask.tolist() == [
  177. [True, True, False, False, True],
  178. [True, True, False, False, True]
  179. ]
  180. assert res[mask] == [0, 4, 5, 0, 4, 5]
  181. res[mask] = -1
  182. assert res.tolist() == [[-1, -1, 9, 9, -1], [-1, -1, 9, 9, -1]]
  183. # test get_connected_components
  184. a = array2d[int].fromlist([
  185. [1, 1, 0, 1],
  186. [0, 2, 2, 1],
  187. [0, 1, 1, 1],
  188. [1, 0, 0, 0],
  189. ])
  190. vis, cnt = a.get_connected_components(1, 'von Neumann')
  191. assert vis == [
  192. [1, 1, 0, 2],
  193. [0, 0, 0, 2],
  194. [0, 2, 2, 2],
  195. [3, 0, 0, 0]
  196. ]
  197. assert cnt == 3
  198. vis, cnt = a.get_connected_components(1, 'Moore')
  199. assert vis == [
  200. [1, 1, 0, 2],
  201. [0, 0, 0, 2],
  202. [0, 2, 2, 2],
  203. [2, 0, 0, 0]
  204. ]
  205. assert cnt == 2
  206. vis, cnt = a.get_connected_components(2, 'von Neumann')
  207. assert cnt == 1
  208. vis, cnt = a.get_connected_components(0, 'Moore')
  209. assert cnt == 2
  210. # test zip_with
  211. a = array2d[int].fromlist([[1, 2], [3, 4]])
  212. b = array2d[int].fromlist([[5, 6], [7, 8]])
  213. c = a.zip_with(b, lambda x, y: x + y)
  214. assert c.tolist() == [[6, 8], [10, 12]]
  215. # test magic op
  216. a = array2d[int].fromlist([[1, 2], [3, 4]])
  217. assert (a <= 2).tolist() == [[True, True], [False, False]]
  218. assert (a < 2).tolist() == [[True, False], [False, False]]
  219. assert (a >= 2).tolist() == [[False, True], [True, True]]
  220. assert (a > 2).tolist() == [[False, False], [True, True]]
  221. assert (a == 2).tolist() == [[False, True], [False, False]]
  222. assert (a != 2).tolist() == [[True, False], [True, True]]
  223. assert (a + 1).tolist() == [[2, 3], [4, 5]]
  224. assert (a - 1).tolist() == [[0, 1], [2, 3]]
  225. assert (a * 2).tolist() == [[2, 4], [6, 8]]
  226. assert (a / 1).tolist() == [[1.0, 2.0], [3.0, 4.0]]
  227. assert (a // 2).tolist() == [[0, 1], [1, 2]]
  228. assert (a % 2).tolist() == [[1, 0], [1, 0]]
  229. assert (a ** 2).tolist() == [[1, 4], [9, 16]]
  230. a = array2d[bool].fromlist([[True, False], [False, True]])
  231. assert (a & True).tolist() == [[True, False], [False, True]]
  232. assert (a | True).tolist() == [[True, True], [True, True]]
  233. assert (a ^ True).tolist() == [[False, True], [True, False]]
  234. b = array2d[bool].fromlist([[True, True], [False, False]])
  235. assert (a & b).tolist() == [[True, False], [False, False]]
  236. assert (a | b).tolist() == [[True, True], [False, True]]
  237. assert (a ^ b).tolist() == [[False, True], [False, True]]
  238. assert (~a).tolist() == [[False, True], [True, False]]
  239. assert (~b).tolist() == [[False, False], [True, True]]
  240. # stackoverflow bug due to recursive mark-and-sweep
  241. # class Cell:
  242. # neighbors: list['Cell']
  243. # cells: array2d[Cell] = array2d(192, 108, default=Cell)
  244. # OutOfBounds = Cell()
  245. # for x, y, cell in cells:
  246. # cell.neighbors = [
  247. # cells.get(x-1, y-1, OutOfBounds),
  248. # cells.get(x , y-1, OutOfBounds),
  249. # cells.get(x+1, y-1, OutOfBounds),
  250. # cells.get(x-1, y , OutOfBounds),
  251. # cells.get(x+1, y , OutOfBounds),
  252. # cells.get(x , y+1, OutOfBounds),
  253. # cells.get(x+1, y+1, OutOfBounds),
  254. # ]
  255. # import gc
  256. # gc.collect()