simplify puzzle data and auto run codegen

This commit is contained in:
Asuro
2025-03-14 01:33:38 +01:00
parent 97146664f2
commit de88190c47
9 changed files with 82 additions and 143 deletions

View File

@@ -60,24 +60,6 @@ namespace Generated
return data.Cards[H.Idx];
}
bool HasElement(const PuzzleNode& node, PuzzleElementType::Enum search)
{
for (int32_t i = 0; i < Puzzle::Config::MaxElementsPerTile; ++i)
{
if (node.PlacedTypes[i] == search) return true;
}
return false;
}
bool IsEmpty(const PuzzleNode& node)
{
for (int32_t i = 0; i < Puzzle::Config::MaxElementsPerTile; ++i)
{
if (node.PlacedTypes[i] != PuzzleElementType::None) return false;
}
return true;
}
bool IsValid(StaticPuzzleCardHandle h)
{
return h.Idx != UINT16_MAX;
@@ -89,18 +71,43 @@ namespace Generated
return stack.MaxAvailableCount - stack.UsedCount;
}
const PuzzleNode& GetNodeAt(const PuzzleData& puz, PuzPos pos)
PuzzleElementType::Enum GetNodeAt(const PuzzleData& puz, PuzPos pos)
{
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];
// TODO: this is horrible
for (int32_t i = 0; i < puz.PlacedCardCount; ++i)
{
auto& card = puz.PlacedCards[i];
int8_t offsetX = pos.X - card.Position.X;
int8_t offsetY = pos.Y - card.Position.Y;
if (offsetX >= 0 && offsetX < Puzzle::Config::CardSize && offsetY >= 0 &&
offsetY < Puzzle::Config::CardSize)
{
PuzzleElementType::Enum cardVal =
GetCardNodeAt(GetCard(GetStaticPuzzleData(), card.RefCard), offsetX, offsetY);
if (cardVal != PuzzleElementType::None) return cardVal;
}
}
return puz.BackgroundTiles[pos.Y * Puzzle::Config::MaxPuzzleSizeCards + pos.X];
}
PuzzleElementType::Enum GetElementAt(const PuzzleData& puz, ElemPos pos)
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, int8_t x, int8_t y)
{
assert(pos.ElemIdx < Puzzle::Config::MaxElementsPerTile);
const PuzzleNode& node = GetNodeAt(puz, pos.Position);
return node.PlacedTypes[pos.ElemIdx];
assert(x >= 0 && x < Puzzle::Config::CardSize);
assert(y >= 0 && y < Puzzle::Config::CardSize);
// TODO: account for card rotation
return card.Elements[y * Puzzle::Config::CardSize + x];
}
PuzzleElementType::Enum& EditCardNodeAt(StaticPuzzleCard& card, int8_t x, int8_t y)
{
assert(x >= 0 && x < Puzzle::Config::CardSize);
assert(y >= 0 && y < Puzzle::Config::CardSize);
// TODO: account for card rotation
return card.Elements[y * Puzzle::Config::CardSize + x];
}
bool PuzzleSolver::IsPuzzleSolved(const PuzzleData& puzzle)
@@ -117,16 +124,15 @@ namespace Generated
return IsSolved;
}
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, ElemPos pos)
bool PuzzleSolver::IsExitSatisfied(const PuzzleData& puzzle, PuzPos pos)
{
const PuzzleNode& goalNode = GetNodeAt(puzzle, pos.Position);
PuzzleElementType::Enum goalType = GetElementAt(puzzle, pos);
PuzzleElementType::Enum goalType = GetNodeAt(puzzle, pos);
uint32_t currentPositionQueueIdx = 0;
uint32_t positionQueueCount = 0;
PuzPos positionQueue[Puzzle::Config::MaxTilesInPuzzle];
positionQueue[0] = pos.Position;
positionQueue[0] = pos;
positionQueueCount++;
while (positionQueueCount > 0)
{
@@ -137,13 +143,9 @@ namespace Generated
PuzPos nextPos = currentPos + dir;
if (IsValidGoalConnection(puzzle, nextPos, currentPos, goalType))
{
const PuzzleNode& node = GetNodeAt(puzzle, nextPos);
for (PuzzleElementType::Enum e : node.PlacedTypes)
if (IsValidSource(GetNodeAt(puzzle, nextPos), goalType))
{
if (IsValidSource(e, goalType))
{
return true;
}
return true;
}
positionQueue[positionQueueCount] = nextPos;
positionQueueCount++;
@@ -159,18 +161,18 @@ namespace Generated
PuzPos flowTo,
PuzzleElementType::Enum goalType)
{
const PuzzleNode& from = GetNodeAt(puzzle, flowFrom);
const PuzzleNode& to = GetNodeAt(puzzle, flowTo);
auto from = GetNodeAt(puzzle, flowFrom);
auto to = GetNodeAt(puzzle, flowTo);
if (goalType == PuzzleElementType::WaterGoal)
{
return HasElement(from, PuzzleElementType::WaterIn) || HasElement(from, PuzzleElementType::WaterChannel) ||
HasElement(from, PuzzleElementType::WaterGoal);
return from == PuzzleElementType::WaterIn || from == PuzzleElementType::WaterChannel ||
from == PuzzleElementType::WaterGoal;
}
else if (goalType == PuzzleElementType::ElectricGoal)
{
return HasElement(from, PuzzleElementType::ElectricIn) ||
HasElement(from, PuzzleElementType::ElectricGoal) || IsEmpty(from);
return from == PuzzleElementType::ElectricIn || from == PuzzleElementType::ElectricGoal ||
from == PuzzleElementType::None;
}
assert(false);
return false;
@@ -192,14 +194,9 @@ namespace Generated
bx::snprintf(buf, bufSize, "%s/%u.pzl", Puzzle::PuzzleFileDir, puzID);
}
const char* GetShortNodeName(const PuzzleNode& node)
const char* GetShortNodeName(const PuzzleElementType::Enum node)
{
PuzzleElementType::Enum elemMax = PuzzleElementType::None;
for (int32_t i = 0; i < BX_COUNTOF(node.PlacedTypes); ++i)
{
if (node.PlacedTypes[i] > elemMax) elemMax = node.PlacedTypes[i];
}
return PuzzleElementType::ShortName[elemMax];
return PuzzleElementType::ShortName[node];
}
bool RenderDebugUI(PuzzleData& obj)
@@ -257,7 +254,7 @@ namespace Generated
for (int32_t x = 0; x < obj.WidthTiles; ++x)
{
ImGui::PushID(x);
PuzzleNode& node = obj.PlacedNodes[Puzzle::Config::MaxPuzzleSizeTiles * y + x];
auto node = GetNodeAt(obj, {int8_t(x), int8_t(y)});
ImVec2 pos = ImVec2{puzCursorStart.x + x * UIPuzBoxSize + 5, puzCursorStart.y + y * UIPuzBoxSize};
ImGui::SetCursorScreenPos(pos);
ImGui::Text("%s", GetShortNodeName(node));

View File

@@ -31,17 +31,16 @@ namespace Generated
void LoadStaticPuzzleData();
void SaveStaticPuzzleData();
const StaticPuzzleCard& GetCard(const StaticPuzzleData& data, StaticPuzzleCardHandle H);
bool HasElement(const PuzzleNode& node, PuzzleElementType::Enum search);
bool IsEmpty(const PuzzleNode& node);
bool IsValid(StaticPuzzleCardHandle h);
uint8_t GetRemainingCount(const PuzzleCardStack& stack);
const PuzzleNode& GetNodeAt(const PuzzleData& puz, PuzPos pos);
PuzzleElementType::Enum GetElementAt(const PuzzleData& puz, ElemPos pos);
PuzzleElementType::Enum GetNodeAt(const PuzzleData& puz, PuzPos pos);
PuzzleElementType::Enum GetCardNodeAt(const StaticPuzzleCard& card, int8_t x, int8_t y);
PuzzleElementType::Enum& EditCardNodeAt(StaticPuzzleCard& card, int8_t x, int8_t y);
struct PuzzleSolver
{
bool IsPuzzleSolved(const Generated::PuzzleData& puzzle);
bool IsExitSatisfied(const Generated::PuzzleData& puzzle, ElemPos pos);
bool IsExitSatisfied(const Generated::PuzzleData& puzzle, PuzPos pos);
// This assumes flowFrom is already verified to be connected.
bool IsValidGoalConnection(const Generated::PuzzleData& puzzle,

Binary file not shown.

Binary file not shown.

View File

@@ -44,12 +44,6 @@ type PuzPos
i8 Y
}
type ElemPos
{
PuzPos Position
u8 ElemIdx
}
enum PuzzleElementType(u8)
{
None GameName("Empty") ShortName(" ")
@@ -62,15 +56,10 @@ enum PuzzleElementType(u8)
Bridge GameName("Bridge") ShortName("#")
}
type PuzzleNode
{
PuzzleElementType PlacedTypes Arr(4)
}
type StaticPuzzleCard
{
PuzzleNode Nodes Arr(4)
u16 ModelHandle
PuzzleElementType Elements Arr(4)
u16 ModelHandle
}
type StaticPuzzleCardHandle
@@ -108,7 +97,7 @@ type PuzzleData
PuzzleCardStack AvailableCards Arr(16)
u32 PlacedCardCount
PlacedPuzzleCard PlacedCards Arr(256)
PuzzleNode PlacedNodes Arr(1024)
PuzzleElementType BackgroundTiles Arr(1024)
u32 GoalPositionCount
ElemPos GoalPositions Arr(16)
PuzPos GoalPositions Arr(16)
}

View File

@@ -603,22 +603,22 @@ namespace Game
}
Tools::ModelDropdown(card.ModelHandle);
for (int32_t y = 0; y < Puzzle::Config::CardSize; ++y)
for (int8_t y = 0; y < Puzzle::Config::CardSize; ++y)
{
ImGui::PushID(y);
for (int32_t x = 0; x < Puzzle::Config::CardSize; ++x)
for (int8_t x = 0; x < Puzzle::Config::CardSize; ++x)
{
if (x > 0) ImGui::SameLine();
ImGui::PushID(x);
auto& node = card.Nodes[y * Puzzle::Config::CardSize + x];
if (ImGui::Button(Generated::PuzzleElementType::ShortName[node.PlacedTypes[0]], {26, 24}))
auto& node = Generated::EditCardNodeAt(card, x, y);
if (ImGui::Button(Generated::PuzzleElementType::ShortName[node], {26, 24}))
{
int32_t newVal = int32_t(node.PlacedTypes[0]) + 1;
int32_t newVal = int32_t(node) + 1;
if (newVal >= Generated::PuzzleElementType::EntryCount)
{
newVal = 0;
}
node.PlacedTypes[0] = Generated::PuzzleElementType::Enum(newVal);
node = Generated::PuzzleElementType::Enum(newVal);
}
ImGui::PopID();
}