feat: Finished and added tests for palette implementation
This commit is contained in:
parent
d1d35c2479
commit
0d6ff2cf96
@ -5,47 +5,82 @@ package world
|
|||||||
//
|
//
|
||||||
// This palette is unique to each section, and allows ranges of blocks to be
|
// 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
|
// 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 NewSectionPalette() SectionPalette {
|
||||||
func (p SectionPalette) Compact() SectionPalette {
|
return SectionPalette{
|
||||||
ids := make(map[BlockID]bool)
|
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
|
// Filter out the duplicate block ids
|
||||||
for _, blockId := range p {
|
for index, blockId := range p.ids {
|
||||||
ids[blockId] = true
|
newIds[blockId] = index
|
||||||
}
|
}
|
||||||
|
|
||||||
var np SectionPalette
|
// If there was not a resize, return instantly
|
||||||
|
if len(newIds) != len(p.ids) {
|
||||||
for blockId := range ids {
|
wasResized = true
|
||||||
np = append(np, blockId)
|
} 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
|
// `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
|
// If the block id does not exist, it is placed in the palette and the index
|
||||||
// is returned
|
// 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
|
// 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 {
|
if state == blockId {
|
||||||
return PaletteIndex(index)
|
return PaletteIndex(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, insert it into the palette and return the 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
|
// `State` returns the state for a palette's index
|
||||||
func (p SectionPalette) State(index PaletteIndex) BlockID {
|
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
|
type PaletteIndex byte
|
||||||
|
64
world/palette_test.go
Normal file
64
world/palette_test.go
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user