1+ /*
2+ * Copyright 2025 Lambda
3+ *
4+ * This program is free software: you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation, either version 3 of the License, or
7+ * (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+ package com.lambda.util
19+
20+ import com.lambda.util.GraphUtil.n6
21+ import com.lambda.util.GraphUtil.n18
22+ import com.lambda.util.GraphUtil.n26
23+ import com.lambda.util.GraphUtil.neighborhood
24+ import com.lambda.util.world.FastVector
25+ import com.lambda.util.world.fastVectorOf
26+ import kotlin.math.sqrt
27+ import kotlin.test.Test
28+ import kotlin.test.assertEquals
29+ import kotlin.test.assertTrue
30+
31+ /* *
32+ * Unit tests for the neighbor functions in GraphUtil.
33+ */
34+ class GraphUtilTest {
35+
36+ /* *
37+ * Test for n6 function which should return 6-connectivity neighbors
38+ * (only axis-aligned moves).
39+ */
40+ @Test
41+ fun `test n6 connectivity` () {
42+ val origin = fastVectorOf(0 , 0 , 0 )
43+ val neighbors = n6(origin)
44+
45+ // Should have exactly 6 neighbors
46+ assertEquals(6 , neighbors.size, " n6 should return exactly 6 neighbors" )
47+
48+ // Expected neighbors (axis-aligned)
49+ val expectedNeighbors = setOf (
50+ fastVectorOf(1 , 0 , 0 ),
51+ fastVectorOf(- 1 , 0 , 0 ),
52+ fastVectorOf(0 , 1 , 0 ),
53+ fastVectorOf(0 , - 1 , 0 ),
54+ fastVectorOf(0 , 0 , 1 ),
55+ fastVectorOf(0 , 0 , - 1 )
56+ )
57+
58+ // Check that all expected neighbors are present
59+ for (neighbor in expectedNeighbors) {
60+ assertTrue(neighbor in neighbors.keys, " Expected neighbor $neighbor not found" )
61+ assertEquals(1.0 , neighbors[neighbor], " Cost for axis-aligned neighbor should be 1.0" )
62+ }
63+ }
64+
65+ /* *
66+ * Test for n18 function which should return 18-connectivity neighbors
67+ * (axis-aligned + face diagonal moves).
68+ */
69+ @Test
70+ fun `test n18 connectivity` () {
71+ val origin = fastVectorOf(0 , 0 , 0 )
72+ val neighbors = n18(origin)
73+
74+ // Should have exactly 18 neighbors
75+ assertEquals(18 , neighbors.size, " n18 should return exactly 18 neighbors" )
76+
77+ // Expected axis-aligned neighbors (6)
78+ val expectedAxisNeighbors = setOf (
79+ fastVectorOf(1 , 0 , 0 ),
80+ fastVectorOf(- 1 , 0 , 0 ),
81+ fastVectorOf(0 , 1 , 0 ),
82+ fastVectorOf(0 , - 1 , 0 ),
83+ fastVectorOf(0 , 0 , 1 ),
84+ fastVectorOf(0 , 0 , - 1 )
85+ )
86+
87+ // Expected face diagonal neighbors (12)
88+ val expectedFaceDiagonalNeighbors = setOf (
89+ // XY plane diagonals
90+ fastVectorOf(1 , 1 , 0 ),
91+ fastVectorOf(1 , - 1 , 0 ),
92+ fastVectorOf(- 1 , 1 , 0 ),
93+ fastVectorOf(- 1 , - 1 , 0 ),
94+ // XZ plane diagonals
95+ fastVectorOf(1 , 0 , 1 ),
96+ fastVectorOf(1 , 0 , - 1 ),
97+ fastVectorOf(- 1 , 0 , 1 ),
98+ fastVectorOf(- 1 , 0 , - 1 ),
99+ // YZ plane diagonals
100+ fastVectorOf(0 , 1 , 1 ),
101+ fastVectorOf(0 , 1 , - 1 ),
102+ fastVectorOf(0 , - 1 , 1 ),
103+ fastVectorOf(0 , - 1 , - 1 )
104+ )
105+
106+ // Check that all expected axis-aligned neighbors are present
107+ for (neighbor in expectedAxisNeighbors) {
108+ assertTrue(neighbor in neighbors.keys, " Expected axis-aligned neighbor $neighbor not found" )
109+ assertEquals(1.0 , neighbors[neighbor], " Cost for axis-aligned neighbor should be 1.0" )
110+ }
111+
112+ // Check that all expected face diagonal neighbors are present
113+ for (neighbor in expectedFaceDiagonalNeighbors) {
114+ assertTrue(neighbor in neighbors.keys, " Expected face diagonal neighbor $neighbor not found" )
115+ assertEquals(sqrt(2.0 ), neighbors[neighbor], " Cost for face diagonal neighbor should be sqrt(2.0)" )
116+ }
117+ }
118+
119+ /* *
120+ * Test for n26 function which should return 26-connectivity neighbors
121+ * (axis-aligned + face diagonal + cube diagonal moves).
122+ */
123+ @Test
124+ fun `test n26 connectivity` () {
125+ val origin = fastVectorOf(0 , 0 , 0 )
126+ val neighbors = n26(origin)
127+
128+ // Should have exactly 26 neighbors
129+ assertEquals(26 , neighbors.size, " n26 should return exactly 26 neighbors" )
130+
131+ // Expected axis-aligned neighbors (6)
132+ val expectedAxisNeighbors = setOf (
133+ fastVectorOf(1 , 0 , 0 ),
134+ fastVectorOf(- 1 , 0 , 0 ),
135+ fastVectorOf(0 , 1 , 0 ),
136+ fastVectorOf(0 , - 1 , 0 ),
137+ fastVectorOf(0 , 0 , 1 ),
138+ fastVectorOf(0 , 0 , - 1 )
139+ )
140+
141+ // Expected face diagonal neighbors (12)
142+ val expectedFaceDiagonalNeighbors = setOf (
143+ // XY plane diagonals
144+ fastVectorOf(1 , 1 , 0 ),
145+ fastVectorOf(1 , - 1 , 0 ),
146+ fastVectorOf(- 1 , 1 , 0 ),
147+ fastVectorOf(- 1 , - 1 , 0 ),
148+ // XZ plane diagonals
149+ fastVectorOf(1 , 0 , 1 ),
150+ fastVectorOf(1 , 0 , - 1 ),
151+ fastVectorOf(- 1 , 0 , 1 ),
152+ fastVectorOf(- 1 , 0 , - 1 ),
153+ // YZ plane diagonals
154+ fastVectorOf(0 , 1 , 1 ),
155+ fastVectorOf(0 , 1 , - 1 ),
156+ fastVectorOf(0 , - 1 , 1 ),
157+ fastVectorOf(0 , - 1 , - 1 )
158+ )
159+
160+ // Expected cube diagonal neighbors (8)
161+ val expectedCubeDiagonalNeighbors = setOf (
162+ fastVectorOf(1 , 1 , 1 ),
163+ fastVectorOf(1 , 1 , - 1 ),
164+ fastVectorOf(1 , - 1 , 1 ),
165+ fastVectorOf(1 , - 1 , - 1 ),
166+ fastVectorOf(- 1 , 1 , 1 ),
167+ fastVectorOf(- 1 , 1 , - 1 ),
168+ fastVectorOf(- 1 , - 1 , 1 ),
169+ fastVectorOf(- 1 , - 1 , - 1 )
170+ )
171+
172+ // Check that all expected axis-aligned neighbors are present
173+ for (neighbor in expectedAxisNeighbors) {
174+ assertTrue(neighbor in neighbors.keys, " Expected axis-aligned neighbor $neighbor not found" )
175+ assertEquals(1.0 , neighbors[neighbor], " Cost for axis-aligned neighbor should be 1.0" )
176+ }
177+
178+ // Check that all expected face diagonal neighbors are present
179+ for (neighbor in expectedFaceDiagonalNeighbors) {
180+ assertTrue(neighbor in neighbors.keys, " Expected face diagonal neighbor $neighbor not found" )
181+ assertEquals(sqrt(2.0 ), neighbors[neighbor], " Cost for face diagonal neighbor should be sqrt(2.0)" )
182+ }
183+
184+ // Check that all expected cube diagonal neighbors are present
185+ for (neighbor in expectedCubeDiagonalNeighbors) {
186+ assertTrue(neighbor in neighbors.keys, " Expected cube diagonal neighbor $neighbor not found" )
187+ assertEquals(sqrt(3.0 ), neighbors[neighbor], " Cost for cube diagonal neighbor should be sqrt(3.0)" )
188+ }
189+ }
190+
191+ /* *
192+ * Test for the neighborhood function with custom distance parameters.
193+ */
194+ @Test
195+ fun `test neighborhood with custom parameters` () {
196+ val origin = fastVectorOf(0 , 0 , 0 )
197+
198+ // Test with minDistSq=2, maxDistSq=2 (should only return face diagonals)
199+ val faceDiagonalNeighbors = neighborhood(origin, minDistSq = 2 , maxDistSq = 2 )
200+ assertEquals(12 , faceDiagonalNeighbors.size, " Should return exactly 12 face diagonal neighbors" )
201+
202+ // Test with minDistSq=3, maxDistSq=3 (should only return cube diagonals)
203+ val cubeDiagonalNeighbors = neighborhood(origin, minDistSq = 3 , maxDistSq = 3 )
204+ assertEquals(8 , cubeDiagonalNeighbors.size, " Should return exactly 8 cube diagonal neighbors" )
205+
206+ // Test with minDistSq=1, maxDistSq=3 (should return all neighbors, same as n26)
207+ val allNeighbors = neighborhood(origin, minDistSq = 1 , maxDistSq = 3 )
208+ assertEquals(26 , allNeighbors.size, " Should return exactly 26 neighbors (same as n26)" )
209+
210+ // Test with invalid range (should return empty map)
211+ val emptyNeighbors = neighborhood(origin, minDistSq = 4 , maxDistSq = 5 )
212+ assertEquals(0 , emptyNeighbors.size, " Should return empty map for invalid distance range" )
213+ }
214+
215+ /* *
216+ * Test for the neighborhood function with non-origin center point.
217+ */
218+ @Test
219+ fun `test neighborhood with non-origin center` () {
220+ val center = fastVectorOf(10 , 20 , 30 )
221+ val neighbors = n6(center)
222+
223+ // Should have exactly 6 neighbors
224+ assertEquals(6 , neighbors.size, " n6 should return exactly 6 neighbors" )
225+
226+ // Expected neighbors (axis-aligned)
227+ val expectedNeighbors = setOf (
228+ fastVectorOf(11 , 20 , 30 ),
229+ fastVectorOf(9 , 20 , 30 ),
230+ fastVectorOf(10 , 21 , 30 ),
231+ fastVectorOf(10 , 19 , 30 ),
232+ fastVectorOf(10 , 20 , 31 ),
233+ fastVectorOf(10 , 20 , 29 )
234+ )
235+
236+ // Check that all expected neighbors are present
237+ for (neighbor in expectedNeighbors) {
238+ assertTrue(neighbor in neighbors.keys, " Expected neighbor $neighbor not found" )
239+ assertEquals(1.0 , neighbors[neighbor], " Cost for axis-aligned neighbor should be 1.0" )
240+ }
241+ }
242+ }
0 commit comments