mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
test: pin avatar work to the reference implementation's golden vectors
§8.10 says its two reference implementations are "pinned to one set of golden vectors". We had not checked against them — the ladder was computed from the section's pseudocode, which is the same text both implementations read, so agreement proved nothing about agreement with them. These are that set, from tests/fixtures/avatar_work.json in cyberspace-cli (MIT). All eight pass. The one that earns its place is "half gibson, ticks": a vertex of [-1,-1,-1] with ticks [60,60,60] is -0.5 of a unit, not -1.5, because the whole part is the floor and the ticks count up from it. An implementation that takes the magnitude before adding the ticks prices that avatar at three times its reach and still passes every other vector. "detailed but small" indexes faces past the end of its vertex list, since the formula counts faces and never looks at them. §1.9 refuses that, so the face count is kept and the indices substituted — the same input as far as the formula is concerned. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JwXApJjoZYtkD3sPRWbPNa
This commit is contained in:
co-authored by
Claude Opus 5
parent
94bc8864d6
commit
0cc0e8c8b8
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.vitorpamplona.quartz.cyberspace.deck0003Sno
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
/**
|
||||
* The avatar-work golden vectors from the reference implementation.
|
||||
*
|
||||
* `CYBERSPACE_V2.md` §8.10 says its two reference implementations, `avatar.ts`
|
||||
* in cyberspace-core and `cyberspace_core/avatar.py` in cyberspace-cli, are
|
||||
* "pinned to one set of golden vectors". This is that set, read out of
|
||||
* `tests/fixtures/avatar_work.json` in cyberspace-cli (MIT), so our ladder is
|
||||
* checked against the implementation the spec points at and not only against
|
||||
* the pseudocode we both read.
|
||||
*
|
||||
* Two of the fixtures need a word:
|
||||
* - **"half gibson, ticks"** is the case a careless reader gets wrong. Its
|
||||
* vertex is `[-1, -1, -1]` with ticks `[60, 60, 60]`, which is -0.5 of a unit,
|
||||
* not -1.5: the whole part is the floor and the ticks count up from it, so the
|
||||
* ticks must be added to the signed whole before the magnitude is taken.
|
||||
* - **"detailed but small"** indexes faces past the end of its vertex list,
|
||||
* because the work formula only counts faces and never looks at them. §1.9
|
||||
* would refuse that payload, so this keeps the face count and substitutes
|
||||
* indices the parser accepts, which is the same input as far as the formula
|
||||
* is concerned.
|
||||
*/
|
||||
class SnoAvatarWorkGoldenVectorsTest {
|
||||
private data class Vector(
|
||||
val name: String,
|
||||
val reach: Double,
|
||||
val required: Int,
|
||||
val substitutedFaces: Boolean,
|
||||
val json: String,
|
||||
)
|
||||
|
||||
private val vectors =
|
||||
listOf(
|
||||
Vector(
|
||||
name = "one gibson, plain",
|
||||
reach = 1.0,
|
||||
required = 16,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"one gibson, plain\",\"unit\":0,\"mode\":\"solid\",\"vertices\":[[0,0,0],[1,0,0],[0,1,0],[0,0,1]],\"colors\":[225,225,225" +
|
||||
",225],\"faces\":[[0,1,2],[0,2,3]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "half gibson, ticks",
|
||||
reach = 0.5,
|
||||
required = 16,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"half gibson, ticks\",\"unit\":0,\"mode\":\"points\",\"vertices\":[[0,0,0],[-1,-1,-1]],\"colors\":[225,225],\"faces\":[]," +
|
||||
"\"ticks\":[[60,60,60],[60,60,60]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "two gibsons",
|
||||
reach = 2.0,
|
||||
required = 18,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"two gibsons\",\"unit\":0,\"mode\":\"solid\",\"vertices\":[[-2,-2,-2],[-2,-2,2],[-2,2,-2],[-2,2,2],[2,-2,-2],[2,-2,2],[2," +
|
||||
"2,-2],[2,2,2]],\"colors\":[225,225,225,225,225,225,225,225],\"faces\":[[0,1,2],[1,3,2],[4,6,5],[5,6,7],[0,4,1],[1,4,5],[2,3,6],[3,7,6],[0,2," +
|
||||
"4],[2,6,4],[1,5,3],[3,5,7]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "four gibsons",
|
||||
reach = 4.0,
|
||||
required = 20,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"four gibsons\",\"unit\":0,\"mode\":\"solid\",\"vertices\":[[-4,-4,-4],[-4,-4,4],[-4,4,-4],[-4,4,4],[4,-4,-4],[4,-4,4],[4" +
|
||||
",4,-4],[4,4,4]],\"colors\":[225,225,225,225,225,225,225,225],\"faces\":[[0,1,2],[1,3,2],[4,6,5],[5,6,7],[0,4,1],[1,4,5],[2,3,6],[3,7,6],[0,2" +
|
||||
",4],[2,6,4],[1,5,3],[3,5,7]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "sixteen gibsons via unit",
|
||||
reach = 16.0,
|
||||
required = 24,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"sixteen gibsons via unit\",\"unit\":2,\"mode\":\"solid\",\"vertices\":[[-4,-4,-4],[-4,-4,4],[-4,4,-4],[-4,4,4],[4,-4,-4]" +
|
||||
",[4,-4,4],[4,4,-4],[4,4,4]],\"colors\":[225,225,225,225,225,225,225,225],\"faces\":[[0,1,2],[1,3,2],[4,6,5],[5,6,7],[0,4,1],[1,4,5],[2,3,6]," +
|
||||
"[3,7,6],[0,2,4],[2,6,4],[1,5,3],[3,5,7]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "a thousand and twenty-four gibsons",
|
||||
reach = 1024.0,
|
||||
required = 36,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"a thousand and twenty-four gibsons\",\"unit\":10,\"mode\":\"solid\",\"vertices\":[[-1,-1,-1],[-1,-1,1],[-1,1,-1],[-1,1,1" +
|
||||
"],[1,-1,-1],[1,-1,1],[1,1,-1],[1,1,1]],\"colors\":[225,225,225,225,225,225,225,225],\"faces\":[[0,1,2],[1,3,2],[4,6,5],[5,6,7],[0,4,1],[1,4," +
|
||||
"5],[2,3,6],[3,7,6],[0,2,4],[2,6,4],[1,5,3],[3,5,7]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "detailed but small",
|
||||
reach = 1.0,
|
||||
required = 28,
|
||||
substitutedFaces = true,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"detailed but small\",\"unit\":0,\"mode\":\"solid\",\"vertices\":[[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-" +
|
||||
"1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0" +
|
||||
",0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-" +
|
||||
"1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1," +
|
||||
"0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1]" +
|
||||
",[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1]," +
|
||||
"[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1]," +
|
||||
"[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1" +
|
||||
",-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-" +
|
||||
"1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0],[-1,1,0],[0,1," +
|
||||
"0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0],[0,0,0],[1,0,0" +
|
||||
"],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0],[1,-1,0],[-1,0,0" +
|
||||
"],[0,0,0],[1,0,0],[-1,1,0],[0,1,0],[1,1,0],[-1,-1,1],[0,-1,1],[1,-1,1],[-1,0,1],[0,0,1],[1,0,1],[-1,1,1],[0,1,1],[1,1,1],[-1,-1,0],[0,-1,0]]" +
|
||||
",\"colors\":[225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225" +
|
||||
",225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225" +
|
||||
",225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225" +
|
||||
",225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225" +
|
||||
",225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225" +
|
||||
",225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225],\"faces\":[[0,1,2],[1,2,3]" +
|
||||
",[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10],[9,10,11],[10,11,12],[11,12,13],[12,13,14],[13,14,15],[14,15,16],[15,16,17],[16,17" +
|
||||
",18],[17,18,19],[18,19,20],[19,20,21],[20,21,22],[21,22,23],[22,23,24],[23,24,25],[24,25,26],[25,26,27],[26,27,28],[27,28,29],[28,29,30],[29" +
|
||||
",30,31],[30,31,32],[31,32,33],[32,33,34],[33,34,35],[34,35,36],[35,36,37],[36,37,38],[37,38,39],[38,39,40],[39,40,41],[40,41,42],[41,42,43]," +
|
||||
"[42,43,44],[43,44,45],[44,45,46],[45,46,47],[46,47,48],[47,48,49],[48,49,50],[49,50,51],[50,51,52],[51,52,53],[52,53,54],[53,54,55],[54,55,5" +
|
||||
"6],[55,56,57],[56,57,58],[57,58,59],[58,59,60],[59,60,61],[60,61,62],[61,62,63],[62,63,64],[63,64,65],[64,65,66],[65,66,67],[66,67,68],[67,6" +
|
||||
"8,69],[68,69,70],[69,70,71],[70,71,72],[71,72,73],[72,73,74],[73,74,75],[74,75,76],[75,76,77],[76,77,78],[77,78,79],[78,79,80],[79,80,81],[8" +
|
||||
"0,81,82],[81,82,83],[82,83,84],[83,84,85],[84,85,86],[85,86,87],[86,87,88],[87,88,89],[88,89,90],[89,90,91],[90,91,92],[91,92,93],[92,93,94]" +
|
||||
",[93,94,95],[94,95,96],[95,96,97],[96,97,98],[97,98,99],[98,99,100],[99,100,101],[100,101,102],[101,102,103],[102,103,104],[103,104,105],[10" +
|
||||
"4,105,106],[105,106,107],[106,107,108],[107,108,109],[108,109,110],[109,110,111],[110,111,112],[111,112,113],[112,113,114],[113,114,115],[11" +
|
||||
"4,115,116],[115,116,117],[116,117,118],[117,118,119],[118,119,120],[119,120,121],[120,121,122],[121,122,123],[122,123,124],[123,124,125],[12" +
|
||||
"4,125,126],[125,126,127],[126,127,128],[127,128,129],[128,129,130],[129,130,131],[130,131,132],[131,132,133],[132,133,134],[133,134,135],[13" +
|
||||
"4,135,136],[135,136,137],[136,137,138],[137,138,139],[138,139,140],[139,140,141],[140,141,142],[141,142,143],[142,143,144],[143,144,145],[14" +
|
||||
"4,145,146],[145,146,147],[146,147,148],[147,148,149],[148,149,150],[149,150,151],[150,151,152],[151,152,153],[152,153,154],[153,154,155],[15" +
|
||||
"4,155,156],[155,156,157],[156,157,158],[157,158,159],[158,159,160],[159,160,161],[160,161,162],[161,162,163],[162,163,164],[163,164,165],[16" +
|
||||
"4,165,166],[165,166,167],[166,167,168],[167,168,169],[168,169,170],[169,170,171],[170,171,172],[171,172,173],[172,173,174],[173,174,175],[17" +
|
||||
"4,175,176],[175,176,177],[176,177,178],[177,178,179],[178,179,180],[179,180,181],[180,181,182],[181,182,183],[182,183,184],[183,184,185],[18" +
|
||||
"4,185,186],[185,186,187],[186,187,188],[187,188,189],[188,189,190],[189,190,191],[190,191,192],[191,192,193],[192,193,194],[193,194,195],[19" +
|
||||
"4,195,196],[195,196,197],[196,197,198],[197,198,199],[198,199,0],[199,0,1],[0,1,2],[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[" +
|
||||
"8,9,10],[9,10,11],[10,11,12],[11,12,13],[12,13,14],[13,14,15],[14,15,16],[15,16,17],[16,17,18],[17,18,19],[18,19,20],[19,20,21],[20,21,22],[" +
|
||||
"21,22,23],[22,23,24],[23,24,25],[24,25,26],[25,26,27],[26,27,28],[27,28,29],[28,29,30],[29,30,31],[30,31,32],[31,32,33],[32,33,34],[33,34,35" +
|
||||
"],[34,35,36],[35,36,37],[36,37,38],[37,38,39],[38,39,40],[39,40,41],[40,41,42],[41,42,43],[42,43,44],[43,44,45],[44,45,46],[45,46,47],[46,47" +
|
||||
",48],[47,48,49],[48,49,50],[49,50,51],[50,51,52],[51,52,53],[52,53,54],[53,54,55],[54,55,56],[55,56,57],[56,57,58],[57,58,59],[58,59,60],[59" +
|
||||
",60,61],[60,61,62],[61,62,63],[62,63,64],[63,64,65],[64,65,66],[65,66,67],[66,67,68],[67,68,69],[68,69,70],[69,70,71],[70,71,72],[71,72,73]," +
|
||||
"[72,73,74],[73,74,75],[74,75,76],[75,76,77],[76,77,78],[77,78,79],[78,79,80],[79,80,81],[80,81,82],[81,82,83],[82,83,84],[83,84,85],[84,85,8" +
|
||||
"6],[85,86,87],[86,87,88],[87,88,89],[88,89,90],[89,90,91],[90,91,92],[91,92,93],[92,93,94],[93,94,95],[94,95,96],[95,96,97],[96,97,98],[97,9" +
|
||||
"8,99],[98,99,100],[99,100,101],[100,101,102],[101,102,103],[102,103,104],[103,104,105],[104,105,106],[105,106,107],[106,107,108],[107,108,10" +
|
||||
"9],[108,109,110],[109,110,111],[110,111,112],[111,112,113]]}",
|
||||
),
|
||||
Vector(
|
||||
name = "packed zero ticks",
|
||||
reach = 3.0,
|
||||
required = 20,
|
||||
substitutedFaces = false,
|
||||
json =
|
||||
"{\"v\":2,\"name\":\"packed zero ticks\",\"unit\":0,\"mode\":\"points\",\"vertices\":[[3,0,0],[0,0,0]],\"colors\":[225,225],\"faces\":[],\"ti" +
|
||||
"cks\":[-2]}",
|
||||
),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun ourLadderMatchesTheReferenceImplementation() {
|
||||
vectors.forEach { vector ->
|
||||
val payload = SnoParser.parse(vector.json).payloadOrNull()
|
||||
assertNotNull(payload, "${vector.name} did not parse")
|
||||
assertEquals(vector.required, SnoAvatarWork.required(payload), "${vector.name} (reach ${vector.reach})")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theWholeSetIsCovered() {
|
||||
assertEquals(8, vectors.size)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user