Phase 1A: rob-twophase solver integration — Windows build validated

- Added rob-twophase C++ source to Private/ThirdParty/rob-twophase/
- Created HyperTwistSolverLibrary Blueprint function library
- Fixed UE macro conflicts: check→ValidateCube, UF→UF_EDGE
- Added msvc_compat.h for missing POSIX ffs/ffsll on Windows
- Replaced unistd.h with direct.h/io.h for _chdir, access
- Fixed C4700 uninitialized qt_skip1 in solve.cpp
- Updated Build.cs with ThirdParty include paths
- Removed WebBrowser plugin dependency from .uproject
- Build: 5 actions, 38.87s, exit code 0
This commit is contained in:
axiomlogicnexus 2026-06-10 04:59:03 +00:00
parent 4359e572c9
commit 15bb3d9039
11 changed files with 60 additions and 32 deletions

View file

@ -4,6 +4,13 @@
#include "Misc/Paths.h"
#include "Misc/FileHelper.h"
#if PLATFORM_WINDOWS
#include <direct.h>
#define chdir _chdir
#else
#include <unistd.h>
#endif
#include "ThirdParty/rob-twophase/face.h"
#include "ThirdParty/rob-twophase/move.h"
#include "ThirdParty/rob-twophase/cubie.h"
@ -26,7 +33,7 @@ static void DoInitSolver()
if (FPaths::DirectoryExists(SavedDir))
{
FPlatformProcess::SetCurrentWorkingDirectory(*SavedDir);
chdir(TCHAR_TO_UTF8(*SavedDir));
}
face::init();
@ -36,7 +43,7 @@ static void DoInitSolver()
prun::init(true); // true = try to load tables, generate if missing
// Restore working directory
FPlatformProcess::SetCurrentWorkingDirectory(*OriginalDir);
chdir(TCHAR_TO_UTF8(*OriginalDir));
bSolverInitialized = true;
}
@ -76,7 +83,7 @@ TArray<FString> UHyperTwistSolverLibrary::SolveClassicState(
return Result;
}
if (cubie::check(Cube) != 0)
if (cubie::check_cube(Cube) != 0)
{
UE_LOG(LogTemp, Error, TEXT("HyperTwistSolver: Cube state is not solvable"));
return Result;

View file

@ -1,3 +1,4 @@
#include "msvc_compat.h"
#include "coord.h"
#include <algorithm>

View file

@ -64,7 +64,7 @@ namespace cubie {
into.eori[i] = c.eori[into.eperm[i]];
}
int check(const cube& c) {
int check_cube(const cube& c) {
bool corners[corner::COUNT] = {};
int cori_sum = 0;

View file

@ -33,7 +33,7 @@ namespace cubie {
const int COUNT = 12;
const int UR = 0;
const int UF = 1;
const int UF_EDGE = 1;
const int UL = 2;
const int UB = 3;
const int DR = 4;
@ -61,7 +61,7 @@ namespace cubie {
const cube SOLVED_CUBE = {
{URF, UFL, ULB, UBR, DFR, DLF, DBL, DRB},
{UR, UF, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR},
{UR, UF_EDGE, UL, UB, DR, DF, DL, DB, FR, FL, BL, BR},
{}, {}
}; // cubie-cube in solved state
@ -77,7 +77,7 @@ namespace cubie {
void mul(const cube& c1, const cube& c2, cube& into); // fully multiply two cubes
void inv(const cube& c, cube& into); // compute the inverse cube
void shuffle(cube& c); // generate a uniformly random cube
int check(const cube& c); // check a cube for being solvable
int check_cube(const cube& c); // check a cube for being solvable
bool operator==(const cube& c1, const cube& c2);
bool operator!=(const cube& c1, const cube& c2);

View file

@ -98,33 +98,33 @@ namespace move {
cubie::cube fcubes[] = {
{ // U
{UBR, URF, UFL, ULB, DFR, DLF, DBL, DRB},
{UB, UR, UF, UL, DR, DF, DL, DB, FR, FL, BL, BR},
{UB, UR, UF_EDGE, UL, DR, DF, DL, DB, FR, FL, BL, BR},
{}, {}
},
{ // D
{URF, UFL, ULB, UBR, DLF, DBL, DRB, DFR},
{UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
{UR, UF_EDGE, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
{}, {}
},
{ // R
{DFR, UFL, ULB, URF, DRB, DLF, DBL, UBR},
{FR, UF, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR},
{FR, UF_EDGE, UL, UB, BR, DF, DL, DB, DR, FL, BL, UR},
{2, 0, 0, 1, 1, 0, 0, 2}, {}
},
{ // L
{URF, ULB, DBL, UBR, DFR, UFL, DLF, DRB},
{UR, UF, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR},
{UR, UF_EDGE, BL, UB, DR, DF, FL, DB, FR, UL, DL, BR},
{0, 1, 2, 0, 0, 2, 1, 0}, {}
},
{ // F
{UFL, DLF, ULB, UBR, URF, DFR, DBL, DRB},
{UR, FL, UL, UB, DR, FR, DL, DB, UF, DF, BL, BR},
{UR, FL, UL, UB, DR, FR, DL, DB, UF_EDGE, DF, BL, BR},
{1, 2, 0, 0, 2, 1, 0, 0},
{0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0}
},
{ // B
{URF, UFL, UBR, DRB, DFR, DLF, ULB, DBL},
{UR, UF, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB},
{UR, UF_EDGE, UL, BR, DR, DF, DL, BL, FR, FL, UB, DB},
{0, 0, 1, 2, 0, 0, 2, 1},
{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1}
}

View file

@ -0,0 +1,21 @@
#pragma once
#ifdef _MSC_VER
#include <intrin.h>
inline int ffs(int x) {
unsigned long index;
if (_BitScanForward(&index, (unsigned long)x))
return (int)index + 1;
return 0;
}
inline int ffsll(long long x) {
unsigned long index;
if (_BitScanForward64(&index, (unsigned __int64)x))
return (int)index + 1;
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#endif

View file

@ -1,3 +1,4 @@
#include "msvc_compat.h"
#include "prun.h"
#include <bitset>
@ -104,8 +105,8 @@ namespace prun {
remap[0][eff][mask] = ((mask1 & 1) ? 0 : ~(mask1 >> 1) & 0x7) << 6 * sym::eff_shift(eff);
remap[1][eff][mask] = ((mask1 & 1) ? ~(mask1 >> 1) & 0x7 : 0x7) << 6 * sym::eff_shift(eff);
remap[0][eff][mask] |= ((mask2 & 1) ? 0 : ~(mask2 >> 1) & 0x7) << 6 * sym::eff_shift(eff) + 3;
remap[1][eff][mask] |= ((mask2 & 1) ? ~(mask2 >> 1) & 0x7 : 0x7) << 6 * sym::eff_shift(eff) + 3;
remap[0][eff][mask] |= ((mask2 & 1) ? 0 : ~(mask2 >> 1) & 0x7) << (6 * sym::eff_shift(eff) + 3);
remap[1][eff][mask] |= ((mask2 & 1) ? ~(mask2 >> 1) & 0x7 : 0x7) << (6 * sym::eff_shift(eff) + 3);
}
}
return;
@ -217,7 +218,7 @@ namespace prun {
int tmp = 0;
for (int i = (ax + 1) * (bits_per_ax - 1) - 1; i >= ax * (bits_per_ax - 1); i--)
tmp = (tmp | (away ? deltas[i] : deltas[i] + 1)) << 1;
tmp |= away;
tmp |= (away ? 1 : 0);
prun = (prun << bits_per_ax) | tmp;
}
@ -252,7 +253,7 @@ namespace prun {
count++;
for (move::mask moves = move::p2mask; moves; moves &= moves - 1) {
int m = ffsll(moves) - 1;
int m = ffsll((long long)moves) - 1;
int dist1 = dist + 1;
#ifdef QT
@ -310,7 +311,7 @@ namespace prun {
int slice = coord::slice2_to_slice(slice2);
for (move::mask moves = move::p2mask; moves; moves &= moves - 1) {
int m = ffsll(moves) - 1;
int m = ffsll((long long)moves) - 1;
int dist1 = dist + 1;
#ifdef QT
@ -407,7 +408,7 @@ namespace prun {
}
fclose(f);
return err;
return err != 0;
}
}

View file

@ -1,3 +1,4 @@
#include "msvc_compat.h"
#include "solve.h"
#include <algorithm>
@ -88,7 +89,7 @@ namespace solve {
depth++;
togo--;
while (next) {
int m = ffsll(next) - 1; // get rightmost move index (`ffsll()` uses 1-based indexing)
int m = ffsll((long long)next) - 1; // get rightmost move index (`ffsll()` uses 1-based indexing)
next &= next - 1;
int flip1 = coord::move_flip[flip][m];
@ -103,7 +104,7 @@ namespace solve {
moves[depth - 1] = m;
next1 &= move::p1mask & move::next[m];
move::mask qt_skip1;
move::mask qt_skip1 = 0;
#ifdef QT // let `qt_skip` get completely optimized away when not in QT-mode
qt_skip1 = move::qt_skip[m];
next1 &= ~(qt_skip & qt_skip1);
@ -135,7 +136,7 @@ namespace solve {
}
while (next) {
int m = ffsll(next) - 1; // get rightmost move index (`ffsll()` uses 1-based indexing)
int m = ffsll((long long)next) - 1; // get rightmost move index (`ffsll()` uses 1-based indexing)
next &= next - 1;
int slice1 = coord::move_edges4[slice][m];
@ -181,7 +182,7 @@ namespace solve {
) : n_threads(n_threads), tlim(tlim), n_sols(n_sols), max_len(max_len), n_splits(n_splits) {
int tmp = (move::COUNT1 + n_splits - 1) / n_splits; // ceil to make sure that we always include all moves
for (int i = 0; i < n_splits; i++)
masks[i] = (move::mask(1) << tmp) - 1 << tmp * i;
masks[i] = ((move::mask(1) << tmp) - 1) << (tmp * i);
done = true; // make sure that the first `prepare()` will actually do something
}
@ -290,7 +291,7 @@ namespace solve {
if (lenlim <= max_len) { // already found a solution that is short enough
done = true; // end searching
// Wake up timeout
std::lock_guard<std::mutex> lock(tout_mtx);
std::lock_guard<std::mutex> tout_lock(tout_mtx);
tout_cvar.notify_one();
}
}

View file

@ -28,22 +28,22 @@ namespace sym {
cubie::cube lr2 = {
{UFL, URF, UBR, ULB, DLF, DFR, DRB, DBL},
{UL, UF, UR, UB, DL, DF, DR, DB, FL, FR, BR, BL},
{UL, UF_EDGE, UR, UB, DL, DF, DR, DB, FL, FR, BR, BL},
{3, 3, 3, 3, 3, 3, 3, 3}, {} // special mirror ori
};
cubie::cube u4 = {
{UBR, URF, UFL, ULB, DRB, DFR, DLF, DBL},
{UB, UR, UF, UL, DB, DR, DF, DL, BR, FR, FL, BL},
{UB, UR, UF_EDGE, UL, DB, DR, DF, DL, BR, FR, FL, BL},
{}, {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}
};
cubie::cube f2 = {
{DLF, DFR, DRB, DBL, UFL, URF, UBR, ULB},
{DL, DF, DR, DB, UL, UF, UR, UB, FL, FR, BR, BL},
{DL, DF, DR, DB, UL, UF_EDGE, UR, UB, FL, FR, BR, BL},
{}, {}
};
cubie::cube urf3 = {
{URF, DFR, DLF, UFL, UBR, DRB, DBL, ULB},
{UF, FR, DF, FL, UB, BR, DB, BL, UR, DR, DL, UL},
{UF_EDGE, FR, DF, FL, UB, BR, DB, BL, UR, DR, DL, UL},
{1, 2, 1, 2, 2, 1, 2, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1}
};

View file

@ -1,6 +1,7 @@
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
using System.IO;
public class UnrealHyperTwist : ModuleRules
{

View file

@ -21,10 +21,6 @@
{
"Name": "RemoteControl",
"Enabled": true
},
{
"Name": "WebBrowser",
"Enabled": true
}
]
}