@@ -9,6 +9,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
99import net.minecraft.nbt.CompoundTag
1010import net.minecraft.nbt.Tag
1111import net.minecraft.world.phys.Vec2
12+ import kotlin.jvm.Throws
1213
1314/* *
1415 * Sequence of angles to define a pattern traced.
@@ -130,11 +131,12 @@ data class HexPattern(val startDir: HexDir, val angles: MutableList<HexAngle> =
130131 const val TAG_ANGLES = " angles"
131132
132133 @JvmField
133- val CODEC : Codec <HexPattern > = RecordCodecBuilder .create({instance -> instance.group(
134- Codec .STRING .fieldOf(TAG_START_DIR ).forGetter(HexPattern ::anglesSignature),
135- HexDir .CODEC .fieldOf(TAG_ANGLES ).forGetter(HexPattern ::startDir)
136- ).apply (instance, HexPattern ::fromAngles)
137- })
134+ val CODEC : Codec <HexPattern > = RecordCodecBuilder .create { instance ->
135+ instance.group(
136+ Codec .STRING .fieldOf(TAG_START_DIR ).forGetter(HexPattern ::anglesSignature),
137+ HexDir .CODEC .fieldOf(TAG_ANGLES ).forGetter(HexPattern ::startDir)
138+ ).apply (instance, HexPattern ::fromAnglesUnchecked)
139+ }
138140
139141 @JvmStatic
140142 fun isPattern (tag : CompoundTag ): Boolean {
@@ -149,30 +151,61 @@ data class HexPattern(val startDir: HexDir, val angles: MutableList<HexAngle> =
149151 return HexPattern (startDir, angles.toMutableList())
150152 }
151153
154+ /* *
155+ * Construct a [HexPattern] from an angle signature and starting direction.
156+ *
157+ * Throws if the signature contains an invalid character, or if the resulting pattern would contain overlaps.
158+ */
152159 @JvmStatic
160+ @Throws(IllegalArgumentException ::class , IllegalStateException ::class )
153161 fun fromAngles (signature : String , startDir : HexDir ): HexPattern {
154162 val out = HexPattern (startDir)
163+
164+ var cursor = HexCoord .Origin
155165 var compass = startDir
166+ val linesSeen = mutableSetOf (
167+ cursor to compass,
168+ cursor + compass to compass.rotatedBy(HexAngle .BACK ),
169+ )
156170
157171 for ((idx, c) in signature.withIndex()) {
158- val angle = when (c) {
159- ' w' -> HexAngle .FORWARD
160- ' e' -> HexAngle .RIGHT
161- ' d' -> HexAngle .RIGHT_BACK
162- // for completeness ...
163- ' s' -> HexAngle .BACK
164- ' a' -> HexAngle .LEFT_BACK
165- ' q' -> HexAngle .LEFT
166- else -> throw IllegalArgumentException (" Cannot match $c at idx $idx to a direction" )
167- }
172+ val angle = HexAngle .fromChar(c)
173+ ? : throw IllegalArgumentException (" Cannot match $c at idx $idx to a direction" )
174+
175+ cursor + = compass
168176 compass * = angle
169- val success = out .tryAppendDir(compass)
170- if (! success) {
177+
178+ if (
179+ ! linesSeen.add(cursor to compass)
180+ // Line from here to there also blocks there to here
181+ || ! linesSeen.add(cursor + compass to compass.rotatedBy(HexAngle .BACK ))
182+ ) {
171183 throw IllegalStateException (" Adding the angle $c at index $idx made the pattern invalid by looping back on itself" )
172184 }
185+
186+ out .angles.add(angle)
173187 }
188+
174189 return out
175190 }
176191
192+ /* *
193+ * Construct a [HexPattern] from an angle signature and starting direction, without checking for overlaps.
194+ *
195+ * Throws if the signature contains an invalid character.
196+ */
197+ @JvmStatic
198+ @Throws(IllegalArgumentException ::class )
199+ fun fromAnglesUnchecked (signature : String , startDir : HexDir ): HexPattern {
200+ val out = HexPattern (startDir)
201+
202+ for ((idx, c) in signature.withIndex()) {
203+ val angle = HexAngle .fromChar(c)
204+ ? : throw IllegalArgumentException (" Cannot match $c at idx $idx to a direction" )
205+ out .angles.add(angle)
206+ }
207+
208+ return out
209+ }
177210 }
178211}
0 commit comments