Мой последний проект для CS50 — это решатель кубика Рубика «человеческим методом».
Это означает, что введенный кубик Рубика собирается с использованием метода, который может использовать человек (CFOP), с четкими шагами: Cross, F2L, OLL и PLL.
Конечный продукт состоит из приложения оболочки, библиотеки C для использования в других проектах и веб-интерфейса, написанного на Flask, HTML, CSS и Javascript.
Я решил создать решатель кубика Рубика, потому что раньше я создавал решатель судоку на C++, и этот кубик был шагом вперед.
Вместо 2D-плоскости у меня полу3D-плоскость с краями и углами.
Поскольку решатели ИИ уже готовы, и я недостаточно уверен в своих способностях к написанию ИИ, я решил заставить программу решать куб так, как я это делаю:
Кросс, F2L, OLL и PLL
Загрузите исполняемый файл bin/solver или выполните сборку из исходного кода с помощью make solver
Загрузите или клонируйте файлы из этого репозитория и создайте их с помощью make solver
Загрузите или клонируйте файлы, используя этот репозиторий, и скомпилируйте все файлы .c в src, кроме Solver_library.
Запустите решатель с помощью одной из следующих команд:
./solver "Algorithm"
./solver [Up] [Front] [Right] [Back] [Left] [Down]
Замена алгоритма алгоритмом скремблирования (например, U R2 FBR B2 R U2 L B2 RU' D' R2 FR' L B2 U2 F2
) или гранями с цветами на этой грани (например, wbwowrwgw gwgogrgyg rwrgrbryr bwbrbobyb owobogoyo ygyoyryby
).
Возможные цвета — это первые символы зеленого, красного, синего, оранжевого, белого и желтого.
Если файлы olls.txt и plls.txt находятся не в той же папке, что и двоичный файл, используйте параметры -o и -p или -d, чтобы указать на файлы.
bin/solver -d data/ "U R2 F B R B2 R U2 L B2 R U' D' R2 F R' L B2 U2 F2"
bin/solver -o data/olls.csv -p data/plls.csv "U R2 F B R B2 R U2 L B2 R U' D' R2 F R' L B2 U2 F2"
Добавьте опцию -t
, чтобы печатать только текст без изображений куба.
Загрузите или клонируйте файлы из этого репозитория.
Установите Flask и Numpy с помощью pip.
python3 -m pip -r requirements.txt
Либо используйте команду flask run
, либо python3 app.py
для запуска веб-сервера.
Перейдите по адресу https://127.0.0.1:5000/, чтобы использовать решатель.
Загрузите или клонируйте файлы из этого репозитория.
Удалите версию bin/libcubesolver.so для Linux вручную или с помощью make clean
и перекомпилируйте с помощью make library
.
Установите Flask и Numpy с помощью pip:
python3 -m pip -r requirements.txt
Либо используйте команду flask run
, либо python3 app.py
для запуска веб-сервера.
Перейдите по адресу https://127.0.0.1:5000/, чтобы использовать решатель.
Загрузите или клонируйте файлы из этого репозитория. Удалите версию bin/libcubesolver.so для Linux вручную.
Скомпилируйте все файлы .c в src, за исключением Solver.c, в bin/libcubesolver.so. Или, если вы используете другое имя, измените строку 19 в app.py, чтобы отразить это.
Установите Flask и Numpy с помощью pip:
python3 -m pip -r requirements.txt
Либо используйте команду flask run
, либо python3 app.py
для запуска веб-сервера.
Перейдите по адресу https://127.0.0.1:5000/, чтобы использовать решатель.
Скомпилируйте все файлы в src, за исключениемsolver.c, в libcubesolver.so, libcubesolver.dylib или libcubesolver.dll и сохраните их там, где на вашем компьютере сохранены библиотеки.
В Linux вы можете использовать make library
Скопируйте libcubesolver.h из src туда, где на вашем компьютере сохранены заголовки (например, /usr/include/).
Свяжите его с помощью -lcubesolver
или просто скомпилируйте в приложение, как если бы это был файл .o.
#include
#include
//Use either setup, or both load_olls and load_plls.
//Load all OLLs and PLLs into memory. Path is the folder where the olls.csv and plls.csv file are located.
//Returns indicating for succes or failure.
setup ( path );
//Loads the OLLs from a CSV file. Returns bool indicating success or failure.
load_olls ( filename );
//Loads the PLLs from a CSV file. Returns bool indicating success or failure.
load_plls ( filename );
//Create an array to hold the cube. 6 faces, 9 squares per face.
//The faces in order are Front, Right, Back, Left, Up and Down.
//The "Colors" are saved as the numbers 0 to 5.
int cube [ 6 ][ 9 ];
//Add the "colors" of the cube to the array as 9 character strings containing numbers 0 to 5.
color_cube ( cube , front , right , back , left , up , down );
//Run a multiple move algorithm on the cube, using standard cube notation. (Useful for scrambling)
run_algorithm ( cube , "Algorithm" );
/*
A function that prints the sides of the cube in an exploded fashion. Uses colors when in linux or OS X
Uses Green for 0, Red for 1, Blue for 2, Orange for 3, White for 4, Yellow for 5
WWW
WWW
WWW
OOO GGG RRR BBB
OOO GGG RRR BBB
OOO GGG RRR BBB
YYY
YYY
YYY
*/
print_cube ( cube );
//Validate the colors on the cube for impossible cubies. This does not check if the scramble is solvable.
//Returns bool.
if (! validate ( cube ))
{
return "Invalid color combinaton" ;
}
//returns pointer to string containing all algorithms used to solve the cube, separated by newlines,
//and the names of the steps. (eg. Cross, F2L, OLL: Sune, PLL: Y perm)
//Modifies the array to its solved position
char * solution = solve ( cube );
// Returns:
/*
Cross
(R D' F D)
(y) (R D' F D)
(y) (R D' F D)
(y) (R D' F D)
F2L
(y) R U R' U R U' R') (d' L U L')
(y2) (L' U' L) (y') (U' F' U F) (R' F R F')
(d2 R' U2 R2 U R2 U R)
(y) (U R U R' U2) (d R' U2 R) (U' R B' R' B)
OLL: Kite
(y2) (R U R' U') R' F R2 U R' U' F'
PLL: G perm c
(y2) L' R' U2 L R (y) L U' R U2 L' U R'
*/
//Generates a cube from an algorithm and returns pointer to its solution, or an error if unsolvable.
char * solution2 = solve_scramble ( "scramble" );
//Solves the (yellow) cross.
//Returns a pointer to a string containing the solve algorithm, with each solved edge separated by newlines.
//May also return an error if unsolvable.
//Modifies the cube array to have a solved cross.
char * cross = solve_cross ( cube );
//Solves the first two layers of the cube assuming a solved cross.
//Returns a string containing the solve algorithm, with each solved pair separated by newlines.
//Modifies the cube array to solve its f2l.
//Returns null if the cube is unsolvable.
char * f2l = solve_f2l ( cube );
//Looks up the right OLL algorithm and runs it, assuming a solved F2L.
//Returns the name of the OLL, and the algorithm, separated by a newline.
//Returns null if the cube is unsolvable.
char * oll = solve_oll ( cube );
//Looks up the right PLL algorithm and runs it, assuming a solved OLL.
//Returns the name of the PLL, and the algorithm, separated by a newline.
//Returns null if the cube is unsolvable.
char * pll = solve_pll ( cube );
См. версию C, чтобы узнать, что делает каждая функция.
Поскольку в Python сложно освободить выделенную память, используйте «безопасные» версии функций решения и используйте free_strings() после использования.
import numpy
import ctypes
# Most functions will need a c 2d int array. Let's give it a name so it's easy to use.
array_2d_int = numpy . ctypeslib . ndpointer (
dtype = ctypes . c_int , ndim = 2 , flags = 'CONTIGUOUS' )
# First load the solver library using ctypes CDLL.
solver = ctypes . CDLL ( "/path/to/libcubesolver.so" )
# Then we set up all functions we might want to use.
# Setup, load_olls and load_plls require a string.
solver . setup . argtypes = [ ctypes . c_char_p ]
solver . load_olls . argtypes = [ ctypes . c_char_p ]
solver . load_olls . argtypes = [ ctypes . c_char_p ]
# Run_algorithm requires a 2d array for the cube, and a string.
solver . run_algorithm . argtypes = [ array_2d_int , ctypes . c_char_p ]
# All other functions require just the 2d array.
solver . print_cube . argtypes = [ array_2d_int ]
solver . validate . argtypes = [ array_2d_int ]
solver . solve_safe . argtypes = [ array_2d_int ]
solver . solve_cross_safe . argtypes = [ array_2d_int ]
solver . solve_f2l_safe . argtypes = [ array_2d_int ]
solver . solve_oll_safe . argtypes = [ array_2d_int ]
solver . solve_pll_safe . argtypes = [ array_2d_int ]
# For functions that return something other than an int (or bool) we also need to set the response type.
solver . solve_safe . restype = ctypes . c_char_p
solver . solve_cross_safe . restype = ctypes . c_char_p
solver . solve_f2l_safe . restype = ctypes . c_char_p
solver . solve_oll_safe . restype = ctypes . c_char_p
solver . solve_pll_safe . restype = ctypes . c_char_p
# Load the olls and plls csvs. in my case they're in the data folder.
# Use .encode('utf-8') to convert the python string to a c string.
solver . setup ( "data" . encode ( 'utf-8' ))
# Set up a cube. The inner lists, in order, are Front, Right, Back, Left, Up and Down.
# By default 0 = green, 1 = red, 2 = blue, 3 = orange, 4 = white, 5 = yellow.
solvedcube = [[ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
[ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ],
[ 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 ],
[ 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ],
[ 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 ],
[ 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 ]]
# Turn it into a C 2d array.
cube = numpy . array ( solvedcube ). astype ( ctypes . c_int )
# Run a scramble on the array. Use .encode('utf-8') to change the python string to a c string.
solver . run_algorithm (
cube , "U R2 F B R B2 R U2 L B2 R U' D' R2 F R' L B2 U2 F2" . encode ( 'utf-8' ))
# Print the cube to the shell.
solver . print_cube ( cube )
# Validate the color comibinations on the cube.
if not validate ( cube ):
return "Invalid color combinaton"
# Solve the cube using solver.solve.
# Note: running the function also modifies the cube array.
solution = solver . solve_safe ( cube ). decode ( "utf-8" )
# Returns:
"""
Cross
(R D' F D)
(y) (R D' F D)
(y) (R D' F D)
(y) (R D' F D)
F2L
(y) R U R' U R U' R') (d' L U L')
(y2) (L' U' L) (y') (U' F' U F) (R' F R F')
(d2 R' U2 R2 U R2 U R)
(y) (U R U R' U2) (d R' U2 R) (U' R B' R' B)
OLL: Kite
(y2) (R U R' U') R' F R2 U R' U' F'
PLL: G perm c
(y2) L' R' U2 L R (y) L U' R U2 L' U R'
"""
# Or returns an error if the cube is unsolvable.
# You can also do the steps separately.
# solve the cross.
cross = solver . solve_cross_safe ( cube ). decode ( "utf-8" )
# returns
'''
(R D' F D)
(y) (R D' F D)
(y) (R D' F D)
(y) (R D' F D)
'''
# solve the F2L.
f2l = solver . solve_f2l_safe ( cube ). decode ( "utf-8" )
# returns
'''
(y) R U R' U R U' R') (d' L U L')
(y2) (L' U' L) (y') (U' F' U F) (R' F R F')
(d2 R' U2 R2 U R2 U R)
(y) (U R U R' U2) (d R' U2 R) (U' R B' R' B)
'''
# solve the OLL.
oll = solver . solve_oll_safe ( cube ). decode ( "utf-8" )
# returns
'''
Kite
(y2) (R U R' U') R' F R2 U R' U' F'
'''
# solve the PLL.
pll = solver . solve_pll_safe ( cube ). decode ( "utf-8" )
# returns
'''
G perm c
(y2) L' R' U2 L R (y) L U' R U2 L' U R'
'''
# If a step is already solved, the functions return an empty string.
# With an unsolvable cube, these functions return NULL, which causes an
# AttributeError when trying to decode. You may want to verify before decoding. (or use try)
# Clean up the memory for the solution strings.
solver . free_strings ()
# Finally clean up the loaded OLLs or PLLs to prevent memory leaks
solver . cleanup_last_layer ()
CS50 хочет, чтобы я объяснил, что делает каждый файл и что в нем находится. Таким образом, этот файл readme длиннее всех моих файлов, кроме трех.
├── app.py ├── мусорное ведро │ ├── libcubesolver.so │ └── решатель ├── данные │ ├── error.txt │ ├── olls.csv │ ├── шаблоны.csv │ └── plls.csv ├── make-файл ├── README.md ├── требования.txt ├── источник │ ├── крест.c │ ├── крест.h │ ├── куб.с │ ├── куб.h │ ├── Cubesolver.h │ ├── f2l.c │ ├── f2l.h │ ├── Lastlayer.c │ ├── последний слой.h │ ├── Solver.c │ ├──solver_library.c │ ├── utils.c │ └── utils.h ├── тест │ ├── randtests.c │ └── случайные тесты ├── статический │ ├── куб.css │ ├── Cube.js │ ├── Cubeinterface.js │ ├── favicon.ico │ ├── next.png │ ├── пауза.png │ ├── play.png │ └── пред.png ├── шаблоны │ ├── Cube.html │ └── Solver.html
Cube.c и Cube.h содержат в памяти весь код, управляющий кубиком Рубика.
Кубик Рубика в памяти представляет собой двумерный массив размером 6 на 9. Внешний массив содержит шесть граней: спереди, справа, сзади, слева, вверх и вниз.
Я выбрал этот порядок, потому что верхняя и нижняя грани всегда одинаковы, поэтому я могу их жестко запрограммировать, но стороны должны быть правильными только по отношению друг к другу. Это означает, что я могу использовать простой плюс или минус в сочетании с модулем для перевода тестов и перемещений во все стороны. То же самое относится и к цветам, которые сохраняются под номерами от 0 до 5, где 0 — цвет переднего плана, 1 — правый и т. д.
Сначала я выбрал порядок цветов, который использую: красный спереди, желтый сверху, зеленый справа. Но позже, когда я писал код и интерфейс Python, я переключился на «Официальный» зеленый цвет спереди и белый сверху, поэтому мне не нужно поворачивать введенный пользователем куб, чтобы внизу был белый цвет.
Сначала я создал функцию color_cube(). Это применит к кубу выбранный вами шаблон с использованием 6 строк.
Он использует простую математику символов для изменения символов «0», «1» и т. д. на целые числа и сохраняет их в заданном массиве.
Я использую это только один или два раза в качестве одной строки для настройки решенного куба в одну строку, потому что при переводе пользовательского ввода во что-то, что понимает компьютер, вы можете также вводить целые числа по отдельности, а не сначала переводить их в строку.
Print_cube() выводит предоставленный куб на терминал. Это часто используется при отладке и для терминального приложения. Я начал с вывода чисел от 0 до 5 в форме взорванного кубика Рубика.
444
444
444
333 000 111 222
333 000 111 222
333 000 111 222
555
555
555
Поскольку для автоматизации этого процесса потребуется больше строк кода, я просто использую 9 операторов печати, каждый из которых содержит до 12 переменных.
Позже я узнал, что можно добавить шелл-коды типа e[42m
чтобы придать этим числам цвет фона. Их добавление дало мне 28 переменных на печать.
Наконец я подумал о том, чтобы просто поместить букву или цифру цвета в массив, содержащий шелл-коды, и вернуть его обратно к 12. К сожалению, Windows не поддерживает этот тип шелл-кодов, поэтому мне пришлось продолжать использовать только цифры и более поздние письма.
Move_cube() — первая функция для фактического изменения куба. Это рекурсивная функция, которая выполняет запрошенное перемещение заданное количество раз. Существует 9 возможных ходов, пронумерованных от 0 до 8. По умолчанию вперед, вправо, назад и т. д. А также средний слой, экватор и стоячий слой. Используя вспомогательную функцию Cycle, которую я написал в utils.c, я переключаю значения каждого квадрата на каждой грани, соответствующие движению по часовой стрелке, повторяя при необходимости.
Поскольку ходы обычно не происходят сами по себе, я написал run_algorithm(). Эта функция использует move_cube() для запуска алгоритма на кубе, предоставленном в стандартной нотации куба. Это дает мне возможность выполнять несколько ходов одновременно (или даже по порядку) и делать ходы, которые влияют на 2 или даже 3 слоя, например x, y и z.
Наконец, проверьте(). Я добавил эту функцию при написании интерфейса Python, потому что вы никогда не должны доверять своему пользователю, чтобы он не вводил странные вещи.
Эта функция не проверяет, разрешим ли кубик Рубика. Он проверяет правильность цветов. Например, на одном кубике не может быть одновременно белых и желтых наклеек. И, двигаясь по часовой стрелке, можно располагать зеленые, белые и красные наклейки именно в таком порядке, но не наоборот.
Чтобы сделать это, я частично скопировал идею заблокированного массива в Tideman, используя 2D логический массив для углов и 3D логический массив для краев, чтобы увидеть, возможна ли комбинация 2 или 3 цветов. Этот код прошел несколько итераций. Сначала проверяйте каждый край и угол отдельно, а затем используйте несколько циклов for.
Cross.c содержит весь код, необходимый для решения креста куба. Поскольку для решения куба я использую «человеческий метод» (CFOP), я вынужден использовать огромные деревья решений.
Я переписал почти весь этот файл в последнюю минуту, чтобы не приходилось выравнивать края на каждом этапе.
Находит место на нижнем слое, где находится желто-зеленый край, или где он мог бы быть, если бы его еще не было. Это упрощает выравнивание других краев за меньшее количество шагов, поскольку они могут выравниваться по «относительному нулю», а не по фактическому нулю.
Эти 6 случаев обозначают все способы ориентации края: направление вниз, направление вверх, указание в верхних и нижних слоях, указание влево и указание вправо на слое E.
Функции в основном сканируют грани в порядке от 0 до 3, чтобы найти части, принадлежащие кресту, поворачивают их на место и сохраняют ходы в массиве символов с помощью вспомогательной функции, которую я вызываю add().
Solve_cross сначала ориентирует куб так, чтобы желтый был внизу. Затем он выполняет 6 перекрестных случаев по порядку. Если кто-то возвращает что-то отличное от нуля, он возвращается к первому случаю.
Как только все 4 ребра решены, функция возвращает алгоритмы. Если все случаи проверены безуспешно или после 4 циклов, функция возвращает NULL.
Та же идея, что и у Cross.c, только размер намного больше. 3600 строк кода для решения всех случаев.
Эти 11 случаев включают в себя все способы ориентации угла и некоторые комбинации углов и краев.
Чтобы сэкономить время и линии, большинство функций не решают полностью комбинацию угла/края, а приводят их к кратчайшему известному состоянию и вызывают правильную функцию.
Числа от 1 до 11 — это порядок, в котором они были написаны, а не всегда порядок, в котором они выполняются.
Solve_f2l сначала проверяет, решен ли крест. Если нет, он возвращает ноль.
После этогоsolve_f2l перебирает случаи в порядке от кратчайшего среднего алгоритма к самому длинному, возвращаясь к 1, как только функция возвращает алгоритм. Если все случаи проверены безуспешно или после 4 циклов, функция возвращает NULL.
Файл, которым я горжусь больше всего. Никаких гигантских циклов и деревьев решений. Просто умная математика и таблицы поиска.
Oll и pll — это две структуры, предназначенные для хранения OLL и PLL. Они хранят имя, шаблон, который я использую для их распознавания, и алгоритм их решения.
Бессонной ночью я понял, что могу распознать PLL, используя только цвета внешнего кольца, а OLL всего лишь по 12 логическим значениям, означающим желтый или не желтый.
Load_olls() и load_plls() загружают имена, шаблоны и алгоритмы из файла CSV. Это прошло несколько итераций.
Сначала я начал с getline(), чтобы получить каждую строку CSV-файлов, и разбил строку на 24 символа и 36 символов, дополнив имя пробелами.
Это было некрасиво, поэтому я начал искать запятые и разделять их.
Наконец кто-то из участников Discord направил меня к sscanf(), позволяющему легко и аккуратно разделить каждую строку.
Я также переключился на fgets(), чтобы сделать строку более перекрестно-совместимой.
Строки, начинающиеся с #, отклоняются, поскольку они являются комментариями. Строки, в которых шаблон не является чисто числовым, распознаются с помощью вспомогательной функции isNumber() или isBinary() и отклоняются. При написании этого раздела я добавил тест, чтобы проверить, имеют ли имя, шаблон и алгоритм правильную длину. остановить вне границ чтения и записи.
В массивах olls и plls пространство для имен и алгоритмов создается с помощью malloc, а информация копируется с помощью strncpy. Шаблон преобразуется в массив из 12 целых или логических значений.
Find_pll() — моя гордость и радость. Это был первый алгоритм, который я написал для решения куба (до креста и f2l), и он пришел ко мне во сне. Способ проверить узор Олла на наличие любой цветовой комбинации с помощью простых математических вычислений. Я буквально проснулся и записал int case[12] containing the outer ring. if (front[0] == (front[1]-(case[0]-case[1])%4))
. На следующий день я упростил его до (faces[0][0] == (faces[0][1] - (plls[i].pattern[0] - plls[i].pattern[1])) % 4)
(раз 12). Затем (faces[j][0] - faces[j][1]) % 4 == (plls[i].pattern[0] - plls[i].pattern[1]) % 4
и, наконец, после многих итераций В итоге я получил mod((cube[(j + i / 3) % 4][i % 3] + dif[j]), 4)
позволяющий мне кодировать шаблон верхнего слоя куба с помощью 12 int для удобства сравнения со всеми известными значениями.
Я мог бы закодировать шаблон как 4-байтовое целое число, но решил не делать этого, потому что считаю, что лучше сделать шаблоны простыми для понимания, чем экономить 44 байта (всего 3408 КБ для шаблонов).
Наконец, функция возвращает значение пары_int_int, содержащее ориентацию слоя и правильный OLL или PLL. Или два отрицательных числа, если ничего не найдено.
Функцииsolve_oll() иsolve_pll() относительно просты. Они вызывают find_oll или pll, чтобы получить правильный индекс и ориентацию (количество ходов y). Затем функция поворачивает куб, используя перемещение по оси y, запускает правильный алгоритм OLL или PLL, а в случаеsolve_pll() поворачивает слой U, чтобы окончательно решить куб. Функции возвращают алгоритм, используемый для решения куба в стандартной нотации куба.
Освобождает память, используемую для хранения всех OLL и PLL.
Некоторые функции, которые сделают мою жизнь немного проще.
Поскольку обычный % не работает с отрицательными числами, это «моя собственная версия». Особая благодарность дискорду cs50.
Для некоторых функций я хочу возвращать более одной переменной. Этот основан на паре C++
Функция, которая циклически обрабатывает 4 числа. По сути, это шаг вперед по сравнению со свопом. Используется в Cube.c для циклического перемещения ребер и углов при перемещении куба. Копия этого хода есть в Cube.js.
Функция, которая добавляет строку к другой строке, перераспределяя при необходимости. Используется повсюду в этом приложении.
Проверяет, содержит ли строка только цифры или только нули и единицы. В настоящее время используется только для загрузки OLL и PLL.
Сначала я написал Solver.c как интерфейс для своего решателя кубов, но быстро решил, что мне нужен графический интерфейс, который я не готов делать на чистом C.
Вот почему я начал превращать свои кубические решатели в библиотеку, которую можно использовать со всем, что захочу.
Собирает все это вместе, чтобы собрать куб. Он берет куб и проверяет его. Затем пытается решить крест. Если это не удается, он возвращает ошибку, в противном случае он сохраняет выходные данные. Затем он решает крест или возвращает ошибку. Затем он решает OLL (или возвращает) и PLL. Наконец, он возвращает строку, содержащую полное решение.
Интерфейс для решения. Генерирует куб из введенной скремблировки и передает его в функциюsolve().
Просто чтобы облегчить всем жизнь. Берет путь и загружает olls и plls с этого пути. Возвращает true, если работает, очищает после себя и возвращает false, если нет.
Поскольку освободить память из Python сложно, я решил сделать это из C. У меня есть «безопасные» версии каждой функции, которую вы, возможно, захотите использовать вне C. Они хранят сгенерированные указатели, которые необходимо освободить, в глобальный массив. за освобождение всех сразу.
Освободить все сохраненные строки
Несколько функций возвращают строки, которые в конце необходимо освободить. Эти функции сохраняют указатели на эти строки для последующего удаления.
Для тестирования и тех, кто лучше владеет клавиатурой, чем мышью, предусмотрен терминальный интерфейс.
Его неоднократно переписывали, и, наконец, во время написания этого файла readme его переписали для работы с Solver_library, а не отдельно.
Он делает все! Он загружает OLL и PLL на основе ввода по умолчанию или пользовательского ввода. Затем он генерирует куб на основе командной строки или пользовательского ввода и, наконец, шаг за шагом решает куб, попутно печатая куб.
Получает каталог по заданному пути к файлу (например, argv[0]). Написан для работы как с операционными системами Windows, так и с Unix.
Изменяет цветную букву на соответствующую int. В Python я просто использовал словарь. Намного проще.
Задайте пользователю девять цветов грани кубика Рубика и наложите их на кубик.
Пошаговый интерактивный интерфейс для ввода цветов в куб.
Распечатывает справочный тест.
Распечатывает использование.
Простое короткое приложение для тестирования ошибок. Создает множество схваток и решает их. Печатает первую шифровку, которая терпит неудачу и останавливается.
Я использовал это, чтобы найти одну-единственную опечатку. Все остальное я делал вручную.
Использует memcmp для сравнения куба, полученного алгоритмом решения, с одним из 4 решенных кубов (по одному на каждую ориентацию).
Обменяет немного памяти на скорость.
Генерирует случайные схватки за кубик Рубика. Плохо. Не защищает от двойного перемещения и обратного хода. Но хорошо, если схватка будет достаточно продолжительной.
Загружает OLL и PLL из пользовательского ввода. Решает куб столько раз, сколько хочет пользователь, пока не произойдет сбой.
Содержит список всех 58 случаев OLL (включая решенные) для использования с моей библиотекой C.
Алгоритмы из моей памяти и из https://www.speedsolve.com/wiki/index.php/OLL.
Содержит список всех 22 случаев PLL (включая решенные) для использования с моей библиотекой C.
Алгоритмы из моей памяти и https://www.speedsolve.com/wiki/index.php/PLL.
Содержит несколько шаблонов для красивого шифрования куба. В основном используется для тестирования моего JavaScript, но является приятной функцией для пользователя.
Надеемся, что он ничего не содержит, но предназначен для хранения всех ошибок при решении куба.
Мост между моим кодом C и JavaScript. Он загружает библиотеку C и инициализирует нужную мне функцию с помощью типов аргументов и, при необходимости, перепечатывает. Использование numpy для преобразования типов Python в типы ctypes.
Функция, которую я «позаимствовал» у stackoverflow. Он принимает входной поток и выводит каждую строку до #
Настоящий решатель. Он берет зашифрованный куб и решает его шаг за шагом, возвращая шаги в виде массива словарей (содержащего массив с алгоритмами). В случае исключений шаблон сохраняется в data/errors.txt.
Использовался только для тестирования. Берет алгоритм шифрования из GET, решает его с помощью getsteps() и передает в шаблон решателя.
Берет шаблон и шифрует его из GET или POST, решает его с помощью getsteps и возвращает в формате JSON.
Берет шаблон из GET или POST и решает куб, не заботясь о фактическом решении, но проверяя, где оно дает сбой. Возвращает 0 в случае успеха или номер ошибки.
Показывает шаблон Cube.html: фактический пользовательский интерфейс. При этом он также берет шаблоны из data/patterns.csv для передачи в шаблон, используя диктофон и декомментацию для удаления моих комментариев.
Передает значок браузеру для красивого символа куба.
Освобождает всю память из моего кода на C: PLL и строки. Зарегистрировано с помощью atexit для запуска при выходе
Все команды для компиляции моего кода C в Linux или OS X. Несмотря на то, что мою библиотеку можно использовать как библиотеку, я решил использовать для компиляции все файлы, чтобы можно было просто предоставить один исполняемый файл.
Содержит две использованные мной библиотеки, которые необходимо устанавливать отдельно. Просто колба и numpy. Ничего особенного.
Запрашивает шифрование, передает его в app.py для решения и печатает решение. Используется только для быстрого тестирования.
Содержит множество пустых элементов div, которые должны быть заполнены моим кодом JavaScript и сформированы с помощью CSS. Содержит 3 изображения для элементов управления воспроизведением, форму для ввода скремблирования и краткое пояснение.
Наконец загружает javascript, потому что без dom это ничто. Не так красиво, но очень функционально.
За исключением src содержит самый актуальный код. Немного CSS, чтобы все выглядело удобным, и JavaScript, чтобы его действительно можно было использовать. И несколько изображений, на которые можно нажать.
Изменяет ссылку случайных элементов div на то, что вы можете видеть.
Использует сетки CSS по умолчанию и реже по умолчанию.
Я использую внешний контейнер для размещения элементов управления слева, анимации решателя вверху справа и решения внизу справа.
Используя абсолютное позиционирование, я поместил элементы управления воспроизведением и текущий алгоритм поверх анимации.
Все остальное по умолчанию, за исключением выбора цвета. Если вы посмотрите на html-код, вы увидите просто div, содержащий 6 div, каждый из которых содержит 9 div. Используя сетки, я формирую 6 элементов div с «гранями», чтобы они выглядели как развернутый куб, каждая грань содержит сетку из 9 квадратов. Это позволяет мне сделать размер переменным, сохраняя при этом форму неизменной, без необходимости использовать изображения.
Я также потратил неделю или две на создание мобильной версии, потому что текст, казалось, имел переменный размер. Я связался с Discord, Facebook и даже stackoverflow. Наконец я нашел строку html в stackoverflow: которая решила все в одной строке.
Доносит мой алгоритм до пользователя. На основе Three.js
Я впервые пишу JavaScript. Это выглядит некрасиво и, возможно, нарушает все правила, но работает.
Я переписывал этот файл несколько раз. Сначала итеративный, это было до того, как я начал загружать на github, затем функциональный и, наконец, своего рода объектно-ориентированный.
Сначала я объявляю все переменные, которые должны использоваться более чем одной функцией: материалы и геометрия для объектов Three.js, массивы для хранения объектов, оси вращения и многое другое.
Существует также гигантский словарь, содержащий необходимые переменные для каждого допустимого перемещения куба: кубы, которые нужно перемещать или менять местами, ось и градусы вращения, а также то, что показывать. Все это могло бы уместиться в 72 строки, но style50 требует одну переменную в каждой строке, что делает его 649 строк.
Берет сцену и сохраняет ссылку, генерирует кубы, контуры и плоскости в цикле, устанавливает позиции кубов и контуров в цикле и плоскости вручную.
Вспомогательная функция. Циклически вращает 4 куба a > b > c > d > a, используя временный куб.
Вспомогательная функция. Меняет местами вращение 2 кубов, используя временный куб.
Сбросьте кубы в положение по умолчанию и сбросьте div решения. Для этого нужно больше шагов, чем вы думаете. Сначала нам нужно сбросить всю анимацию, закончить ее. Сбросьте все будущие и прошлые ходы и, наконец, сбросьте вращение кубиков.
Возвращает true или false в зависимости от того, движется ли куб.
Устанавливает анимацию перемещения по кубу.
Первоначально эта функция состояла из 160 строк операторов if/else, но позже я переписал ее, чтобы получить кубы и ходы из гигантского словаря. Это облегчает чтение этой и следующей функции, и если я напишу версию 4x4 или 5x5, мне нужно будет только изменить словарь.
Завершает анимацию и фактически перемещает (вращает) кубики.
Поскольку кубы на самом деле не движутся, основная идея состоит в том, чтобы скопировать вращение куба, который в реальном кубе переместился бы на свое место, а затем повернуть все.
Первоначально эта функция представляла собой чудовищное 375-строчное чудовище, состоящее из следующих операторов if/else. Позже он был переписан для работы со словарем ходов.
Выполняет следующий ход в списке ходов или следующий алгоритм в списке шагов и отображает текущий алгоритм на экране.
Предыдущий ход в списке перемещается в обратном направлении или предыдущий алгоритм в списке шагов?
Применяет цвета из палитры цветов (или фактически массива граней) к кубу, вращая каждый куб. Содержит некоторые свои функции. Каждый куб имеет свою собственную строку с ручными модификаторами. Для меня это слишком случайно, чтобы автоматизировать. Но если хочешь попробовать, будь моим гостем.
Меняет зеленый цвет на синий, красный на оранжевый, белый на желтый и наоборот. Теперь я думаю об этом, это мог бы быть диктат, но одна математическая строка и три «если» тоже работают.
Вращает куб на основе переднего и левого цвета или верхнего цвета. В основном много операторов if с жестко запрограммированными ходами, но здесь этого достаточно.