Spaces:
Sleeping
Sleeping
first cube class
Browse files- README.md +14 -2
- src/rubik/cube.py +88 -0
README.md
CHANGED
|
@@ -14,8 +14,20 @@ pre-commit install
|
|
| 14 |
|
| 15 |
## Basic usage
|
| 16 |
|
| 17 |
-
```
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
```
|
| 20 |
|
| 21 |
## Roadmap
|
|
|
|
| 14 |
|
| 15 |
## Basic usage
|
| 16 |
|
| 17 |
+
```python
|
| 18 |
+
from cubik import Cube
|
| 19 |
+
|
| 20 |
+
cube = Cube.from_default(['U', 'L', 'C', 'R', 'B', 'D'], size = 3)
|
| 21 |
+
print(cube)
|
| 22 |
+
# UUU
|
| 23 |
+
# UUU
|
| 24 |
+
# UUU
|
| 25 |
+
# LLL CCC RRR BBB
|
| 26 |
+
# LLL CCC RRR BBB
|
| 27 |
+
# LLL CCC RRR BBB
|
| 28 |
+
# DDD
|
| 29 |
+
# DDD
|
| 30 |
+
# DDD
|
| 31 |
```
|
| 32 |
|
| 33 |
## Roadmap
|
src/rubik/cube.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
@dataclass
|
| 7 |
+
class Cube:
|
| 8 |
+
"""
|
| 9 |
+
A 5D tensor filled with 0 or 1. Dimensions have the following interpretation:
|
| 10 |
+
- X coordinate (from 0 to self.size - 1, from Left to Right).
|
| 11 |
+
- Y coordinate (from 0 to self.size - 1, from Back to Front).
|
| 12 |
+
- Z coordinate (from 0 to self.size - 1, from Down to Up).
|
| 13 |
+
- Face (from 0 to 5, with 0 = "Up", 1 = "Left", 2 = "Front", 3 = "Right", 4 = "Back", 5 = "Down").
|
| 14 |
+
- Color (from 0 to 6, 0 being the "dark" color, the rest according to order given in "colors" attribute).
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
tensor: torch.Tensor
|
| 18 |
+
colors: list[str]
|
| 19 |
+
size: int
|
| 20 |
+
|
| 21 |
+
@classmethod
|
| 22 |
+
def from_default(cls, colors: list[str], size: int) -> "Cube":
|
| 23 |
+
"""
|
| 24 |
+
Create Cube from a given list of 6 colors and size.
|
| 25 |
+
Example:
|
| 26 |
+
cube = Cube.from_default(['U', 'L', 'C', 'R', 'B', 'D'], size = 3)
|
| 27 |
+
"""
|
| 28 |
+
assert (num := len(set(colors))) == 6, f"Expected 6 distinct colors, got {num}"
|
| 29 |
+
assert isinstance(size, int) and size > 1, (
|
| 30 |
+
f"Expected non-zero integrer size, got {size}"
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
# build tensor filled with 0's, and fill the faces with 1's
|
| 34 |
+
n = size - 1
|
| 35 |
+
tensor = torch.zeros([size, size, size, 6, 7], dtype=torch.int8)
|
| 36 |
+
tensor[:, :, n, 0, 1] = 1 # up
|
| 37 |
+
tensor[0, :, :, 1, 2] = 1 # left
|
| 38 |
+
tensor[:, 0, :, 2, 3] = 1 # front
|
| 39 |
+
tensor[n, :, :, 3, 4] = 1 # right
|
| 40 |
+
tensor[:, n, :, 4, 5] = 1 # back
|
| 41 |
+
tensor[:, :, 0, 5, 6] = 1 # down
|
| 42 |
+
return cls(tensor, colors, size)
|
| 43 |
+
|
| 44 |
+
def to_grid(self) -> list[list[list[str]]]:
|
| 45 |
+
"""
|
| 46 |
+
Convert Cube into a 3D grid representation.
|
| 47 |
+
"""
|
| 48 |
+
n = self.size - 1
|
| 49 |
+
grid = [
|
| 50 |
+
self.tensor[:, :, n, 0, :].argmax(dim=-1), # up
|
| 51 |
+
self.tensor[0, :, :, 1, :].argmax(dim=-1), # left
|
| 52 |
+
self.tensor[:, 0, :, 2, :].argmax(dim=-1), # front
|
| 53 |
+
self.tensor[n, :, :, 3, :].argmax(dim=-1), # right
|
| 54 |
+
self.tensor[:, n, :, 4, :].argmax(dim=-1), # back
|
| 55 |
+
self.tensor[:, :, 0, 5, :].argmax(dim=-1), # down
|
| 56 |
+
]
|
| 57 |
+
return [
|
| 58 |
+
[[self.colors[i - 1] for i in row] for row in face.tolist()]
|
| 59 |
+
for face in grid
|
| 60 |
+
]
|
| 61 |
+
|
| 62 |
+
def __str__(self):
|
| 63 |
+
"""
|
| 64 |
+
Compute a string representation of a cube.
|
| 65 |
+
Example:
|
| 66 |
+
cube = Cube.from_default(['U', 'L', 'C', 'R', 'B', 'D'], size = 3)
|
| 67 |
+
print(cube)
|
| 68 |
+
# UUU
|
| 69 |
+
# UUU
|
| 70 |
+
# UUU
|
| 71 |
+
# LLL CCC RRR BBB
|
| 72 |
+
# LLL CCC RRR BBB
|
| 73 |
+
# LLL CCC RRR BBB
|
| 74 |
+
# DDD
|
| 75 |
+
# DDD
|
| 76 |
+
# DDD
|
| 77 |
+
"""
|
| 78 |
+
grid = self.to_grid()
|
| 79 |
+
void = " " * self.size
|
| 80 |
+
top = "\n".join(" ".join([void, "".join(row), void, void]) for row in grid[0])
|
| 81 |
+
middle = "\n".join(
|
| 82 |
+
" ".join("".join(grid[face_i][row_i]) for face_i in range(1, 5))
|
| 83 |
+
for row_i in range(self.size)
|
| 84 |
+
)
|
| 85 |
+
bottom = "\n".join(
|
| 86 |
+
" ".join((void, "".join(row), void, void)) for row in grid[-1]
|
| 87 |
+
)
|
| 88 |
+
return "\n".join([top, middle, bottom])
|