CS50 の最後のプロジェクトは、「Human Method」ルービック キューブ ソルバーです。
これは、入力されたルービック キューブが、クロス、F2L、OLL、PLL という明確なステップを備えた、人間が使用できる方法 (CFOP) を使用して解決されることを意味します。
最終的な製品は、シェル アプリケーション、他のプロジェクトで使用するための C ライブラリ、および Flask、HTML、CSS、JavaScript で記述された Web インターフェイスで構成されます。
私がルービック キューブ ソルバーを作成することにしたのは、以前に C++ で数独ソルバーを作成したことがあり、キューブはステップアップだったためです。
2D 平面の代わりに、エッジとコーナーのある半 3D 平面を作成します。
AI ソルバーは既に完成しており、私は自分の AI 記述能力に十分な自信がないため、私が行っている方法でプログラムに立方体を解決させることにしました。
クロス、F2L、OLL、PLL
bin/solver 実行可能ファイルをダウンロードするか、 make solver
を使用してソースからビルドします
このリポジトリからファイルをダウンロードまたはクローンし、 make solver
使用してビルドします。
このリポジトリを使用してファイルをダウンロードまたはクローンし、src 内のsolver_library を除くすべての .c ファイルをコンパイルします。
次のコマンドのいずれかを使用してソルバーを実行します。
./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
を追加します。
このリポジトリからファイルをダウンロードまたは複製します。
pip を使用して Flask と Numpy をインストールします。
python3 -m pip -r requirements.txt
コマンドflask run
またはpython3 app.py
を使用して Web サーバーを実行します。
ソルバーを使用するには、https://127.0.0.1:5000/ に移動します。
このリポジトリからファイルをダウンロードまたは複製します。
Linux バージョンの bin/libcubesolver.so を手動で削除するか、 make clean
使用して削除し、 make library
を使用して再コンパイルします。
pip を使用して Flask と Numpy をインストールします。
python3 -m pip -r requirements.txt
コマンドflask run
またはpython3 app.py
を使用して Web サーバーを実行します。
ソルバーを使用するには、https://127.0.0.1:5000/ に移動します。
このリポジトリからファイルをダウンロードまたは複製します。 Linux バージョンの bin/libcubesolver.so を手動で削除します。
solver.c を除く src 内のすべての .c ファイルを bin/libcubesolver.so にコンパイルします。または、別の名前を使用する場合は、app.py の 19 行目を変更してそれを反映させます。
pip を使用して Flask と Numpy をインストールします。
python3 -m pip -r requirements.txt
コマンドflask run
またはpython3 app.py
を使用して Web サーバーを実行します。
ソルバーを使用するには、https://127.0.0.1:5000/ に移動します。
src 内のsolver.c を除くすべてのファイルを libcubesolver.so、libcubesolver.dylib、または libcubesolver.dll にコンパイルし、PC 上のライブラリが保存されている場所に保存します。
Linuxではmake library
を使用できます
libcubesolver.h を src から PC 上のヘッダーが保存されている場所 (例: /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 は、私のファイルのうち 3 つを除くすべてのファイルよりも長くなっています。
§── app.py §── ビン │ §── libcubesolver.so │ └── ソルバー §── データ │ §──errors.txt │ §── olls.csv │ §── パターン.csv │ └── plls.csv §── メイクファイル §── README.md §── 要件.txt §── ソース │ §── クロス.c │ §──cross.h │ §── cube.c │ §── cube.h │ §── cubesolver.h │ §── f2l.c │ §── f2l.h │ §── lastlayer.c │ §── lastlayer.h │ §──solver.c │ §──solver_library.c │ §── utils.c │ └── utils.h §── テスト │ §──randomtests.c │ └── ランダムテスト §── 静的 │ §── cube.css │ §── cube.js │ §── cubeinterface.js │ §── favicon.ico │ §── 次へ.png │ §── 一時停止.png │ §── play.png │ └── 前のpng §── テンプレート │ §── cube.html │ └──solver.html
Cube.c と cube.h には、メモリ内のルービック キューブを制御するすべてのコードが含まれています。
メモリ内のルービック キューブは 6 × 9 の 2 次元配列です。外側の配列には、Front、Right、Back、Left、Up、Down の 6 つの面が含まれています。
この順序を選択したのは、上面と下面が常に同じであるため、ハードコード化できますが、側面は相互の関係だけが正しい必要があるためです。これは、単純なプラスまたはマイナスをモジュラスと組み合わせて使用して、テストを変換し、あらゆる面に移動できることを意味します。色も同様で、0 ~ 5 の番号として保存されます。0 は前面の色、1 は右側などです。
まず、使用する色の順序を選択しました。前が赤、上が黄色、右が緑です。しかし、後で Python コードとインターフェイスを作成するときに、前面が「公式」の緑色、上が白に切り替えたので、ユーザーが入力した立方体を回転させて下が白になる必要はありません。
最初に color_cube() 関数を作成しました。これは、6 つの文字列を使用して、選択したパターンを立方体に適用します。
単純な char 計算を使用して、char '0'、'1' などを int に変更し、指定された配列に格納します。
これは、解決されたキューブを 1 行で設定するためのワンライナーとして 1 回か 2 回だけ使用します。これは、ユーザー入力をコンピューターが理解できるものに変換するときに、最初に文字列に変換するのではなく、int を個別に入力した方がよいためです。
Print_cube() は、指定されたキューブを端末に出力します。これは、デバッグ時やターミナル アプリケーションでよく使用されます。まず、分解したルービック キューブの形で 0 ~ 5 の数字だけを出力しました。
444
444
444
333 000 111 222
333 000 111 222
333 000 111 222
555
555
555
これを自動化するとさらに多くのコード行が必要になるため、それぞれ最大 12 個の変数を含む 9 つの print ステートメントを使用するだけです。
後で、 e[42m
のようなシェル コードを追加して、これらの数字に背景色を与えることができることがわかりました。これらを追加すると、印刷ごとに 28 個の変数が得られました。
最後に、シェル コードを保持する配列に色の文字または数字を単純に入れて 12 に戻すことを考えました。残念ながら、Windows はこのタイプのシェル コードをサポートしていないため、数字だけを使用し続ける必要がありました。後の手紙。
Move_cube() は、実際にキューブを変更するための最初の関数です。これは、要求された移動を要求された回数だけ実行する再帰関数です。実行可能な移動は 9 つあり、0 ~ 8 の番号が付けられています。デフォルトは前、右、後などですが、中央、赤道、立っているレイヤーも含まれます。 utils.c で作成した Cycle というヘルパー関数を使用して、時計回りの移動に対応する各面の各正方形の値を切り替え、必要に応じて繰り返します。
通常、移動は自動的に行われないため、次に run_algorithm() を書きました。この関数は、move_cube() を使用して、標準のキューブ表記で提供されるキューブに対してアルゴリズムを実行します。これにより、複数の動きを一度に (または実際には順番に) 実行したり、x、y、z などの 2 つまたは 3 つのレイヤーに影響を与える動きを実行したりできるようになります。
最後に validate() を行います。ユーザーが奇妙なものを入力しないことを決して信頼してはいけないため、Python インターフェイスを作成するときにこの関数を追加しました。
この関数は、ルービック キューブが解けるかどうかをチェックしません。色が正しいかどうかをチェックします。たとえば、1 つのキュービーに白と黄色の両方のステッカーを付けることはできません。時計回りに緑、白、赤のステッカーをこの順序で配置することは可能ですが、その逆はできません。
これを行うために、私は Tideman のロックされた配列のアイデアを部分的にコピーし、コーナーに 2D ブール配列を使用し、エッジに 3D ブール配列を使用して、2 色または 3 色の組み合わせが可能かどうかを確認しました。このコードは複数回反復されました。最初に各エッジとコーナーを個別にチェックし、その後、いくつかの for ループを使用します。
Cross.c には、立方体の十字を解くために必要なすべてのコードが含まれています。私は立方体を解くために「ヒューマンメソッド」(CFOP) を使用しているため、巨大な決定木を使用する必要があります。
直前にこのファイルのほぼ全体を書き直したので、各ステップで端を揃える必要はありません。
最下位レイヤーのどこに黄緑色のエッジがあるか、またはまだ存在しない場合はそのエッジが存在する場所を見つけます。これにより、他のエッジを実際のゼロではなく「相対ゼロ」に揃えることができるため、より少ないステップで簡単に揃えることができます。
これら 6 つのケースは、下向き、上向き、上下のレイヤーでの向き、E レイヤーでの左向きと右向きなど、エッジの方向を指定できるあらゆる方法です。
これらの関数は基本的に 0 から 3 の順に面をスキャンして、十字に属する駒を探し、それらを所定の位置に回転させ、append() と呼ぶヘルパー関数を使用して動きを char 配列に保存します。
Solve_cross は、まず黄色が下になるように立方体の向きを変えます。次に、6 つのクロスケースを順番に実行します。 null 以外を返した場合は、最初のケースに戻ります。
4 つのエッジがすべて解決されると、関数はアルゴリズムを返します。すべてのケースのテストが成功しなかった場合、または 4 回のループの後、関数は NULL を返します。
はるかに大きいことを除いて、cross.c と同じアイデアです。すべてのケースを解決するには 3600 行のコード。
これらの 11 のケースは、角を方向付けることができるあらゆる方法と、角とエッジのいくつかの組み合わせで構成されています。
時間と行数を節約するために、ほとんどの関数はコーナー/エッジの組み合わせを完全には解決しませんが、既知の最短の状態にして正しい関数を呼び出します。
1 から 11 までの数字は書かれた順序であり、必ずしも実行される順序ではありません。
Solve_f2l は、まずクロスが解決されたことを確認します。そうでない場合は null を返します。
その後、solve_f2l は平均アルゴリズムが最短のものから最長のものまでの順にケースを調べ、関数がアルゴリズムを返したら 1 に戻ります。すべてのケースがテストされても成功しない場合、または 4 回のループの後、関数は NULL を返します。
私が最も誇りに思っているファイルです。巨大なループやデシジョン ツリーはありません。スマートな計算とルックアップテーブルだけです。
Oll と pll は、OLL と PLL を格納するための 2 つの構造体です。これらには、名前、それらを認識するために使用するパターン、およびそれらを解決するためのアルゴリズムが保存されています。
眠れない夜に、私は外側のリングの色だけを使用して PLL を認識でき、OLL は黄色か黄色ではないかを意味する 12 個のブール値だけで認識できることに気づきました。
Load_olls() およびload_plls() は、CSV ファイルから名前、パターン、アルゴリズムをロードします。これは何度か繰り返しました。
まず getline() で CSV ファイルの各行を取得し、文字列を 24 文字と 36 文字で分割し、名前にスペースを埋め込みました。
これはあまり美しくないので、カンマを探してそこで分割することにしました。
最後に、Discord の誰かが私に sscanf() を教えてくれて、各文字列を簡単にきれいに分割できるようにしました。
また、行の取得の相互互換性を高めるために fgets() に切り替えました。
# で始まる行はコメントであるため拒否されます。パターンが純粋な数値ではない行は、isNumber() または isBinary() というヘルパー関数を使用して認識され、拒否されます。このセクションを書いているときに、名前、パターン、アルゴリズムが適切な長さであるかどうかを確認するテストを追加しました。境界外の読み取りと書き込みを停止します。
olls および plls 配列では、名前とアルゴリズム用のスペースが malloc を使用して作成され、情報は strncpy を使用してコピーされます。パターンは 12 個の int または boolean の配列に変換されます。
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 バイトの int としてエンコードすることもできましたが、44 バイト (パターンの合計 3408 kb) を節約するよりも、パターンを理解しやすくする方が良いと考えたため、エンコードしないことにしました。
最後に、この関数は、レイヤーの向きと正しい OLL または PLL を含む par_int_int を返します。または、何も見つからない場合は 2 つの負の数。
関数solve_oll()およびsolve_pll()は比較的単純です。 find_oll または pll を呼び出して、正しいインデックスと方向 (y の移動量) を取得します。次に、関数は y 移動を使用して立方体を回転させ、適切な OLL または PLL アルゴリズムを実行します。さらに、solve_pll() の場合は、U 層を回転させて最終的に立方体を解きます。これらの関数は、標準の立方体表記法で立方体を解くために使用されるアルゴリズムを返します。
すべての OLL および PLL の保存に使用されているメモリを解放します。
私の生活を少し楽にするいくつかの機能。
通常の % は負の数値では機能しないため、これは「私独自のバージョン」で機能します。 cs50 discord に特に感謝します。
一部の関数では、複数の変数を返したいと考えています。これは、C++ のペア
4 つの数値を循環させる関数。基本的にはスワップからのステップアップです。 cube.c でキューブの移動のエッジとコーナーを循環させるために使用されます。その動きのコピーが cube.js にあります
文字列を別の文字列に追加し、必要に応じて再割り当てする関数。このアプリケーションのあらゆる場所で使用されます。
文字列に数字のみが含まれているか、0 と 1 のみが含まれているかを確認します。現在、OLL および PLL のロードにのみ使用されます。
私は最初、キューブ ソルバーのインターフェイスとしてsolver.c を作成しましたが、すぐにグラフィカル UI が必要だと判断しました。これを純粋な C で行う準備はできていません。
だからこそ、私はキューブソルバーをライブラリにして、必要なものすべてに使用できるようにし始めました。
すべてを組み合わせて立方体を解きます。キューブを取得して検証します。次に、クロスを解決しようとします。失敗した場合はエラーが返され、失敗した場合は出力が保存されます。その後、クロスを解決するか、エラーを返します。次に、OLL (またはリターン) と PLL を解決します。最後に、完全なソリューションを含む文字列を返します。
解決するためのインターフェイス。入力されたスクランブルからキューブを生成し、solve() に渡します。
みんなの生活を少しでも楽にするためです。パスを取得し、そのパスから ol と pll をロードします。機能する場合は true を返し、それ自体の後をクリーンアップし、機能しない場合は false を返します。
Python からメモリを解放するのは難しいため、C から行うことにしました。C の外部から使用する可能性のあるすべての関数の「安全な」バージョンが用意されています。これらには、グローバル配列に解放する必要がある生成されたポインタが保存されます。一気に解放するため。
保存されているすべての文字列を解放する
複数の関数は文字列を返しますが、最終的には解放する必要があります。これらの関数は、後で削除できるようにこれらの文字列へのポインターを保存します。
テスト用、およびマウスよりもキーボードの方が得意な場合は、ターミナル インターフェイスを使用します。
何度も書き直され、最終的にはこの Readme を書いているときに、単独ではなくsolver_library で動作するように書き直されました。
それはすべてを行います!デフォルトまたはユーザー入力に基づいて OLL と PLL をロードします。次に、コマンド ラインまたはユーザー入力に基づいてキューブを生成し、最後にキューブを段階的に解決し、途中でキューブを出力します。
指定されたファイルパス (例: argv[0]) からディレクトリを取得します。 Windows ベースと Unix ベースの OS の両方で動作するように書かれています。
カラー文字を対応する int に変更します。 Pythonでは辞書を使っただけです。ずっと簡単です。
ルービックキューブの面の9つの色をユーザーに尋ね、それをキューブに配置します。
立方体に色を入力するためのステップバイステップのインタラクティブなインターフェイス。
ヘルプテストを出力します。
使用状況を出力します。
バグテストのためのシンプルな短いアプリケーション。多くのスクランブルを生成し、解決します。失敗して停止した最初のスクランブルを出力します。
これを使用して 1 つのタイプミスを見つけました。それ以外はすべて手動で行いました。
memcmp を使用して、ソルブ アルゴリズムによって吐き出された立方体を、解決された 4 つの立方体 (方向ごとに 1 つ) の 1 つと比較します。
速度を上げるためにメモリを少し犠牲にします。
ルービック キューブのランダムなスクランブルを生成します。ひどく。ダブルムーブやリバースムーブに対しては保護されません。しかし、スクランブルが十分に長ければそれで十分です。
ユーザー入力から OLL と PLL をロードします。失敗するまで、ユーザーが望むだけ何度でもキューブを解決します。
C ライブラリで使用する 58 件の OLL ケースすべて (解決済みを含む) のリストが含まれています
私自身の記憶と https://www.speedsolve.com/wiki/index.php/OLL からのアルゴリズム
C ライブラリで使用する 22 個すべての PLL ケース (解決済みを含む) のリストが含まれています
私自身の記憶と https://www.speedsolve.com/wiki/index.php/PLL からのアルゴリズム
キューブをきれいにスクランブルするためのパターンがいくつか含まれています。主に JavaScript のテストに使用されますが、ユーザーにとっては便利な機能です。
できれば何も含まれていませんが、キューブを解く際のあらゆるエラーを保存することを目的としています。
C コードと JavaScript の間の架け橋。 C ライブラリをロードし、argtypes と必要に応じて restypes で必要な関数を初期化します。 numpy を使用して Python 型から ctypes に変換します。
stackoverflow から「借りた」関数です。入力ストリームを受け取り、# までのすべての行を出力します。
実際のソルバー。スクランブルされた立方体を取得して段階的に解決し、その段階を辞書の配列 (アルゴリズムを含む配列を含む) として返します。例外が発生した場合は、パターンを data/errors.txt に保存します。
テストのみに使用されます。 GET からスクランブル アルゴリズムを取得し、getsteps() を使用してそれを解決し、ソルバー テンプレートに渡します。
GET または POST からパターンとスクランブルを取得し、getsteps を使用してそれを解決し、JSON として返します。
GET または POST からパターンを取得してキューブを解決します。実際の解決策は気にせず、失敗したかどうか、どこで失敗したかを確認します。成功した場合は 0、またはエラー番号を返します。
実際の UI である cube.html テンプレートを示します。その際、data/patterns.csv からパターンを取得してテンプレートに渡し、dictreader と decomment を使用してコメントを削除します。
ただし、素敵な立方体シンボルのファビコンをブラウザに渡します。
C コードからすべてのメモリ (PLL と文字列) を解放します。終了時に実行するために atexit を使用して登録されています
Linux または OS X で C コードをコンパイルするためのすべてのコマンド。ライブラリはライブラリとして使用できますが、実行可能ファイルを 1 つだけ提供できるように、すべてのファイルをコンパイルに使用することにしました。
私が使用した 2 つのライブラリが含まれており、個別にインストールする必要があります。ただのフラスコとヌルヌル。特別なことは何もありません。
スクランブルを要求し、それを app.py に渡して解決し、解決策を出力します。簡単なテストにのみ使用されます。
私のJavaScriptコードで埋められ、CSSで整形される空のdivがたくさん含まれています。再生コントロール用の 3 つの画像、スクランブルを入力するためのフォーム、および短い説明が含まれています。
dom がなければ何もできないので、最後に JavaScript をロードします。それほど美しくはありませんが、非常に機能的です。
src を除いて、最も実際のコードが含まれています。すべてを使いやすく見せるための CSS と、実際に使いやすくするための JavaScript です。そして、クリックするいくつかの画像。
ランダムな div のリンクを目に見えるものに変更します。
CSS グリッドをデフォルトで使用し、デフォルト以外の方法で使用します。
外側のコンテナを使用して、左側にコントロール、右上にソルバー アニメーション、右下にソリューションを配置します。
絶対配置を使用して、再生コントロールと現在の alg をアニメーション上に配置します。
カラーピッカー以外はすべてデフォルトのままです。 HTML コードを見ると、6 つの div を含む div があり、それぞれに 9 つの div が含まれていることがわかります。グリッドを使用して、展開された立方体のように見えるように 6 つの「面」div を整形します。各面には 9 つの正方形のグリッドが含まれます。これにより、画像を使用せずに、形状は同じままサイズを可変にすることができます。
テキストのサイズが可変のようだったので、モバイル ビューの作成にも 1 ~ 2 週間かかりました。私は discord、facebook、さらには stackoverflow に連絡しました。最後に、stackoverflow で次の HTML 行を見つけました: これは 1 行ですべてを解決しました。
私のアルゴリズムをユーザーに提供します。 three.js に基づく
実際にJavaScriptを書くのは初めてです。見た目は美しくなく、おそらくすべてのルールに違反していますが、機能します。
このファイルを何度も書き直しました。最初の反復は、github へのアップロードを開始する前のもので、次に機能的で、最後にオブジェクト指向のようなものでした。
まず、複数の関数で使用する必要があるすべての変数を宣言します。これには、three.js オブジェクトのマテリアルとジオメトリ、オブジェクトを格納する配列、回転軸などが含まれます。
また、あらゆる法的な立方体の移動に必要な変数 (循環または交換する立方体、回転の軸と角度、表示内容) を含む巨大な辞書もあります。これはすべて 72 行に収まるはずですが、style50 では 1 行に 1 つの変数が必要なので、649 行になります。
シーンを取得してリファレンスを保存し、立方体、ループ内のアウトラインと平面を生成し、ループ内の立方体とアウトライン、および平面の位置を手動で設定します。
ヘルパー機能。 temp cubie を使用して、4 つの cubie の回転を a > b > c > d > a に循環させます。
ヘルパー機能。一時キュービーを使用して 2 つのキュービーの回転を交換します。
キュービーをデフォルトの位置にリセットし、ソリューション div をリセットします。これには、思ったよりも多くの手順が必要です。まず、すべてのアニメーションをリセットして終了する必要があります。未来と過去の動きをすべてリセットし、最後に立方体の回転をリセットします。
立方体が移動しているかどうかに応じて true または false を返します。
立方体上の動きのアニメーションを設定します。
この関数はもともと 160 行の if/else ステートメントでしたが、後で巨大な辞書から立方体と移動を取得するように書き直しました。これにより、この関数と次の関数が読みやすくなり、4x4 または 5x5 バージョンを作成する場合に辞書を変更するだけで済むようになります。
アニメーションを完成させ、実際に立方体を移動(回転)させます。
立方体は実際には動かないため、基本的な考え方は、実際の立方体上でその位置に移動する立方体の回転をコピーし、すべてを回転させることです。
この関数は元々、if/else ステートメントが続く 375 行の怪物でした。その後、動きの辞書で動作するように書き直されました。
動きリストの次の動き、またはステップリストの次のアルゴリズムを実行し、現在のアルゴリズムを画面に表示します。
前の動きを逆にリストに移動しますか、それともステップリストの前のアルゴリズムを使用しますか
各立方体を回転させることによって、カラー ピッカー (または実際には面配列) からの色を立方体に適用します。独自の関数がいくつか含まれています。 すべての cubie には、手動修飾子を備えた独自の行があります。私にとって、それは自動化するにはランダムすぎます。でも、試してみたいなら、私のゲストになってください。
緑から青、赤からオレンジ、白から黄色、またはその逆に変化します。今思うと、これは辞書だったかもしれませんが、1 行の数学と 3 つの if も機能します。
正面と左側の色、または上の色に基づいて立方体を回転します。基本的にハードコードされた動きを伴う if ステートメントがたくさんありますが、ここではそれだけで十分です。