feat: Finished and added tests for palette implementation

This commit is contained in:
Nicholas Novak 2023-12-11 00:23:31 -08:00
parent d1d35c2479
commit 0d6ff2cf96
2 changed files with 115 additions and 16 deletions

View File

@ -5,47 +5,82 @@ package world
//
// This palette is unique to each section, and allows ranges of blocks to be
// changed in constant time, with the downside of having to "compact" the palette
type SectionPalette []BlockID
type SectionPalette struct {
ids map[PaletteIndex]BlockID
}
// `Compact` removes all duplicate states from a palette and returns a new palette
func (p SectionPalette) Compact() SectionPalette {
ids := make(map[BlockID]bool)
func NewSectionPalette() SectionPalette {
return SectionPalette{
ids: make(map[PaletteIndex]BlockID),
}
}
// `Compact` removes all duplicate states from a palette and returns if the
// palette was modified
func (p *SectionPalette) Compact() bool {
newIds := make(map[BlockID]PaletteIndex)
var wasResized bool
// Filter out the duplicate block ids
for _, blockId := range p {
ids[blockId] = true
for index, blockId := range p.ids {
newIds[blockId] = index
}
var np SectionPalette
for blockId := range ids {
np = append(np, blockId)
// If there was not a resize, return instantly
if len(newIds) != len(p.ids) {
wasResized = true
} else {
return false
}
return np
ids := make(map[PaletteIndex]BlockID)
for blockId, index := range newIds {
ids[index] = blockId
}
p.ids = ids
return wasResized
}
// `IndexFor` returns the palette index for a specified block id
//
// If the block id does not exist, it is placed in the palette and the index
// is returned
func (p SectionPalette) IndexFor(state BlockID) PaletteIndex {
func (p *SectionPalette) IndexFor(state BlockID) PaletteIndex {
var maxIndex PaletteIndex
// If the state is already in the palette, return it
for index, blockId := range p {
for index, blockId := range p.ids {
if index > maxIndex {
maxIndex = index
}
if state == blockId {
return PaletteIndex(index)
}
}
// Otherwise, insert it into the palette and return the index
p = append(p, state)
p.ids[maxIndex+1] = state
return PaletteIndex(len(p) - 1)
return maxIndex + 1
}
// `State` returns the state for a palette's index
func (p SectionPalette) State(index PaletteIndex) BlockID {
return p[index]
return p.ids[index]
}
// `ReplaceIndex` replaces the block state at the given palette' index
//
// This function is used to quickly zero a section with a given block state in
// constant time, and should not be used for any other purpose. Otherwise, set
// the block state within the section to the result of `IndexFor`.
func (p *SectionPalette) ReplaceIndex(index PaletteIndex, state BlockID) {
p.ids[index] = state
}
type PaletteIndex byte

64
world/palette_test.go Normal file
View File

@ -0,0 +1,64 @@
package world
import (
"runtime/debug"
"testing"
)
func newPaletteWith(ids []BlockID) *SectionPalette {
p := NewSectionPalette()
for _, id := range ids {
p.IndexFor(id)
}
return &p
}
func checkPaletteEqual(t *testing.T, p *SectionPalette, index PaletteIndex, expected BlockID) {
if p.State(index) != expected {
debug.PrintStack()
t.Fatalf("Expected to get state %v at index %v, got %v", expected, index, p.State(index))
}
}
func TestInsertPalette(t *testing.T) {
p := NewSectionPalette()
ids := []BlockID{Empty, Generic}
for _, id := range ids {
index := p.IndexFor(id)
if id != p.State(index) {
t.Fatalf("Fetching index for id %v: got index %v which returned %v", id, index, p.State(index))
}
}
}
func TestReplaceCompactPalettte(t *testing.T) {
p := newPaletteWith([]BlockID{Empty, Generic})
zeroIndex := p.IndexFor(Empty)
checkPaletteEqual(t, p, zeroIndex, Empty)
// Zero out the chunk
genIndex := p.IndexFor(Generic)
checkPaletteEqual(t, p, genIndex, Generic)
p.ReplaceIndex(genIndex, Empty)
// Check that everything now returns zero
checkPaletteEqual(t, p, zeroIndex, Empty)
checkPaletteEqual(t, p, genIndex, Empty)
// Test for compaction
wasCompacted := p.Compact()
if !wasCompacted {
t.Fatalf("Palette should have been compacted")
}
// Test to see that we don't compact again
wasCompacted = p.Compact()
if wasCompacted {
t.Fatalf("Palette should have not been compacted again")
}
}