76 lines
2.2 KiB
Go
76 lines
2.2 KiB
Go
package level
|
|
|
|
// BlockPuzzleState describes the state of a block puzzle.
|
|
type BlockPuzzleState struct {
|
|
width int
|
|
height int
|
|
data []byte
|
|
}
|
|
|
|
// NewBlockPuzzleState returns a new instance of a block puzzle state modifier.
|
|
// The returned instance works with the passed data slice directly.
|
|
func NewBlockPuzzleState(data []byte, height, width int) *BlockPuzzleState {
|
|
return &BlockPuzzleState{
|
|
data: data,
|
|
width: width,
|
|
height: height}
|
|
}
|
|
|
|
// CellValue returns the value of the identified cell.
|
|
func (state *BlockPuzzleState) CellValue(row, col int) int {
|
|
scratch := uint16(0)
|
|
|
|
if state.positionOk(row, col) {
|
|
byteOffset, byteShift := state.byteOffset(row, col)
|
|
bitsAvailable := 8 - byteShift
|
|
|
|
scratch = uint16(state.data[state.mappedByteIndex(byteOffset)]) >> byteShift
|
|
if bitsAvailable < 3 {
|
|
scratch |= uint16(state.data[state.mappedByteIndex(byteOffset+1)]) << bitsAvailable
|
|
}
|
|
}
|
|
|
|
return int(scratch & 7)
|
|
}
|
|
|
|
// SetCellValue sets the value of the identified cell.
|
|
func (state *BlockPuzzleState) SetCellValue(row, col int, value int) {
|
|
if state.positionOk(row, col) {
|
|
byteOffset, byteShift := state.byteOffset(row, col)
|
|
needsSecondByte := (8 - byteShift) < 3
|
|
scratch := uint16(state.data[state.mappedByteIndex(byteOffset)])
|
|
mask := uint16(0x0007) << byteShift
|
|
|
|
if needsSecondByte {
|
|
scratch |= uint16(state.data[state.mappedByteIndex(byteOffset+1)]) << 8
|
|
}
|
|
scratch = (scratch & ^mask) | (uint16(value) << byteShift)
|
|
state.data[state.mappedByteIndex(byteOffset)] = byte((scratch >> 0) & 0xFF)
|
|
if needsSecondByte {
|
|
state.data[state.mappedByteIndex(byteOffset+1)] = byte((scratch >> 8) & 0xFF)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (state *BlockPuzzleState) bitOffset(row, col int) int {
|
|
return (row*state.width + col) * 3
|
|
}
|
|
|
|
func (state *BlockPuzzleState) positionOk(row, col int) bool {
|
|
bitOffset := state.bitOffset(row, col)
|
|
|
|
return (row < state.height) && (col < state.width) && (bitOffset <= (128 - 3))
|
|
}
|
|
|
|
func (state *BlockPuzzleState) byteOffset(row, col int) (byteOffset int, byteShift uint) {
|
|
bitOffset := state.bitOffset(row, col)
|
|
byteOffset = bitOffset / 8
|
|
byteShift = uint(bitOffset % 8)
|
|
return
|
|
}
|
|
|
|
func (state *BlockPuzzleState) mappedByteIndex(index int) int {
|
|
remainder := index % 4
|
|
return 15 - (index - remainder + (3 - remainder))
|
|
}
|