From 1f85741c8d12d9b1fbd55b29f334de572f9eea9b Mon Sep 17 00:00:00 2001 From: jbzdarkid Date: Fri, 9 Nov 2018 10:08:03 -0800 Subject: Reading & writing to tutorial vault works! --- App/Main.cpp | 6 +- Installer/Installer.vdproj | 6 +- Source/Panel.cpp | 178 +++++++++++++++++++++++++++--------------- Source/Panel.h | 30 +++++-- Test/PanelExtractionTests.cpp | 119 +++++++++++++++++++++------- 5 files changed, 239 insertions(+), 100 deletions(-) diff --git a/App/Main.cpp b/App/Main.cpp index ab3e88a..6ebef7e 100644 --- a/App/Main.cpp +++ b/App/Main.cpp @@ -19,8 +19,8 @@ #define IDT_RANDOMIZED 0x409 HWND hwndSeed, hwndRandomize; -int panel = 0x18AF; -// int panel = 0x33D4; +// int panel = 0x18AF; +int panel = 0x33D4; std::shared_ptr _panel; std::shared_ptr randomizer = std::make_shared(); @@ -94,7 +94,7 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) _panel->Write(panel); break; case IDC_DUMP: - // _panel->Serialize(); + _panel->Serialize(); break; } } diff --git a/Installer/Installer.vdproj b/Installer/Installer.vdproj index 9b05e20..19d6036 100644 --- a/Installer/Installer.vdproj +++ b/Installer/Installer.vdproj @@ -125,7 +125,7 @@ } "{3C67513D-01DD-4637-8A68-80971EB9504F}:_8E9D847124D34D9D9008762077D816DE" { - "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" + "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]" "Name" = "8:#1925" "AlwaysCreate" = "11:FALSE" "Condition" = "8:" @@ -163,7 +163,7 @@ "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:Witness Randomizer" "ProductCode" = "8:{7DD620CA-9593-4E32-9D60-9D12069DA33C}" - "PackageCode" = "8:{90B5567A-BE63-4F98-A6C8-5FAC1942075A}" + "PackageCode" = "8:{BBA8F7F1-52D8-44B0-BC53-9AC3F0181E3D}" "UpgradeCode" = "8:{4CB5496B-A47E-41D3-B4A7-677E29AB7513}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" @@ -184,7 +184,7 @@ "ARPIconIndex" = "3:0" "SearchPath" = "8:" "UseSystemSearchPath" = "11:TRUE" - "TargetPlatform" = "3:0" + "TargetPlatform" = "3:1" "PreBuildEvent" = "8:" "PostBuildEvent" = "8:" "RunPostBuildEvent" = "3:0" diff --git a/Source/Panel.cpp b/Source/Panel.cpp index b6aa504..c0fb7ec 100644 --- a/Source/Panel.cpp +++ b/Source/Panel.cpp @@ -13,8 +13,9 @@ int find(const std::vector &data, T search, size_t startIndex = 0) { } Panel::Panel(int id) { - _width = 2 * _memory.ReadPanelData(id, GRID_SIZE_X, 1)[0] - 1; - _height = 2 * _memory.ReadPanelData(id, GRID_SIZE_Y, 1)[0] - 1; + _memory = std::make_shared("witness64_d3d11.exe"); + _width = 2 * _memory->ReadPanelData(id, GRID_SIZE_X, 1)[0] - 1; + _height = 2 * _memory->ReadPanelData(id, GRID_SIZE_Y, 1)[0] - 1; _grid.resize(_width); for (auto& row : _grid) row.resize(_height); @@ -22,15 +23,12 @@ Panel::Panel(int id) { ReadDecorations(id); } -// For testing -Panel::Panel() {} - void Panel::Write(int id) { WriteIntersections(id); WriteDecorations(id); - _memory.WritePanelData(id, GRID_SIZE_X, {(_width + 1)/2}); - _memory.WritePanelData(id, GRID_SIZE_Y, {(_height + 1)/2}); + _memory->WritePanelData(id, GRID_SIZE_X, {(_width + 1)/2}); + _memory->WritePanelData(id, GRID_SIZE_Y, {(_height + 1)/2}); } nlohmann::json Panel::Serialize() { @@ -49,6 +47,9 @@ nlohmann::json Panel::Serialize() { if (x%2 == 1 && y%2 == 1) { puzzle["grid"][x][y] = Decoration::to_json(_grid[x][y]); } else { + if (_grid[x][y] & IntersectionFlags::HAS_DOT) { + puzzle["dots"].emplace_back(nlohmann::json({{"x", x}, {"y", y}})); + } puzzle["grid"][x][y] = false; } } @@ -80,65 +81,52 @@ void Panel::Random() { } void Panel::ReadDecorations(int id) { - int numDecorations = _memory.ReadPanelData(id, NUM_DECORATIONS, 1)[0]; - std::vector decorations = _memory.ReadArray(id, DECORATIONS, numDecorations); - - int x = 1; - int y = _height - 2; - for (int decoration : decorations) { - _grid[x][y] = decoration; - x += 2; - if (x > _width - 1) { - x = 1; - y -= 2; - } + int numDecorations = _memory->ReadPanelData(id, NUM_DECORATIONS, 1)[0]; + std::vector decorations = _memory->ReadArray(id, DECORATIONS, numDecorations); + + for (int i=0; i decorations; - for (int y=_height - 2; y>0; y-=2) { + for (int y=_height-2; y>0; y-=2) { for (int x=1; x<_width - 1; x+=2) { decorations.push_back(_grid[x][y]); } } - _memory.WritePanelData(id, NUM_DECORATIONS, {static_cast(decorations.size())}); - _memory.WriteArray(id, DECORATIONS, decorations); + _memory->WritePanelData(id, NUM_DECORATIONS, {static_cast(decorations.size())}); + _memory->WriteArray(id, DECORATIONS, decorations); } void Panel::ReadIntersections(int id) { - int numIntersections = _memory.ReadPanelData(id, NUM_DOTS, 1)[0]; - std::vector intersectionFlags = _memory.ReadArray(id, DOT_FLAGS, numIntersections); + int numIntersections = _memory->ReadPanelData(id, NUM_DOTS, 1)[0]; + std::vector intersectionFlags = _memory->ReadArray(id, DOT_FLAGS, numIntersections); - int x = 0; - int y = _height - 1; int i = 0; for (;; i++) { + auto [x, y] = loc_to_xy(i); + if (y < 0) break; if (intersectionFlags[i] & IntersectionFlags::IS_STARTPOINT) { _startpoints.push_back({x, y}); } - x += 2; - if (x > _width) { - x = 0; - y -= 2; - } - if (y < 0) break; } - std::pair, std::vector> connections; - int numConnections = _memory.ReadPanelData(id, NUM_CONNECTIONS, 1)[0]; - connections.first = _memory.ReadArray(id, DOT_CONNECTION_A, numConnections); - connections.second = _memory.ReadArray(id, DOT_CONNECTION_B, numConnections); - std::vector intersections = _memory.ReadArray(id, DOT_POSITIONS, numIntersections*2); + int numConnections = _memory->ReadPanelData(id, NUM_CONNECTIONS, 1)[0]; + std::vector connections_a = _memory->ReadArray(id, DOT_CONNECTION_A, numConnections); + std::vector connections_b = _memory->ReadArray(id, DOT_CONNECTION_B, numConnections); + std::vector intersections = _memory->ReadArray(id, DOT_POSITIONS, numIntersections*2); - // Iterate the remaining intersections (either endpoints or gaps) + // Iterate the remaining intersections (endpoints, dots, gaps) for (; i < numIntersections; i++) { if (intersectionFlags[i] & IntersectionFlags::IS_ENDPOINT) { for (int j=0; j intersections[2*location]) { // To the right + x++; + } else if (intersections[2*i + 1] > intersections[2*location + 1]) { + // y coordinate is 0 (bottom) 1 (top), so this check is reversed. We are above the target (location) + y--; + } else { // Beleow the target + y++; + } + + _grid[x][y] |= IntersectionFlags::HAS_DOT; + break; } } } @@ -161,34 +177,41 @@ void Panel::ReadIntersections(int id) { void Panel::WriteIntersections(int id) { std::vector intersections; std::vector intersectionFlags; - std::pair, std::vector> connections; + std::vector connections_a; + std::vector connections_b; double min = 0.1; double max = 0.9; double width_interval = (max - min) / (_width/2); double height_interval = (max - min) / (_height/2); - for (int y=0; y<_height/2; y++) { - for (int x=0; x<_width/2; x++) { - intersections.push_back(static_cast(min + x * width_interval)); - intersections.push_back(static_cast(min + y * height_interval)); + // TODO(future): Stop using push_back and set these into explicit locations, unrequires loop iteration order + for (int y=_height-1; y>=0; y-=2) { + for (int x=0; x<_width; x+=2) { + intersections.push_back(static_cast(min + (x/2) * width_interval)); + intersections.push_back(static_cast(max - (y/2) * height_interval)); int flags = 0; - if (find(_startpoints, {2*x, 2*y}) != -1) flags |= IntersectionFlags::IS_STARTPOINT; + if (find(_startpoints, {x, y}) != -1) flags |= IntersectionFlags::IS_STARTPOINT; intersectionFlags.push_back(flags); + + // Create connections for this intersection -- always write low -> high if (y > 0) { - connections.first.push_back(y * _width + x); - connections.second.push_back((y - 1) * _width + x); + connections_a.push_back(xy_to_loc(x, y-2)); + connections_b.push_back(xy_to_loc(x, y)); } if (x > 0) { - connections.first.push_back(y * _width + x); - connections.second.push_back(y * _width + (x - 1)); + connections_a.push_back(xy_to_loc(x-2, y)); + connections_b.push_back(xy_to_loc(x, y)); } } } for (Endpoint endpoint : _endpoints) { - double xPos = min + endpoint.GetX() * width_interval; - double yPos = min + endpoint.GetY() * height_interval; + connections_a.push_back(xy_to_loc(endpoint.GetX(), endpoint.GetY())); // Target to connect to + connections_b.push_back(static_cast(intersectionFlags.size())); // This endpoint + + double xPos = min + (endpoint.GetX()/2) * width_interval; + double yPos = max - (endpoint.GetY()/2) * height_interval; if (endpoint.GetDir()== Endpoint::Direction::LEFT) { xPos -= .05; } else if (endpoint.GetDir() == Endpoint::Direction::RIGHT) { @@ -200,18 +223,49 @@ void Panel::WriteIntersections(int id) { } intersections.push_back(static_cast(xPos)); intersections.push_back(static_cast(yPos)); - - connections.first.push_back(endpoint.GetY() * _width + endpoint.GetX()); // Target to connect to - connections.second.push_back(static_cast(intersectionFlags.size())); // This endpoint intersectionFlags.push_back(IntersectionFlags::IS_ENDPOINT); } - _memory.WritePanelData(id, NUM_DOTS, {static_cast(intersectionFlags.size())}); - _memory.WriteArray(id, DOT_POSITIONS, intersections); - _memory.WriteArray(id, DOT_FLAGS, intersectionFlags); - _memory.WritePanelData(id, NUM_CONNECTIONS, {static_cast(connections.first.size())}); - _memory.WriteArray(id, DOT_CONNECTION_A, connections.first); - _memory.WriteArray(id, DOT_CONNECTION_B, connections.second); - _memory.WritePanelData(id, NEEDS_REDRAW, {1}); + // Dots + for (int y=0; y<_height; y++) { + for (int x=0; x<_width; x++) { + if (!(_grid[x][y] & IntersectionFlags::HAS_DOT)) continue; + if (x%2 == 1 && y%2 == 1) continue; + if (x%2 == 0 && y%2 == 0) { + intersectionFlags[xy_to_loc(x, y)] |= _grid[x][y]; + continue; + } + + // Locate the segment we're breaking + for (int i=0; i(intersectionFlags.size()); // This endpoint + + connections_a.push_back(static_cast(intersectionFlags.size())); // This endpoint + connections_b.push_back(other_connection); + break; + } + } + // Add this dot to the end + double xPos = min + (x/2.0) * width_interval; + double yPos = max - (y/2.0) * height_interval; + intersections.push_back(static_cast(xPos)); + intersections.push_back(static_cast(yPos)); + intersectionFlags.push_back(_grid[x][y]); + } + } + + + _memory->WritePanelData(id, NUM_DOTS, {static_cast(intersectionFlags.size())}); + _memory->WriteArray(id, DOT_POSITIONS, intersections); + _memory->WriteArray(id, DOT_FLAGS, intersectionFlags); + _memory->WritePanelData(id, NUM_CONNECTIONS, {static_cast(connections_a.size())}); + _memory->WriteArray(id, DOT_CONNECTION_A, connections_a); + _memory->WriteArray(id, DOT_CONNECTION_B, connections_b); + _memory->WritePanelData(id, NEEDS_REDRAW, {1}); } diff --git a/Source/Panel.h b/Source/Panel.h index 565b4c3..b8e67df 100644 --- a/Source/Panel.h +++ b/Source/Panel.h @@ -45,7 +45,7 @@ enum IntersectionFlags { IS_ENDPOINT = 0x1, IS_STARTPOINT = 0x2, IS_GAP = 0x10000, - HAS_DOT = 0x20, + HAS_DOT = 0x40020, DOT_IS_BLUE = 0x100, DOT_IS_ORANGE = 0x200, DOT_IS_INVISIBLE = 0x1000, @@ -110,7 +110,7 @@ public: private: // For testing - Panel(); + Panel() = default; void ReadIntersections(int id); void WriteIntersections(int id); @@ -121,8 +121,11 @@ private: // TODO: Decoration colors std::tuple loc_to_xy(int location) { - int x = 2 * (location % ((_width + 1) / 2)); - int y = (_height - 1) - 2 * (location / ((_width + 1) / 2)); + int height2 = (_height - 1) / 2; + int width2 = (_width + 1) / 2; + + int x = 2 * (location % width2); + int y = 2 * (height2 - location / width2); return {x, y}; } @@ -134,7 +137,24 @@ private: return rowsFromBottom * width2 + x/2; } - Memory _memory = Memory("witness64_d3d11.exe"); + std::tuple dloc_to_xy(int location) { + int height2 = (_height - 3) / 2; + int width2 = (_width - 1) / 2; + + int x = 2 * (location % width2) + 1; + int y = 2 * (height2 - location / width2) + 1; + return {x, y}; + } + + int xy_to_dloc(int x, int y) { + int height2 = (_height - 3) / 2; + int width2 = (_width - 1) / 2; + + int rowsFromBottom = height2 - (y - 1)/2; + return rowsFromBottom * width2 + (x - 1)/2; + } + + std::shared_ptr _memory; int _width, _height; diff --git a/Test/PanelExtractionTests.cpp b/Test/PanelExtractionTests.cpp index dfb9b9e..099fab2 100644 --- a/Test/PanelExtractionTests.cpp +++ b/Test/PanelExtractionTests.cpp @@ -4,7 +4,8 @@ class PanelExtractionTests : public testing::Test { protected: - Panel _panel; + // Test constructor, does not attach to process + Panel _panel = Panel(); // std::shared_ptr _panel; void SetPanelSize(int width, int height) { @@ -13,22 +14,88 @@ protected: _panel._height = height; } - std::tuple loc_to_xy(int location) { - return _panel.loc_to_xy(location); - } - - int xy_to_loc(int x, int y) { - return _panel.xy_to_loc(x, y); - } + std::tuple loc_to_xy(int location) {return _panel.loc_to_xy(location);} + int xy_to_loc(int x, int y) {return _panel.xy_to_loc(x, y);} + std::tuple dloc_to_xy(int location) {return _panel.dloc_to_xy(location);} + int xy_to_dloc(int x, int y) {return _panel.xy_to_dloc(x, y);} }; -TEST_F(PanelExtractionTests, LocToXY_7x5) { +TEST_F(PanelExtractionTests, 1x1) { + SetPanelSize(1, 1); + /* Here's the panel, with the correct location order + 0(_width = 1) + (_height = 1) + */ + ASSERT_EQ(0, xy_to_loc(0, 0)); + ASSERT_EQ((std::tuple{0, 0}), loc_to_xy(0)); +} + +TEST_F(PanelExtractionTests, 7x1) { + SetPanelSize(7, 1); + /* Here's the panel, with the correct location order + 3 . 2 . 1 . 0(_width = 7) + (_height = 1) + */ + ASSERT_EQ(0, xy_to_loc(0, 0)); + ASSERT_EQ(1, xy_to_loc(2, 0)); + ASSERT_EQ(2, xy_to_loc(4, 0)); + ASSERT_EQ(3, xy_to_loc(6, 0)); + ASSERT_EQ((std::tuple{0, 0}), loc_to_xy(0)); + ASSERT_EQ((std::tuple{2, 0}), loc_to_xy(1)); + ASSERT_EQ((std::tuple{4, 0}), loc_to_xy(2)); + ASSERT_EQ((std::tuple{6, 0}), loc_to_xy(3)); +} + +TEST_F(PanelExtractionTests, 1x7) { + SetPanelSize(1, 7); + /* Here's the panel, with the correct location order + 3(_width = 1) + . + 2 + . + 1 + . + 0 + (_height = 7) + */ + ASSERT_EQ(0, xy_to_loc(0, 6)); + ASSERT_EQ(1, xy_to_loc(0, 4)); + ASSERT_EQ(2, xy_to_loc(0, 2)); + ASSERT_EQ(3, xy_to_loc(0, 0)); + ASSERT_EQ((std::tuple{0, 6}), loc_to_xy(0)); + ASSERT_EQ((std::tuple{0, 4}), loc_to_xy(1)); + ASSERT_EQ((std::tuple{0, 2}), loc_to_xy(2)); + ASSERT_EQ((std::tuple{0, 0}), loc_to_xy(3)); +} + +TEST_F(PanelExtractionTests, 3x3) { + SetPanelSize(3, 3); + /* Here's the panel, with the correct location order + 2 . 3 (_width = 3) + . A . + 0 . 1 + (_height = 3) + */ + ASSERT_EQ(0, xy_to_loc(0, 2)); + ASSERT_EQ(1, xy_to_loc(2, 2)); + ASSERT_EQ(2, xy_to_loc(0, 0)); + ASSERT_EQ(3, xy_to_loc(2, 0)); + ASSERT_EQ((std::tuple{0, 2}), loc_to_xy(0)); + ASSERT_EQ((std::tuple{2, 2}), loc_to_xy(1)); + ASSERT_EQ((std::tuple{0, 0}), loc_to_xy(2)); + ASSERT_EQ((std::tuple{2, 0}), loc_to_xy(3)); + + ASSERT_EQ(0, xy_to_dloc(1, 1)); + ASSERT_EQ((std::tuple{1, 1}), dloc_to_xy(0)); +} + +TEST_F(PanelExtractionTests, 7x5) { SetPanelSize(7, 5); /* Here's the panel, with the correct location order 8 . 9 . 10. 11 (_width = 7) - . . . . . . . + . D . E . F . 4 . 5 . 6 . 7 - . . . . . . . + . A . B . C . 0 . 1 . 2 . 3 (_height = 5) */ @@ -36,28 +103,26 @@ TEST_F(PanelExtractionTests, LocToXY_7x5) { ASSERT_EQ(1, xy_to_loc(2, 4)); ASSERT_EQ(2, xy_to_loc(4, 4)); ASSERT_EQ(3, xy_to_loc(6, 4)); + ASSERT_EQ((std::tuple{0, 4}), loc_to_xy(0)); + ASSERT_EQ((std::tuple{2, 4}), loc_to_xy(1)); + ASSERT_EQ((std::tuple{4, 4}), loc_to_xy(2)); + ASSERT_EQ((std::tuple{6, 4}), loc_to_xy(3)); ASSERT_EQ(4, xy_to_loc(0, 2)); ASSERT_EQ(5, xy_to_loc(2, 2)); ASSERT_EQ(6, xy_to_loc(4, 2)); ASSERT_EQ(7, xy_to_loc(6, 2)); + ASSERT_EQ((std::tuple{0, 2}), loc_to_xy(4)); + ASSERT_EQ((std::tuple{2, 2}), loc_to_xy(5)); + ASSERT_EQ((std::tuple{4, 2}), loc_to_xy(6)); + ASSERT_EQ((std::tuple{6, 2}), loc_to_xy(7)); - ASSERT_EQ(8, xy_to_loc(0, 0)); - ASSERT_EQ(9, xy_to_loc(2, 0)); + ASSERT_EQ(8, xy_to_loc(0, 0)); + ASSERT_EQ(9, xy_to_loc(2, 0)); ASSERT_EQ(10, xy_to_loc(4, 0)); ASSERT_EQ(11, xy_to_loc(6, 0)); + ASSERT_EQ((std::tuple{0, 0}), loc_to_xy(8)); + ASSERT_EQ((std::tuple{2, 0}), loc_to_xy(9)); + ASSERT_EQ((std::tuple{4, 0}), loc_to_xy(10)); + ASSERT_EQ((std::tuple{6, 0}), loc_to_xy(11)); } - -TEST_F(PanelExtractionTests, LocToXY_3x3) { - SetPanelSize(3, 3); - /* Here's the panel, with the correct location order - 2 . 3 (_width = 3) - . . . - 0 . 1 - (_height = 3) - */ - ASSERT_EQ(0, xy_to_loc(0, 2)); - ASSERT_EQ(1, xy_to_loc(2, 2)); - ASSERT_EQ(2, xy_to_loc(0, 0)); - ASSERT_EQ(3, xy_to_loc(2, 0)); -} \ No newline at end of file -- cgit 1.4.1