save works!

This commit is contained in:
Asuro
2025-03-10 22:45:15 +01:00
parent ff00119e5b
commit c7377c3452
11 changed files with 538 additions and 217 deletions

View File

@@ -9,73 +9,79 @@
namespace
{
static constexpr Puzzle::PuzPos Dirs[4]{
static constexpr Generated::PuzPos Dirs[4]{
{-1, 0},
{0, -1},
{0, 1},
{1, 0},
};
Puzzle::StaticPuzzleData* StaticDataInstance = nullptr;
Generated::StaticPuzzleData* StaticDataInstance = nullptr;
} // namespace
namespace Puzzle
namespace Generated
{
void StaticPuzzleData::Setup()
void Setup(StaticPuzzleData& data)
{
StaticDataInstance = this;
StaticDataInstance = &data;
LOG("Setting up static puzzle data");
for (int32_t i = 0; i < BX_COUNTOF(Cards); ++i)
for (int32_t i = 0; i < BX_COUNTOF(data.Cards); ++i)
{
Cards[i].ModelHandle = Game::GameRendering::Get().GetModelHandleFromPath("models/w straight.glb");
data.Cards[i].ModelHandle = Game::GameRendering::Get().GetModelHandleFromPath("models/w straight.glb");
}
}
StaticPuzzleData& StaticPuzzleData::Get()
StaticPuzzleData& GetStaticPuzzleData()
{
assert(StaticDataInstance != nullptr);
return *StaticDataInstance;
}
const StaticPuzzleCard& StaticPuzzleData::GetCard(StaticPuzzleCardHandle H) const
const StaticPuzzleCard& GetCard(const StaticPuzzleData& data, StaticPuzzleCardHandle H)
{
assert(H.IsValid());
return Cards[H.Idx];
// assert(IsValid(H));
return data.Cards[H.Idx];
}
bool PuzzleNode::HasElement(PuzzleElementType search) const
bool HasElement(const PuzzleNode& node, PuzzleElementType::Enum search)
{
for (int32_t i = 0; i < Config::MaxElementsPerTile; ++i)
for (int32_t i = 0; i < Puzzle::Config::MaxElementsPerTile; ++i)
{
if (PlacedTypes[i] == search) return true;
if (node.PlacedTypes[i] == search) return true;
}
return false;
}
bool PuzzleNode::IsEmpty() const
bool IsEmpty(const PuzzleNode& node)
{
for (int32_t i = 0; i < Config::MaxElementsPerTile; ++i)
for (int32_t i = 0; i < Puzzle::Config::MaxElementsPerTile; ++i)
{
if (PlacedTypes[i] != PuzzleElementType::None) return false;
if (node.PlacedTypes[i] != PuzzleElementType::None) return false;
}
return true;
}
uint8_t PuzzleCardStack::GetRemainingCount()
bool IsValid(StaticPuzzleCardHandle h)
{
assert(MaxAvailableCount >= UsedCount);
return MaxAvailableCount - UsedCount;
return h.Idx != UINT16_MAX;
}
const PuzzleNode& PuzzleData::GetNodeAt(PuzPos pos) const
uint8_t GetRemainingCount(const PuzzleCardStack& stack)
{
assert(pos.X < Config::MaxPuzzleSizeCards && pos.Y < Config::MaxPuzzleSizeCards && pos.X >= 0 && pos.Y >= 0);
return PlacedNodes[pos.Y * Config::MaxPuzzleSizeCards + pos.X];
assert(stack.MaxAvailableCount >= stack.UsedCount);
return stack.MaxAvailableCount - stack.UsedCount;
}
PuzzleElementType PuzzleData::GetElementAt(ElemPos pos) const
const PuzzleNode& GetNodeAt(const PuzzleData& puz, PuzPos pos)
{
assert(pos.ElemIdx < Config::MaxElementsPerTile);
const PuzzleNode& node = GetNodeAt(pos.Position);
assert(pos.X < Puzzle::Config::MaxPuzzleSizeCards && pos.Y < Puzzle::Config::MaxPuzzleSizeCards && pos.X >= 0 &&
pos.Y >= 0);
return puz.PlacedNodes[pos.Y * Puzzle::Config::MaxPuzzleSizeCards + pos.X];
}
PuzzleElementType::Enum GetElementAt(const PuzzleData& puz, ElemPos pos)
{
assert(pos.ElemIdx < Puzzle::Config::MaxElementsPerTile);
const PuzzleNode& node = GetNodeAt(puz, pos.Position);
return node.PlacedTypes[pos.ElemIdx];
}
@@ -95,26 +101,26 @@ namespace Puzzle
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, ElemPos pos)
{
const PuzzleNode& goalNode = puzzle.GetNodeAt(pos.Position);
PuzzleElementType goalType = puzzle.GetElementAt(pos);
const PuzzleNode& goalNode = GetNodeAt(puzzle, pos.Position);
PuzzleElementType::Enum goalType = GetElementAt(puzzle, pos);
uint32_t currentPositionQueueIdx = 0;
uint32_t positionQueueCount = 0;
PuzPos positionQueue[Config::MaxTilesInPuzzle];
PuzPos positionQueue[Puzzle::Config::MaxTilesInPuzzle];
positionQueue[0] = pos.Position;
positionQueueCount++;
while (positionQueueCount > 0)
{
assert(currentPositionQueueIdx < Config::MaxTilesInPuzzle);
assert(currentPositionQueueIdx < Puzzle::Config::MaxTilesInPuzzle);
PuzPos currentPos = positionQueue[currentPositionQueueIdx];
for (PuzPos dir : Dirs)
{
PuzPos nextPos = currentPos + dir;
if (IsValidGoalConnection(puzzle, nextPos, currentPos, goalType))
{
const PuzzleNode& node = puzzle.GetNodeAt(nextPos);
for (PuzzleElementType e : node.PlacedTypes)
const PuzzleNode& node = GetNodeAt(puzzle, nextPos);
for (PuzzleElementType::Enum e : node.PlacedTypes)
{
if (IsValidSource(e, goalType))
{
@@ -133,46 +139,50 @@ namespace Puzzle
bool PuzzleSolver::IsValidGoalConnection(const PuzzleData& puzzle,
PuzPos flowFrom,
PuzPos flowTo,
PuzzleElementType goalType)
PuzzleElementType::Enum goalType)
{
const PuzzleNode& from = puzzle.GetNodeAt(flowFrom);
const PuzzleNode& to = puzzle.GetNodeAt(flowTo);
const PuzzleNode& from = GetNodeAt(puzzle, flowFrom);
const PuzzleNode& to = GetNodeAt(puzzle, flowTo);
if (goalType == PuzzleElementType::WaterGoal)
{
return from.HasElement(PuzzleElementType::WaterIn) || from.HasElement(PuzzleElementType::WaterChannel) ||
from.HasElement(PuzzleElementType::WaterGoal);
return HasElement(from, PuzzleElementType::WaterIn) || HasElement(from, PuzzleElementType::WaterChannel) ||
HasElement(from, PuzzleElementType::WaterGoal);
}
else if (goalType == PuzzleElementType::ElectricGoal)
{
return from.HasElement(PuzzleElementType::ElectricIn) || from.HasElement(PuzzleElementType::ElectricGoal) ||
from.IsEmpty();
return HasElement(from, PuzzleElementType::ElectricIn) ||
HasElement(from, PuzzleElementType::ElectricGoal) || IsEmpty(from);
}
assert(false);
return false;
}
bool PuzzleSolver::IsValidSource(PuzzleElementType sourceType, PuzzleElementType goalType)
bool PuzzleSolver::IsValidSource(PuzzleElementType::Enum sourceType, PuzzleElementType::Enum goalType)
{
return (sourceType == PuzzleElementType::WaterIn && goalType == PuzzleElementType::WaterGoal) ||
(sourceType == PuzzleElementType::ElectricIn && goalType == PuzzleElementType::ElectricGoal);
}
bool PuzzleData::RenderDebugUI()
} // namespace Generated
namespace Generated
{
bool RenderDebugUI(PuzzleData& obj)
{
bool dataChanged = false;
bool isVisible = true;
if (ImGui::Begin("Puzzle", &isVisible))
{
ImGui::Text("%s", PuzzleName);
ImGui::Text("%s", obj.PuzzleName);
int32_t W = S.WidthTiles;
int32_t H = S.HeightTiles;
int32_t W = obj.WidthTiles;
int32_t H = obj.HeightTiles;
ImGui::PushID("width");
ImGui::SetNextItemWidth(40);
if (ImGui::DragInt("", &W, 0.3f, 0, Config::MaxPuzzleSizeTiles))
if (ImGui::DragInt("", &W, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{
S.WidthTiles = uint8_t(W);
obj.WidthTiles = uint8_t(W);
dataChanged = true;
}
ImGui::PopID();
@@ -181,9 +191,9 @@ namespace Puzzle
ImGui::SameLine();
ImGui::SetNextItemWidth(40);
ImGui::PushID("height");
if (ImGui::DragInt("", &H, 0.3f, 0, Config::MaxPuzzleSizeTiles))
if (ImGui::DragInt("", &H, 0.3f, 0, Puzzle::Config::MaxPuzzleSizeTiles))
{
S.HeightTiles = uint8_t(H);
obj.HeightTiles = uint8_t(H);
dataChanged = true;
}
ImGui::PopID();
@@ -193,10 +203,32 @@ namespace Puzzle
if (dataChanged)
{
char path[128]{0};
bx::snprintf(path, sizeof(path), "game/data/%s.pzl", PuzzleName);
SerializeStruct(&S, sizeof(S), path);
bx::snprintf(path, sizeof(path), "game/data/%s.pzl", obj.PuzzleName);
Serializer ser;
ser.Init(path);
if (Save(&obj, 1, ser))
{
LOG("Saved to %s", path);
}
else
{
LOG_ERROR("Failed to save to %s", path);
}
ser.Finish();
}
return isVisible;
}
} // namespace Puzzle
PuzPos operator+=(PuzPos lhs, const PuzPos& rhs)
{
lhs.X += rhs.X;
lhs.Y += rhs.Y;
return lhs;
}
PuzPos operator+(PuzPos lhs, const PuzPos& rhs)
{
lhs += rhs;
return lhs;
}
} // namespace Generated