trianglengin 1.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. tests/__init__.py +0 -0
  2. tests/conftest.py +108 -0
  3. tests/core/__init__.py +2 -0
  4. tests/core/environment/README.md +47 -0
  5. tests/core/environment/__init__.py +2 -0
  6. tests/core/environment/test_action_codec.py +50 -0
  7. tests/core/environment/test_game_state.py +483 -0
  8. tests/core/environment/test_grid_data.py +205 -0
  9. tests/core/environment/test_grid_logic.py +362 -0
  10. tests/core/environment/test_shape_logic.py +171 -0
  11. tests/core/environment/test_step.py +372 -0
  12. tests/core/structs/__init__.py +0 -0
  13. tests/core/structs/test_shape.py +83 -0
  14. tests/core/structs/test_triangle.py +97 -0
  15. tests/utils/__init__.py +0 -0
  16. tests/utils/test_geometry.py +93 -0
  17. trianglengin/__init__.py +18 -0
  18. trianglengin/app.py +110 -0
  19. trianglengin/cli.py +134 -0
  20. trianglengin/config/__init__.py +9 -0
  21. trianglengin/config/display_config.py +47 -0
  22. trianglengin/config/env_config.py +103 -0
  23. trianglengin/core/__init__.py +8 -0
  24. trianglengin/core/environment/__init__.py +31 -0
  25. trianglengin/core/environment/action_codec.py +37 -0
  26. trianglengin/core/environment/game_state.py +217 -0
  27. trianglengin/core/environment/grid/README.md +46 -0
  28. trianglengin/core/environment/grid/__init__.py +18 -0
  29. trianglengin/core/environment/grid/grid_data.py +140 -0
  30. trianglengin/core/environment/grid/line_cache.py +189 -0
  31. trianglengin/core/environment/grid/logic.py +131 -0
  32. trianglengin/core/environment/logic/__init__.py +3 -0
  33. trianglengin/core/environment/logic/actions.py +38 -0
  34. trianglengin/core/environment/logic/step.py +134 -0
  35. trianglengin/core/environment/shapes/__init__.py +19 -0
  36. trianglengin/core/environment/shapes/logic.py +84 -0
  37. trianglengin/core/environment/shapes/templates.py +587 -0
  38. trianglengin/core/structs/__init__.py +27 -0
  39. trianglengin/core/structs/constants.py +28 -0
  40. trianglengin/core/structs/shape.py +61 -0
  41. trianglengin/core/structs/triangle.py +48 -0
  42. trianglengin/interaction/README.md +45 -0
  43. trianglengin/interaction/__init__.py +17 -0
  44. trianglengin/interaction/debug_mode_handler.py +96 -0
  45. trianglengin/interaction/event_processor.py +43 -0
  46. trianglengin/interaction/input_handler.py +82 -0
  47. trianglengin/interaction/play_mode_handler.py +141 -0
  48. trianglengin/utils/__init__.py +9 -0
  49. trianglengin/utils/geometry.py +73 -0
  50. trianglengin/utils/types.py +10 -0
  51. trianglengin/visualization/README.md +44 -0
  52. trianglengin/visualization/__init__.py +61 -0
  53. trianglengin/visualization/core/README.md +52 -0
  54. trianglengin/visualization/core/__init__.py +12 -0
  55. trianglengin/visualization/core/colors.py +117 -0
  56. trianglengin/visualization/core/coord_mapper.py +73 -0
  57. trianglengin/visualization/core/fonts.py +55 -0
  58. trianglengin/visualization/core/layout.py +101 -0
  59. trianglengin/visualization/core/visualizer.py +232 -0
  60. trianglengin/visualization/drawing/README.md +45 -0
  61. trianglengin/visualization/drawing/__init__.py +30 -0
  62. trianglengin/visualization/drawing/grid.py +156 -0
  63. trianglengin/visualization/drawing/highlight.py +30 -0
  64. trianglengin/visualization/drawing/hud.py +39 -0
  65. trianglengin/visualization/drawing/previews.py +172 -0
  66. trianglengin/visualization/drawing/shapes.py +36 -0
  67. trianglengin-1.0.6.dist-info/METADATA +367 -0
  68. trianglengin-1.0.6.dist-info/RECORD +72 -0
  69. trianglengin-1.0.6.dist-info/WHEEL +5 -0
  70. trianglengin-1.0.6.dist-info/entry_points.txt +2 -0
  71. trianglengin-1.0.6.dist-info/licenses/LICENSE +22 -0
  72. trianglengin-1.0.6.dist-info/top_level.txt +2 -0
@@ -0,0 +1,587 @@
1
+ # File: trianglengin/core/environment/shapes/templates.py
2
+ # ==============================================================================
3
+ # == PREDEFINED SHAPE TEMPLATES ==
4
+ # == ==
5
+ # == DO NOT MODIFY THIS LIST MANUALLY unless you are absolutely sure! ==
6
+ # == These shapes are fundamental to the game's design and balance. ==
7
+ # == Modifying them can have unintended consequences on gameplay and agent ==
8
+ # == training. ==
9
+ # ==============================================================================
10
+
11
+ # List of predefined shape templates. Each template is a list of relative triangle coordinates (dr, dc, is_up).
12
+ # Coordinates are relative to the shape's origin (typically the top-leftmost triangle).
13
+ # is_up = True for upward-pointing triangle, False for downward-pointing.
14
+ PREDEFINED_SHAPE_TEMPLATES: list[list[tuple[int, int, bool]]] = [
15
+ [ # Shape 1
16
+ (
17
+ 0,
18
+ 0,
19
+ True,
20
+ )
21
+ ],
22
+ [ # Shape 1
23
+ (
24
+ 0,
25
+ 0,
26
+ True,
27
+ )
28
+ ],
29
+ [ # Shape 2
30
+ (
31
+ 0,
32
+ 0,
33
+ True,
34
+ ),
35
+ (
36
+ 1,
37
+ 0,
38
+ False,
39
+ ),
40
+ ],
41
+ [ # Shape 2
42
+ (
43
+ 0,
44
+ 0,
45
+ True,
46
+ ),
47
+ (
48
+ 1,
49
+ 0,
50
+ False,
51
+ ),
52
+ ],
53
+ [ # Shape 3
54
+ (
55
+ 0,
56
+ 0,
57
+ False,
58
+ )
59
+ ],
60
+ [ # Shape 4
61
+ (
62
+ 0,
63
+ 0,
64
+ True,
65
+ ),
66
+ (
67
+ 0,
68
+ 1,
69
+ False,
70
+ ),
71
+ ],
72
+ [ # Shape 4
73
+ (
74
+ 0,
75
+ 0,
76
+ True,
77
+ ),
78
+ (
79
+ 0,
80
+ 1,
81
+ False,
82
+ ),
83
+ ],
84
+ [ # Shape 5
85
+ (
86
+ 0,
87
+ 0,
88
+ False,
89
+ ),
90
+ (
91
+ 0,
92
+ 1,
93
+ True,
94
+ ),
95
+ ],
96
+ [ # Shape 5
97
+ (
98
+ 0,
99
+ 0,
100
+ False,
101
+ ),
102
+ (
103
+ 0,
104
+ 1,
105
+ True,
106
+ ),
107
+ ],
108
+ [ # Shape 6
109
+ (
110
+ 0,
111
+ 0,
112
+ True,
113
+ ),
114
+ (
115
+ 0,
116
+ 1,
117
+ False,
118
+ ),
119
+ (
120
+ 0,
121
+ 2,
122
+ True,
123
+ ),
124
+ ],
125
+ [ # Shape 7
126
+ (
127
+ 0,
128
+ 0,
129
+ False,
130
+ ),
131
+ (
132
+ 0,
133
+ 1,
134
+ True,
135
+ ),
136
+ (
137
+ 0,
138
+ 2,
139
+ False,
140
+ ),
141
+ ],
142
+ [ # Shape 8
143
+ (
144
+ 0,
145
+ 0,
146
+ True,
147
+ ),
148
+ (
149
+ 0,
150
+ 1,
151
+ False,
152
+ ),
153
+ (
154
+ 0,
155
+ 2,
156
+ True,
157
+ ),
158
+ (
159
+ 1,
160
+ 0,
161
+ False,
162
+ ),
163
+ ],
164
+ [ # Shape 9
165
+ (
166
+ 0,
167
+ 0,
168
+ True,
169
+ ),
170
+ (
171
+ 0,
172
+ 1,
173
+ False,
174
+ ),
175
+ (
176
+ 0,
177
+ 2,
178
+ True,
179
+ ),
180
+ (
181
+ 1,
182
+ 2,
183
+ False,
184
+ ),
185
+ ],
186
+ [ # Shape 10
187
+ (
188
+ 0,
189
+ 0,
190
+ False,
191
+ ),
192
+ (
193
+ 0,
194
+ 1,
195
+ True,
196
+ ),
197
+ (
198
+ 1,
199
+ 0,
200
+ True,
201
+ ),
202
+ (
203
+ 1,
204
+ 1,
205
+ False,
206
+ ),
207
+ ],
208
+ [ # Shape 11
209
+ (
210
+ 0,
211
+ 0,
212
+ True,
213
+ ),
214
+ (
215
+ 0,
216
+ 2,
217
+ True,
218
+ ),
219
+ (
220
+ 1,
221
+ 0,
222
+ False,
223
+ ),
224
+ (
225
+ 1,
226
+ 1,
227
+ True,
228
+ ),
229
+ (
230
+ 1,
231
+ 2,
232
+ False,
233
+ ),
234
+ ],
235
+ [ # Shape 12
236
+ (
237
+ 0,
238
+ 0,
239
+ True,
240
+ ),
241
+ (
242
+ 1,
243
+ -2,
244
+ False,
245
+ ),
246
+ (
247
+ 1,
248
+ -1,
249
+ True,
250
+ ),
251
+ (
252
+ 1,
253
+ 0,
254
+ False,
255
+ ),
256
+ ],
257
+ [ # Shape 13
258
+ (
259
+ 0,
260
+ 0,
261
+ True,
262
+ ),
263
+ (
264
+ 0,
265
+ 1,
266
+ False,
267
+ ),
268
+ (
269
+ 1,
270
+ 0,
271
+ False,
272
+ ),
273
+ (
274
+ 1,
275
+ 1,
276
+ True,
277
+ ),
278
+ ],
279
+ [ # Shape 14
280
+ (
281
+ 0,
282
+ 0,
283
+ True,
284
+ ),
285
+ (
286
+ 0,
287
+ 1,
288
+ False,
289
+ ),
290
+ (
291
+ 1,
292
+ 0,
293
+ False,
294
+ ),
295
+ (
296
+ 1,
297
+ 1,
298
+ True,
299
+ ),
300
+ (
301
+ 1,
302
+ 2,
303
+ False,
304
+ ),
305
+ ],
306
+ [ # Shape 15
307
+ (
308
+ 0,
309
+ 0,
310
+ True,
311
+ ),
312
+ (
313
+ 0,
314
+ 1,
315
+ False,
316
+ ),
317
+ (
318
+ 0,
319
+ 2,
320
+ True,
321
+ ),
322
+ (
323
+ 1,
324
+ 0,
325
+ False,
326
+ ),
327
+ (
328
+ 1,
329
+ 1,
330
+ True,
331
+ ),
332
+ ],
333
+ [ # Shape 16
334
+ (
335
+ 0,
336
+ 0,
337
+ True,
338
+ ),
339
+ (
340
+ 0,
341
+ 1,
342
+ False,
343
+ ),
344
+ (
345
+ 0,
346
+ 2,
347
+ True,
348
+ ),
349
+ (
350
+ 1,
351
+ 0,
352
+ False,
353
+ ),
354
+ (
355
+ 1,
356
+ 2,
357
+ False,
358
+ ),
359
+ ],
360
+ [ # Shape 17
361
+ (
362
+ 0,
363
+ 0,
364
+ True,
365
+ ),
366
+ (
367
+ 0,
368
+ 1,
369
+ False,
370
+ ),
371
+ (
372
+ 0,
373
+ 2,
374
+ True,
375
+ ),
376
+ (
377
+ 1,
378
+ 1,
379
+ True,
380
+ ),
381
+ (
382
+ 1,
383
+ 2,
384
+ False,
385
+ ),
386
+ ],
387
+ [ # Shape 18
388
+ (
389
+ 0,
390
+ 0,
391
+ True,
392
+ ),
393
+ (
394
+ 0,
395
+ 2,
396
+ True,
397
+ ),
398
+ (
399
+ 1,
400
+ 0,
401
+ False,
402
+ ),
403
+ (
404
+ 1,
405
+ 1,
406
+ True,
407
+ ),
408
+ (
409
+ 1,
410
+ 2,
411
+ False,
412
+ ),
413
+ ],
414
+ [ # Shape 19
415
+ (
416
+ 0,
417
+ 0,
418
+ True,
419
+ ),
420
+ (
421
+ 0,
422
+ 1,
423
+ False,
424
+ ),
425
+ (
426
+ 1,
427
+ 0,
428
+ False,
429
+ ),
430
+ (
431
+ 1,
432
+ 1,
433
+ True,
434
+ ),
435
+ (
436
+ 1,
437
+ 2,
438
+ False,
439
+ ),
440
+ ],
441
+ [ # Shape 20
442
+ (
443
+ 0,
444
+ 0,
445
+ False,
446
+ ),
447
+ (
448
+ 0,
449
+ 1,
450
+ True,
451
+ ),
452
+ (
453
+ 1,
454
+ 1,
455
+ False,
456
+ ),
457
+ ],
458
+ [ # Shape 21
459
+ (
460
+ 0,
461
+ 0,
462
+ True,
463
+ ),
464
+ (
465
+ 1,
466
+ -1,
467
+ True,
468
+ ),
469
+ (
470
+ 1,
471
+ 0,
472
+ False,
473
+ ),
474
+ ],
475
+ [ # Shape 22
476
+ (
477
+ 0,
478
+ 0,
479
+ True,
480
+ ),
481
+ (
482
+ 1,
483
+ 0,
484
+ False,
485
+ ),
486
+ (
487
+ 1,
488
+ 1,
489
+ True,
490
+ ),
491
+ ],
492
+ [ # Shape 23
493
+ (
494
+ 0,
495
+ 0,
496
+ True,
497
+ ),
498
+ (
499
+ 1,
500
+ -1,
501
+ True,
502
+ ),
503
+ (
504
+ 1,
505
+ 0,
506
+ False,
507
+ ),
508
+ (
509
+ 1,
510
+ 1,
511
+ True,
512
+ ),
513
+ ],
514
+ [ # Shape 24
515
+ (
516
+ 0,
517
+ 0,
518
+ True,
519
+ ),
520
+ (
521
+ 1,
522
+ -1,
523
+ True,
524
+ ),
525
+ (
526
+ 1,
527
+ 0,
528
+ False,
529
+ ),
530
+ ],
531
+ [ # Shape 25
532
+ (
533
+ 0,
534
+ 0,
535
+ False,
536
+ ),
537
+ (
538
+ 0,
539
+ 1,
540
+ True,
541
+ ),
542
+ (
543
+ 0,
544
+ 2,
545
+ False,
546
+ ),
547
+ (
548
+ 1,
549
+ 1,
550
+ False,
551
+ ),
552
+ ],
553
+ [ # Shape 26
554
+ (
555
+ 0,
556
+ 0,
557
+ False,
558
+ ),
559
+ (
560
+ 0,
561
+ 1,
562
+ True,
563
+ ),
564
+ (
565
+ 1,
566
+ 1,
567
+ False,
568
+ ),
569
+ ],
570
+ [ # Shape 27
571
+ (
572
+ 0,
573
+ 0,
574
+ True,
575
+ ),
576
+ (
577
+ 0,
578
+ 1,
579
+ False,
580
+ ),
581
+ (
582
+ 1,
583
+ 0,
584
+ False,
585
+ ),
586
+ ],
587
+ ]
@@ -0,0 +1,27 @@
1
+ # File: trianglengin/core/structs/__init__.py
2
+ """
3
+ Module for core data structures used across different parts of the application,
4
+ like environment, visualization, and features. Helps avoid circular dependencies.
5
+ """
6
+
7
+ # Correctly export constants from the constants submodule
8
+ from .constants import (
9
+ COLOR_ID_MAP,
10
+ COLOR_TO_ID_MAP,
11
+ DEBUG_COLOR_ID,
12
+ NO_COLOR_ID,
13
+ SHAPE_COLORS,
14
+ )
15
+ from .shape import Shape
16
+ from .triangle import Triangle
17
+
18
+ __all__ = [
19
+ "Triangle",
20
+ "Shape",
21
+ # Exported Constants
22
+ "SHAPE_COLORS",
23
+ "NO_COLOR_ID",
24
+ "DEBUG_COLOR_ID",
25
+ "COLOR_ID_MAP",
26
+ "COLOR_TO_ID_MAP",
27
+ ]
@@ -0,0 +1,28 @@
1
+ SHAPE_COLORS: list[tuple[int, int, int]] = [
2
+ (220, 40, 40), # 0: Red
3
+ (60, 60, 220), # 1: Blue
4
+ (40, 200, 40), # 2: Green
5
+ (230, 230, 40), # 3: Yellow
6
+ (240, 150, 20), # 4: Orange
7
+ (140, 40, 140), # 5: Purple
8
+ (40, 200, 200), # 6: Cyan
9
+ (200, 100, 180), # 7: Pink (Example addition)
10
+ (100, 180, 200), # 8: Light Blue (Example addition)
11
+ ]
12
+
13
+ # --- NumPy GridData Color Representation ---
14
+ # ID for empty cells in the _color_id_np array
15
+ NO_COLOR_ID: int = -1
16
+ # ID for debug-toggled cells
17
+ DEBUG_COLOR_ID: int = -2
18
+
19
+ # Mapping from Color ID (int >= 0) to RGB tuple.
20
+ # Index 0 corresponds to SHAPE_COLORS[0], etc.
21
+ # This list is used by visualization to get the RGB from the ID.
22
+ COLOR_ID_MAP: list[tuple[int, int, int]] = SHAPE_COLORS
23
+
24
+ # Reverse mapping for efficient lookup during placement (Color Tuple -> ID)
25
+ # Note: Ensure SHAPE_COLORS have unique tuples.
26
+ COLOR_TO_ID_MAP: dict[tuple[int, int, int], int] = {
27
+ color: i for i, color in enumerate(COLOR_ID_MAP)
28
+ }
@@ -0,0 +1,61 @@
1
+ # File: trianglengin/core/structs/shape.py
2
+ from __future__ import annotations
3
+
4
+ import logging
5
+ from typing import cast
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class Shape:
11
+ """Represents a polyomino-like shape made of triangles."""
12
+
13
+ def __init__(
14
+ self, triangles: list[tuple[int, int, bool]], color: tuple[int, int, int]
15
+ ):
16
+ # Ensure triangles are tuples and sort them for consistent representation
17
+ # Sorting is based on (row, col) primarily
18
+ try:
19
+ # Explicitly cast inner tuples to the correct type for mypy
20
+ processed_triangles = [
21
+ cast("tuple[int, int, bool]", tuple(t)) for t in triangles
22
+ ]
23
+ self.triangles: list[tuple[int, int, bool]] = sorted(processed_triangles)
24
+ except Exception as e:
25
+ logger.error(f"Failed to sort triangles: {triangles}. Error: {e}")
26
+ # Fallback or re-raise depending on desired behavior
27
+ self.triangles = [
28
+ cast("tuple[int, int, bool]", tuple(t)) for t in triangles
29
+ ] # Store as is if sort fails
30
+
31
+ self.color: tuple[int, int, int] = color
32
+
33
+ def bbox(self) -> tuple[int, int, int, int]:
34
+ """Calculates bounding box (min_r, min_c, max_r, max_c) in relative coords."""
35
+ if not self.triangles:
36
+ return (0, 0, 0, 0)
37
+ rows = [t[0] for t in self.triangles]
38
+ cols = [t[1] for t in self.triangles]
39
+ return (min(rows), min(cols), max(rows), max(cols))
40
+
41
+ def copy(self) -> Shape:
42
+ """Creates a shallow copy (triangle list is copied, color is shared)."""
43
+ new_shape = Shape.__new__(Shape)
44
+ new_shape.triangles = list(self.triangles)
45
+ new_shape.color = self.color
46
+ return new_shape
47
+
48
+ def __str__(self) -> str:
49
+ return f"Shape(Color:{self.color}, Tris:{len(self.triangles)})"
50
+
51
+ def __eq__(self, other: object) -> bool:
52
+ """Checks for equality based on triangles and color."""
53
+ if not isinstance(other, Shape):
54
+ return NotImplemented
55
+ # Compare sorted lists of tuples
56
+ return self.triangles == other.triangles and self.color == other.color
57
+
58
+ def __hash__(self) -> int:
59
+ """Allows shapes to be used in sets/dicts if needed."""
60
+ # Hash the tuple representation of the sorted list
61
+ return hash((tuple(self.triangles), self.color))