-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
290 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"\u001b[33mWARNING: You are using pip version 22.0.4; however, version 23.0.1 is available.\n", | ||
"You should consider upgrading via the '/home/osman/Documents/github/rubics-cube/.venv/bin/python -m pip install --upgrade pip' command.\u001b[0m\u001b[33m\n", | ||
"\u001b[0m" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"!pip install --no-cache-dir -q -U ../.." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 10, | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
" ╔═U════╗\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;33myy\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
"╔═L════╬═F════╬═R════╦═B════╗\n", | ||
"║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[1;31mrr\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[38;5;214moo\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[1;31mrr\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[38;5;214moo\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[38;5;214moo\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"╚══════╬═D════╬══════╩══════╝\n", | ||
" ║\u001b[38;5;255mww\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ╚══════╝\n", | ||
"current best cube value: 24\n", | ||
"Solution length: 3 moves\n", | ||
" ╔═U════╗\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
"╔═L════╬═F════╬═R════╦═B════╗\n", | ||
"║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"╚══════╬═D════╬══════╩══════╝\n", | ||
" ║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ╚══════╝\n", | ||
" ╔═U════╗\n", | ||
" ║\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\n", | ||
"╔═L════╬═F════╬═R════╦═B════╗\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[1;34mbb\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;32mgg\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"╚══════╬═D════╬══════╩══════╝\n", | ||
" ║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ╚══════╝\n", | ||
" ╔═U════╗\n", | ||
" ║\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
" ║\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m\u001b[1;34mbb\u001b[0m║\n", | ||
"╔═L════╬═F════╬═R════╦═B════╗\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"║\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m\u001b[38;5;214moo\u001b[0m║\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m\u001b[38;5;255mww\u001b[0m║\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m\u001b[1;31mrr\u001b[0m║\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m\u001b[1;33myy\u001b[0m║\n", | ||
"╚══════╬═D════╬══════╩══════╝\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ║\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m\u001b[1;32mgg\u001b[0m║\n", | ||
" ╚══════╝\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"import rubics_cube as rc\n", | ||
"\n", | ||
"cube = rc.Cube(size=3, show_letter=True)\n", | ||
"cube.shuffle(4)\n", | ||
"\n", | ||
"cube.print()\n", | ||
"\n", | ||
"heuristic = rc.same_color_amount\n", | ||
"solver = rc.AStarSolver(cube, heuristic)\n", | ||
"\n", | ||
"solution = solver.solve()\n", | ||
"\n", | ||
"print(\"Solution length:\", len(solution), \"moves\")\n", | ||
"\n", | ||
"for move in solution:\n", | ||
" cube.make_move(move)\n", | ||
" cube.print()\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": ".venv", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.8.16" | ||
}, | ||
"orig_nbformat": 4, | ||
"vscode": { | ||
"interpreter": { | ||
"hash": "cfcf6a851aa7abbcb53a758be308e0956bbf6a72dc19c18fa073aa2d68ce39af" | ||
} | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import numpy as np | ||
from .cube import Cube | ||
from typing import Callable | ||
|
||
def same_color_amount(combinations: np.array) -> int: | ||
"""Sum of the largest amount of same colors on a face. | ||
On a 5x5x5 cube largest possible amount is 6*5*5 = 150. | ||
*bigger the better* | ||
Args: | ||
combinations (np.array): A combination of a cube. shape: (6, n, n) | ||
Returns: | ||
int: Value of the heuristic. | ||
""" | ||
|
||
# check if the colors are the same on the same face | ||
same_color_amount = 0 | ||
for face in combinations: | ||
value_counts = np.unique(face, return_counts=True)[1] | ||
same_color_amount += np.max(value_counts) | ||
|
||
# but we need a function that returns a smaller value for a better solution | ||
# so we subtract the value from the maximum possible value | ||
max_possible_value = 6*combinations.shape[1]*combinations.shape[2] | ||
return max_possible_value - same_color_amount | ||
|
||
|
||
|
||
class AStarSolver(): | ||
def __init__(self, cube: Cube, heuristic: Callable): | ||
"""Initialize the solver. | ||
Args: | ||
combinations (np.array): A combination of a cube. | ||
""" | ||
self.cube = cube | ||
self.heuristic = heuristic | ||
self.possible_moves = cube.get_possible_moves() # possible moves are constant | ||
|
||
# lets remove rotational moves from the possible moves | ||
self.possible_moves = [move for move in self.possible_moves if not (("x" in move) or ("y" in move) or ("z" in move))] | ||
|
||
def make_str(self, combinations: np.array) -> str: | ||
"""Make a string from the combinations. | ||
Args: | ||
combinations (np.array): A combination of a cube. | ||
Returns: | ||
str: The string. | ||
""" | ||
return "".join(["".join(x_row) for face in combinations for x_row in face]) | ||
|
||
|
||
def solve(self) -> str: | ||
"""Solve the cube. | ||
Returns: | ||
str: The solution. | ||
""" | ||
if self.cube.is_solved(): | ||
print("Cube is already solved!") | ||
return "" | ||
|
||
# current combinations of the cube | ||
initial_combinations = self.cube.combinations.copy() | ||
|
||
visited = [str(initial_combinations)] | ||
queue = [(initial_combinations, (), self.heuristic(initial_combinations))] | ||
# queue elements in the form of (combinations, path, value) | ||
|
||
print("current best cube value: ", queue[0][2]) | ||
|
||
|
||
while queue: | ||
# sort the queue by the value of the elements | ||
|
||
queue = sorted(queue, key=lambda x: len(x[1])+ x[2]) # length of the path + evaluation value | ||
|
||
# get the element with the lowest value | ||
combinations, path, value = queue.pop(0) | ||
|
||
# check if the cube is solved | ||
new_cube = Cube.from_combinations(combinations) | ||
|
||
if new_cube.is_solved(): | ||
return path | ||
|
||
for move in self.possible_moves: | ||
child_cube = Cube.from_combinations(combinations.copy()) | ||
child_cube.make_move(move) | ||
new_combinations = child_cube.combinations | ||
# check if the new combinations are already visited | ||
if str(new_combinations) not in visited: | ||
visited.append(str(new_combinations)) | ||
queue_element = (new_combinations.copy(), (*path, move), self.heuristic(new_combinations)) | ||
queue.append(queue_element) | ||
|
||
if child_cube.is_solved(): | ||
return queue_element[1] | ||
|
||
raise ValueError("Invalid cube!") | ||
|