Index: ps/trunk/source/lib/file/archive/disabled_tests/test_codec_zlib.h =================================================================== --- ps/trunk/source/lib/file/archive/disabled_tests/test_codec_zlib.h (revision 26011) +++ ps/trunk/source/lib/file/archive/disabled_tests/test_codec_zlib.h (revision 26012) @@ -1,81 +1,85 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "lib/self_test.h" #include "lib/self_test.h" #include "lib/res/file/archive/codec_zlib.h" +#include + class TestCodecZLib : public CxxTest::TestSuite { public: void test_compress_decompress_compare() { size_t inConsumed, outProduced; u32 checksum; // generate random input udata // (limit values to 0..7 so that the udata will actually be compressible) + std::mt19937 engine(42); + std::uniform_int_distribution distribution(0x00, 0x07); const size_t usize = 10000; u8 udata[usize]; for(size_t i = 0; i < usize; i++) - udata[i] = rand() & 0x07; + udata[i] = distribution(engine); // compress u8* cdata; size_t csize; { boost::shared_ptr compressor_zlib = CreateCompressor_ZLib(); ICodec* c = compressor_zlib.get(); const size_t csizeMax = c->MaxOutputSize(usize); cdata = new u8[csizeMax]; TS_ASSERT_OK(c->Process(udata, usize, cdata, csizeMax, inConsumed, outProduced)); TS_ASSERT_EQUALS(inConsumed, usize); TS_ASSERT_LESS_THAN_EQUALS(outProduced, csizeMax); u8* cdata2; TS_ASSERT_OK(c->Finish(cdata2, csize, checksum)); TS_ASSERT_EQUALS(cdata, cdata2); TS_ASSERT_EQUALS(csize, outProduced); } // make sure the data changed during compression TS_ASSERT(csize != usize || memcmp(udata, cdata, std::min(usize, csize)) != 0); // decompress u8 ddata[usize]; { boost::shared_ptr decompressor_zlib = CreateDecompressor_ZLib(); ICodec* d = decompressor_zlib.get(); TS_ASSERT_OK(decompressor_zlib->Process(cdata, csize, ddata, usize, inConsumed, outProduced)); TS_ASSERT_EQUALS(inConsumed, csize); // ZLib always outputs as much data as possible TS_ASSERT_EQUALS(outProduced, usize); // .. so these figures are correct before Finish() u8* ddata2; size_t dsize; TS_ASSERT_OK(d->Finish(&ddata2, &dsize, &checksum)); TS_ASSERT_EQUALS(ddata, ddata2); TS_ASSERT_EQUALS(dsize, outProduced); } // verify udata survived intact TS_ASSERT_SAME_DATA(udata, ddata, usize); delete[] cdata; } }; Index: ps/trunk/source/lib/file/archive/disabled_tests/test_compression.h =================================================================== --- ps/trunk/source/lib/file/archive/disabled_tests/test_compression.h (revision 26011) +++ ps/trunk/source/lib/file/archive/disabled_tests/test_compression.h (revision 26012) @@ -1,76 +1,80 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "lib/self_test.h" #include "lib/self_test.h" #include "lib/res/file/archive/compression.h" +#include + class TestCompression : public CxxTest::TestSuite { public: void test_compress_decompress_compare() { // generate random input data // (limit values to 0..7 so that the data will actually be compressible) + std::mt19937 engine(42); + std::uniform_int_distribution distribution(0x00, 0x07); const size_t data_size = 10000; u8 data[data_size]; for(size_t i = 0; i < data_size; i++) - data[i] = rand() & 0x07; + data[i] = distribution(engine); u8* cdata; size_t csize; u8 udata[data_size]; // compress uintptr_t c = comp_alloc(CT_COMPRESSION, CM_DEFLATE); { TS_ASSERT(c != 0); const size_t csizeBound = comp_max_output_size(c, data_size); TS_ASSERT_OK(comp_alloc_output(c, csizeBound)); const ssize_t cdata_produced = comp_feed(c, data, data_size); TS_ASSERT(cdata_produced >= 0); u32 checksum; TS_ASSERT_OK(comp_finish(c, &cdata, &csize, &checksum)); TS_ASSERT(cdata_produced <= (ssize_t)csize); // can't have produced more than total } // decompress uintptr_t d = comp_alloc(CT_DECOMPRESSION, CM_DEFLATE); { TS_ASSERT(d != 0); comp_set_output(d, udata, data_size); const ssize_t udata_produced = comp_feed(d, cdata, csize); TS_ASSERT(udata_produced >= 0); u8* udata_final; size_t usize_final; u32 checksum; TS_ASSERT_OK(comp_finish(d, &udata_final, &usize_final, &checksum)); TS_ASSERT(udata_produced <= (ssize_t)usize_final); // can't have produced more than total TS_ASSERT_EQUALS(udata_final, udata); // output buffer address is same TS_ASSERT_EQUALS(usize_final, data_size); // correct amount of output } comp_free(c); comp_free(d); // verify data survived intact TS_ASSERT_SAME_DATA(data, udata, data_size); } }; Index: ps/trunk/source/lib/tests/test_adts.h =================================================================== --- ps/trunk/source/lib/tests/test_adts.h (revision 26011) +++ ps/trunk/source/lib/tests/test_adts.h (revision 26012) @@ -1,98 +1,102 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "lib/self_test.h" #include "lib/adts/ring_buf.h" -#include "lib/rand.h" + +#include class TestRingbuf : public CxxTest::TestSuite { static const size_t N = 49; // RingBuf capacity static const int S = 100; // number of test items public: void test_insert_remove() { RingBuf buf; for(int i = 1; i < S; i++) { buf.push_back(i); TS_ASSERT_EQUALS(buf.front(), i); buf.pop_front(); } TS_ASSERT(buf.size() == 0 && buf.empty()); } void test_fill_overwrite_old() { RingBuf buf; for(int i = 1; i < S; i++) buf.push_back(i); TS_ASSERT_EQUALS(buf.size(), N); int first = buf.front(); TS_ASSERT_EQUALS(first, (int)(S-1 -N +1)); for(size_t i = 0; i < N; i++) { TS_ASSERT_EQUALS(buf.front(), first); first++; buf.pop_front(); } TS_ASSERT(buf.size() == 0 && buf.empty()); } void test_randomized_insert_remove() { - srand(1); + std::mt19937 engine(42); + std::uniform_int_distribution distributionProbability(0, 9); + std::uniform_int_distribution distributionValue(0); + RingBuf buf; std::deque deq; for(size_t rep = 0; rep < 1000; rep++) { - size_t rnd_op = rand(0, 10); + const size_t rnd_op = distributionProbability(engine); // 70% - insert if(rnd_op >= 3) { - int item = rand(); + int item = distributionValue(engine); buf.push_back(item); deq.push_back(item); int excess_items = (int)deq.size() - N; if(excess_items > 0) { for(int i = 0; i < excess_items; i++) { deq.pop_front(); } } } // 30% - pop front (only if not empty) else if(!deq.empty()) { buf.pop_front(); deq.pop_front(); } TS_ASSERT_EQUALS(buf.size(), deq.size()); RingBuf::iterator begin = buf.begin(), end = buf.end(); TS_ASSERT(std::equal(begin, end, deq.begin())); } } }; Index: ps/trunk/source/maths/tests/test_Matrix3d.h =================================================================== --- ps/trunk/source/maths/tests/test_Matrix3d.h (revision 26011) +++ ps/trunk/source/maths/tests/test_Matrix3d.h (revision 26012) @@ -1,164 +1,175 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "lib/self_test.h" -#include -#include #include "maths/Matrix3D.h" #include "maths/Quaternion.h" +#include +#include +#include + class TestMatrix : public CxxTest::TestSuite { + std::mt19937 m_Engine; + public: + void setUp() + { + m_Engine = std::mt19937(42); + } + void test_inverse() { CMatrix3D m; - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (int i = 0; i < 4; ++i) { for (int j = 0; j < 16; ++j) { - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); } CMatrix3D n; m.GetInverse(n); m *= n; // verify identity has 1s on diagonal and 0 otherwise for (int x = 0; x < 4; ++x) { for (int y = 0; y < 4; ++y) { const float expected = (x==y)? 1.0f : 0.0f; TS_ASSERT_DELTA(m(x,y), expected, 0.0002f); } } } } void test_quats() { - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (int i = 0; i < 4; ++i) { CQuaternion q; q.FromEulerAngles( - -6.28f + 12.56f*(rand()/(float)RAND_MAX), - -6.28f + 12.56f*(rand()/(float)RAND_MAX), - -6.28f + 12.56f*(rand()/(float)RAND_MAX) + -6.28f + 12.56f * distribution01(m_Engine), + -6.28f + 12.56f * distribution01(m_Engine), + -6.28f + 12.56f * distribution01(m_Engine) ); CMatrix3D m; q.ToMatrix(m); CQuaternion q2 = m.GetRotation(); // Quaternions (x,y,z,w) and (-x,-y,-z,-w) are equivalent when // interpreted as rotations, so it doesn't matter which we get const bool ok_oneway = feq(q2.m_W, q.m_W) && feq(q2.m_V.X, q.m_V.X) && feq(q2.m_V.Y, q.m_V.Y) && feq(q2.m_V.Z, q.m_V.Z); const bool ok_otherway = feq(q2.m_W, -q.m_W) && feq(q2.m_V.X, -q.m_V.X) && feq(q2.m_V.Y, -q.m_V.Y) && feq(q2.m_V.Z, -q.m_V.Z); TS_ASSERT(ok_oneway ^ ok_otherway); } } void test_rotate() { - CMatrix3D m; - srand(0); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; for (int j = 0; j < 16; ++j) - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); CMatrix3D r, a, b; a = m; b = m; a.RotateX(1.0f); r.SetXRotation(1.0f); b.Concatenate(r); for (int x = 0; x < 4; ++x) for (int y = 0; y < 4; ++y) TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f); a = m; b = m; a.RotateY(1.0f); r.SetYRotation(1.0f); b.Concatenate(r); for (int x = 0; x < 4; ++x) for (int y = 0; y < 4; ++y) TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f); a = m; b = m; a.RotateZ(1.0f); r.SetZRotation(1.0f); b.Concatenate(r); for (int x = 0; x < 4; ++x) for (int y = 0; y < 4; ++y) TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f); } void test_getRotation() { + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; - srand(0); m.SetZero(); TS_ASSERT_EQUALS(m.GetYRotation(), 0.f); m.SetIdentity(); TS_ASSERT_EQUALS(m.GetYRotation(), 0.f); for (int j = 0; j < 16; ++j) { - float a = 2*M_PI*rand()/(float)RAND_MAX - M_PI; + float a = 2 * M_PI * distribution01(m_Engine) - M_PI; m.SetYRotation(a); TS_ASSERT_DELTA(m.GetYRotation(), a, 0.001f); } } void test_scale() { + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); + CMatrix3D m; - srand(0); for (int j = 0; j < 16; ++j) - m._data[j] = -1.0f + 2.0f*(rand()/(float)RAND_MAX); + m._data[j] = -1.0f + 2.0f * distribution01(m_Engine); CMatrix3D s, a, b; a = m; b = m; a.Scale(0.5f, 2.0f, 3.0f); s.SetScaling(0.5f, 2.0f, 3.0f); b.Concatenate(s); for (int x = 0; x < 4; ++x) for (int y = 0; y < 4; ++y) TS_ASSERT_DELTA(a(x,y), b(x,y), 0.0002f); } }; Index: ps/trunk/source/simulation2/components/tests/test_Pathfinder.h =================================================================== --- ps/trunk/source/simulation2/components/tests/test_Pathfinder.h (revision 26011) +++ ps/trunk/source/simulation2/components/tests/test_Pathfinder.h (revision 26012) @@ -1,431 +1,435 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "simulation2/system/ComponentTest.h" #include "simulation2/components/ICmpObstructionManager.h" #include "simulation2/components/ICmpPathfinder.h" #include "simulation2/helpers/Grid.h" #include "graphics/MapReader.h" #include "graphics/Terrain.h" #include "graphics/TerrainTextureManager.h" #include "lib/timer.h" #include "lib/tex/tex.h" #include "ps/Loader.h" #include "ps/Pyrogenesis.h" #include "scriptinterface/ScriptContext.h" #include "simulation2/Simulation2.h" #include +#include class TestCmpPathfinder : public CxxTest::TestSuite { public: void setUp() { g_VFS = CreateVfs(); g_VFS->Mount(L"", DataDir() / "mods" / "mod" / "", VFS_MOUNT_MUST_EXIST); g_VFS->Mount(L"", DataDir() / "mods" / "public" / "", VFS_MOUNT_MUST_EXIST, 1); // ignore directory-not-found errors TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir() / "_testcache" / "", 0, VFS_MAX_PRIORITY)); CXeromyces::Startup(); // Need some stuff for terrain movement costs: // (TODO: this ought to be independent of any graphics code) new CTerrainTextureManager; g_TexMan.LoadTerrainTextures(); } void tearDown() { delete &g_TexMan; CXeromyces::Terminate(); g_VFS.reset(); DeleteDirectory(DataDir()/"_testcache"); } void test_namespace() { // Check that Pathfinding::NAVCELL_SIZE is actually an integer and that the definitions // of Pathfinding::NAVCELL_SIZE_INT and Pathfinding::NAVCELL_SIZE_LOG2 match TS_ASSERT_EQUALS(Pathfinding::NAVCELL_SIZE.ToInt_RoundToNegInfinity(), Pathfinding::NAVCELL_SIZE.ToInt_RoundToInfinity()); TS_ASSERT_EQUALS(Pathfinding::NAVCELL_SIZE.ToInt_RoundToNearest(), Pathfinding::NAVCELL_SIZE_INT); TS_ASSERT_EQUALS((Pathfinding::NAVCELL_SIZE >> 1).ToInt_RoundToZero(), Pathfinding::NAVCELL_SIZE_LOG2); } void test_pathgoal_nearest_distance() { entity_pos_t i = Pathfinding::NAVCELL_SIZE; CFixedVector2D u(i*1, i*0); CFixedVector2D v(i*0, i*1); { PathGoal goal = { PathGoal::POINT, i*8, i*6 }; TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*6); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*2); TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*8 + v*6); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*10); TS_ASSERT(goal.RectContainsGoal(i*4, i*3, i*12, i*9)); TS_ASSERT(goal.RectContainsGoal(i*4, i*3, i*8, i*6)); TS_ASSERT(goal.RectContainsGoal(i*8, i*6, i*12, i*9)); TS_ASSERT(!goal.RectContainsGoal(i*4, i*3, i*7, i*5)); TS_ASSERT(!goal.RectContainsGoal(i*9, i*7, i*13, i*15)); } { PathGoal goal = { PathGoal::CIRCLE, i*8, i*6, i*5 }; TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*4); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*0); TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*4 + v*3); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*5); TS_ASSERT(goal.RectContainsGoal(i*7, i*5, i*9, i*7)); // fully inside TS_ASSERT(goal.RectContainsGoal(i*3, i*1, i*13, i*11)); // fully outside TS_ASSERT(goal.RectContainsGoal(i*4, i*3, i*8, i*6)); // partially inside TS_ASSERT(goal.RectContainsGoal(i*4, i*0, i*12, i*1)); // touching the edge } { PathGoal goal = { PathGoal::INVERTED_CIRCLE, i*8, i*6, i*5 }; TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*1); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*3); TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*0 + v*0); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*0); TS_ASSERT(!goal.RectContainsGoal(i*7, i*5, i*9, i*7)); // fully inside TS_ASSERT(goal.RectContainsGoal(i*3, i*1, i*13, i*11)); // fully outside TS_ASSERT(goal.RectContainsGoal(i*4, i*3, i*8, i*6)); // partially inside TS_ASSERT(goal.RectContainsGoal(i*4, i*0, i*12, i*1)); // touching the edge } { PathGoal goal = { PathGoal::SQUARE, i*8, i*6, i*4, i*3, u, v }; TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*4); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*0); TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*4 + v*3); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*5); TS_ASSERT(goal.RectContainsGoal(i*7, i*5, i*9, i*7)); // fully inside TS_ASSERT(goal.RectContainsGoal(i*3, i*1, i*13, i*11)); // fully outside TS_ASSERT(goal.RectContainsGoal(i*4, i*3, i*8, i*6)); // partially inside TS_ASSERT(goal.RectContainsGoal(i*4, i*2, i*12, i*3)); // touching the edge TS_ASSERT(goal.RectContainsGoal(i*3, i*0, i*4, i*10)); // touching the edge } { PathGoal goal = { PathGoal::INVERTED_SQUARE, i*8, i*6, i*4, i*3, u, v }; TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*8 + v*4), u*8 + v*3); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*8 + v*4), i*1); TS_ASSERT_EQUALS(goal.NearestPointOnGoal(u*0 + v*0), u*0 + v*0); TS_ASSERT_EQUALS(goal.DistanceToPoint(u*0 + v*0), i*0); TS_ASSERT(!goal.RectContainsGoal(i*7, i*5, i*9, i*7)); // fully inside TS_ASSERT(goal.RectContainsGoal(i*3, i*1, i*13, i*11)); // fully outside TS_ASSERT(!goal.RectContainsGoal(i*4, i*3, i*8, i*6)); // inside, touching (should fail) TS_ASSERT(goal.RectContainsGoal(i*4, i*2, i*12, i*3)); // touching the edge TS_ASSERT(goal.RectContainsGoal(i*3, i*0, i*4, i*10)); // touching the edge } } void test_performance_DISABLED() { CTerrain terrain; CSimulation2 sim2(NULL, g_ScriptContext, &terrain); sim2.LoadDefaultScripts(); sim2.ResetState(); std::unique_ptr mapReader = std::make_unique(); LDR_BeginRegistering(); mapReader->LoadMap(L"maps/skirmishes/Median Oasis (2).pmp", *sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue, &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &sim2, &sim2.GetSimContext(), -1, false); LDR_EndRegistering(); TS_ASSERT_OK(LDR_NonprogressiveLoad()); sim2.PreInitGame(); sim2.InitGame(); sim2.Update(0); CmpPtr cmp(sim2, SYSTEM_ENTITY); #if 0 entity_pos_t x0 = entity_pos_t::FromInt(10); entity_pos_t z0 = entity_pos_t::FromInt(495); entity_pos_t x1 = entity_pos_t::FromInt(500); entity_pos_t z1 = entity_pos_t::FromInt(495); ICmpPathfinder::Goal goal = { ICmpPathfinder::Goal::POINT, x1, z1 }; WaypointPath path; cmp->ComputePath(x0, z0, goal, cmp->GetPassabilityClass("default"), path); for (size_t i = 0; i < path.m_Waypoints.size(); ++i) printf("%d: %f %f\n", (int)i, path.m_Waypoints[i].x.ToDouble(), path.m_Waypoints[i].z.ToDouble()); #endif double t = timer_Time(); - srand(1234); + std::mt19937 engine(42); + std::uniform_int_distribution distribution511(0, 511); + std::uniform_int_distribution distribution63(0, 63); for (size_t j = 0; j < 1024*2; ++j) { - entity_pos_t x0 = entity_pos_t::FromInt(rand() % 512); - entity_pos_t z0 = entity_pos_t::FromInt(rand() % 512); - entity_pos_t x1 = x0 + entity_pos_t::FromInt(rand() % 64); - entity_pos_t z1 = z0 + entity_pos_t::FromInt(rand() % 64); + entity_pos_t x0 = entity_pos_t::FromInt(distribution511(engine)); + entity_pos_t z0 = entity_pos_t::FromInt(distribution511(engine)); + entity_pos_t x1 = x0 + entity_pos_t::FromInt(distribution63(engine)); + entity_pos_t z1 = z0 + entity_pos_t::FromInt(distribution63(engine)); PathGoal goal = { PathGoal::POINT, x1, z1 }; WaypointPath path; cmp->ComputePathImmediate(x0, z0, goal, cmp->GetPassabilityClass("default"), path); } t = timer_Time() - t; printf("[%f]", t); } void test_performance_short_DISABLED() { CTerrain terrain; terrain.Initialize(5, NULL); CSimulation2 sim2(NULL, g_ScriptContext, &terrain); sim2.LoadDefaultScripts(); sim2.ResetState(); const entity_pos_t range = entity_pos_t::FromInt(48); CmpPtr cmpObstructionMan(sim2, SYSTEM_ENTITY); CmpPtr cmpPathfinder(sim2, SYSTEM_ENTITY); - srand(0); + std::mt19937 engine(42); + std::uniform_real_distribution distribution01(0.0f, std::nextafter(1.0f, 2.0f)); for (size_t i = 0; i < 200; ++i) { - fixed x = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX); - fixed z = fixed::FromFloat(1.5f*range.ToFloat() * rand()/(float)RAND_MAX); + fixed x = fixed::FromFloat(1.5f*range.ToFloat() * distribution01(engine)); + fixed z = fixed::FromFloat(1.5f*range.ToFloat() * distribution01(engine)); // printf("# %f %f\n", x.ToFloat(), z.ToFloat()); cmpObstructionMan->AddUnitShape(INVALID_ENTITY, x, z, fixed::FromInt(2), 0, INVALID_ENTITY); } PathGoal goal = { PathGoal::POINT, range, range }; WaypointPath path = cmpPathfinder->ComputeShortPathImmediate(ShortPathRequest{ 0, range/3, range/3, fixed::FromInt(2), range, goal, 0, false, 0, 0 }); for (size_t i = 0; i < path.m_Waypoints.size(); ++i) printf("# %d: %f %f\n", (int)i, path.m_Waypoints[i].x.ToFloat(), path.m_Waypoints[i].z.ToFloat()); } template void DumpGrid(std::ostream& stream, const Grid& grid, int mask) { for (u16 j = 0; j < grid.m_H; ++j) { for (u16 i = 0; i < grid.m_W; ) { if (!(grid.get(i, j) & mask)) { i++; continue; } u16 i0 = i; for (i = i0+1; ; ++i) { if (i >= grid.m_W || !(grid.get(i, j) & mask)) { stream << " \n"; break; } } } } } void test_perf2_DISABLED() { CTerrain terrain; CSimulation2 sim2(NULL, g_ScriptContext, &terrain); sim2.LoadDefaultScripts(); sim2.ResetState(); std::unique_ptr mapReader = std::make_unique(); LDR_BeginRegistering(); mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", *sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue, &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &sim2, &sim2.GetSimContext(), -1, false); LDR_EndRegistering(); TS_ASSERT_OK(LDR_NonprogressiveLoad()); sim2.PreInitGame(); sim2.InitGame(); sim2.Update(0); std::ofstream stream(OsString("perf2.html").c_str(), std::ofstream::out | std::ofstream::trunc); CmpPtr cmpObstructionManager(sim2, SYSTEM_ENTITY); CmpPtr cmpPathfinder(sim2, SYSTEM_ENTITY); pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); const Grid& obstructions = cmpPathfinder->GetPassabilityGrid(); int scale = 1; stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << " \n"; DumpGrid(stream, obstructions, obstructionsMask); stream << " \n"; DumpPath(stream, 128*4, 256*4, 128*4, 384*4, cmpPathfinder); // RepeatPath(500, 128*4, 256*4, 128*4, 384*4, cmpPathfinder); // // DumpPath(stream, 128*4, 204*4, 192*4, 204*4, cmpPathfinder); // // DumpPath(stream, 128*4, 230*4, 32*4, 230*4, cmpPathfinder); stream << "\n"; stream << "\n"; } void test_perf3_DISABLED() { CTerrain terrain; CSimulation2 sim2(NULL, g_ScriptContext, &terrain); sim2.LoadDefaultScripts(); sim2.ResetState(); std::unique_ptr mapReader = std::make_unique(); LDR_BeginRegistering(); mapReader->LoadMap(L"maps/scenarios/Peloponnese.pmp", *sim2.GetScriptInterface().GetContext(), JS::UndefinedHandleValue, &terrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &sim2, &sim2.GetSimContext(), -1, false); LDR_EndRegistering(); TS_ASSERT_OK(LDR_NonprogressiveLoad()); sim2.PreInitGame(); sim2.InitGame(); sim2.Update(0); std::ofstream stream(OsString("perf3.html").c_str(), std::ofstream::out | std::ofstream::trunc); CmpPtr cmpObstructionManager(sim2, SYSTEM_ENTITY); CmpPtr cmpPathfinder(sim2, SYSTEM_ENTITY); pass_class_t obstructionsMask = cmpPathfinder->GetPassabilityClass("default"); const Grid& obstructions = cmpPathfinder->GetPassabilityGrid(); int scale = 31; stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << "\n"; stream << " \n"; DumpGrid(stream, obstructions, obstructionsMask); stream << " \n"; for (int j = 160; j < 190; ++j) for (int i = 220; i < 290; ++i) DumpPath(stream, 230, 178, i, j, cmpPathfinder); stream << "\n"; stream << "\n"; stream << "\n"; } void DumpPath(std::ostream& stream, int i0, int j0, int i1, int j1, CmpPtr& cmpPathfinder) { entity_pos_t x0 = entity_pos_t::FromInt(i0); entity_pos_t z0 = entity_pos_t::FromInt(j0); entity_pos_t x1 = entity_pos_t::FromInt(i1); entity_pos_t z1 = entity_pos_t::FromInt(j1); PathGoal goal = { PathGoal::POINT, x1, z1 }; WaypointPath path; cmpPathfinder->ComputePathImmediate(x0, z0, goal, cmpPathfinder->GetPassabilityClass("default"), path); u32 debugSteps; double debugTime; Grid debugGrid; cmpPathfinder->GetDebugData(debugSteps, debugTime, debugGrid); // stream << " \n"; stream << " \n"; // stream << " \n"; // DumpGrid(stream, debugGrid, 1); // stream << " \n"; // stream << " \n"; // DumpGrid(stream, debugGrid, 2); // stream << " \n"; // stream << " \n"; // DumpGrid(stream, debugGrid, 3); // stream << " \n"; stream << " \n"; stream << " \n"; } void RepeatPath(int n, int i0, int j0, int i1, int j1, CmpPtr& cmpPathfinder) { entity_pos_t x0 = entity_pos_t::FromInt(i0); entity_pos_t z0 = entity_pos_t::FromInt(j0); entity_pos_t x1 = entity_pos_t::FromInt(i1); entity_pos_t z1 = entity_pos_t::FromInt(j1); PathGoal goal = { PathGoal::POINT, x1, z1 }; double t = timer_Time(); for (int i = 0; i < n; ++i) { WaypointPath path; cmpPathfinder->ComputePathImmediate(x0, z0, goal, cmpPathfinder->GetPassabilityClass("default"), path); } t = timer_Time() - t; debug_printf("### RepeatPath %fms each (%fs total)\n", 1000*t / n, t); } };