Skip to content

Commit

Permalink
chore(quadtree): Change Set() and Get() params to use image.Point
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe565 committed Jul 22, 2024
1 parent 711be0a commit bd6388a
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 118 deletions.
8 changes: 4 additions & 4 deletions internal/game/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,19 @@ func (g *Game) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch g.mode {
case ModeSmart:
if g.smartVal == -1 {
val := g.pattern.Tree.Get(msg.X, msg.Y, 0).Value()
val := g.pattern.Tree.Get(image.Pt(msg.X, msg.Y), 0).Value()
switch val {
case 0:
g.smartVal = 1
case 1:
g.smartVal = 0
}
}
g.pattern.Tree = g.pattern.Tree.Set(msg.X, msg.Y, g.smartVal)
g.pattern.Tree = g.pattern.Tree.Set(image.Pt(msg.X, msg.Y), g.smartVal)
case ModePlace:
g.pattern.Tree = g.pattern.Tree.Set(msg.X, msg.Y, 1)
g.pattern.Tree = g.pattern.Tree.Set(image.Pt(msg.X, msg.Y), 1)
case ModeErase:
g.pattern.Tree = g.pattern.Tree.Set(msg.X, msg.Y, 0)
g.pattern.Tree = g.pattern.Tree.Set(image.Pt(msg.X, msg.Y), 0)
}
}
case tea.MouseButtonWheelUp:
Expand Down
17 changes: 9 additions & 8 deletions internal/pattern/plaintext.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"fmt"
"image"
"io"

"github.com/gabe565/cli-of-life/internal/quadtree"
Expand All @@ -16,7 +17,7 @@ func UnmarshalPlaintext(r io.Reader) (Pattern, error) {
Tree: quadtree.Empty(quadtree.DefaultTreeSize),
}
scanner := bufio.NewScanner(r)
var y int
var p image.Point
for scanner.Scan() {
line := scanner.Bytes()
switch {
Expand All @@ -32,21 +33,21 @@ func UnmarshalPlaintext(r io.Reader) (Pattern, error) {
pattern.Comment += string(comment)
}
default:
var x int
pattern.Tree = pattern.Tree.GrowToFit(x, len(line))
pattern.Tree = pattern.Tree.GrowToFit(p.Add(image.Pt(0, len(line))))
for _, b := range line {
switch b {
case '.':
pattern.Tree = pattern.Tree.Set(x, y, 0)
x++
pattern.Tree = pattern.Tree.Set(p, 0)
p.X++
case 'O', '*':
pattern.Tree = pattern.Tree.Set(x, y, 1)
x++
pattern.Tree = pattern.Tree.Set(p, 1)
p.X++
default:
return pattern, fmt.Errorf("plaintext: %w: %q in line %q", ErrUnexpectedCharacter, string(b), line)
}
}
y++
p.X = 0
p.Y++
}
}
if scanner.Err() != nil {
Expand Down
19 changes: 10 additions & 9 deletions internal/pattern/rle.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"fmt"
"image"
"io"
"regexp"
"strconv"
Expand All @@ -21,7 +22,7 @@ func UnmarshalRLE(r io.Reader) (Pattern, error) {
Tree: quadtree.Empty(quadtree.DefaultTreeSize),
}
scanner := bufio.NewScanner(r)
var x, y int
var p image.Point
scan:
for scanner.Scan() {
line := scanner.Bytes()
Expand Down Expand Up @@ -71,7 +72,7 @@ scan:
}
}

pattern.Tree = pattern.Tree.GrowToFit(w, h)
pattern.Tree = pattern.Tree.GrowToFit(image.Pt(w, h))
default:
if len(line) == 0 {
continue
Expand All @@ -85,9 +86,9 @@ scan:
runCount += int(b - '0')
case b == '$':
runCount = max(runCount, 1)
if x != 0 || y != 0 {
y += runCount
x = 0
if p.X != 0 || p.Y != 0 {
p.Y += runCount
p.X = 0
}
runCount = 0
case b == '!':
Expand All @@ -97,14 +98,14 @@ scan:
switch b {
case 'b':
for range runCount {
pattern.Tree = pattern.Tree.Set(x, y, 0)
x++
pattern.Tree = pattern.Tree.Set(p, 0)
p.X++
}
case ' ':
default:
for range runCount {
pattern.Tree = pattern.Tree.Set(x, y, 1)
x++
pattern.Tree = pattern.Tree.Set(p, 1)
p.X++
}
}
runCount = 0
Expand Down
3 changes: 2 additions & 1 deletion internal/quadtree/game_of_life.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package quadtree

import (
"image"
"slices"

"github.com/gabe565/cli-of-life/internal/rule"
Expand Down Expand Up @@ -67,7 +68,7 @@ func (n *Node) slowSimulation(r *rule.Rule) *Node {
var b uint16
for y := -2; y < 2; y++ {
for x := -2; x < 2; x++ {
b = (b << 1) + uint16(n.Get(x, y, 0).value)
b = (b << 1) + uint16(n.Get(image.Pt(x, y), 0).value)
}
}
return memoizedNew.Call(Children{NW: oneGen(b>>5, r), NE: oneGen(b>>4, r), SW: oneGen(b>>1, r), SE: oneGen(b, r)})
Expand Down
46 changes: 23 additions & 23 deletions internal/quadtree/quadtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,20 @@ func (n *Node) grow() *Node {
})
}

func (n *Node) GrowToFit(x, y int) *Node {
func (n *Node) GrowToFit(p image.Point) *Node {
w := n.Width() / 2
for x > w || y > w || x < -w || y < -w {
for p.X > w || p.Y > w || p.X < -w || p.Y < -w {
n = n.grow()
w = n.Width() / 2
}
return n
}

func (n *Node) Set(x, y int, value int) *Node {
func (n *Node) Set(p image.Point, value int) *Node {
if n.level == 0 {
switch {
case x < -1, x > 0, y < -1, y > 0:
panic(fmt.Sprintf("Reached leaf node with coordinates too big: (%d, %d)", x, y))
case p.X < -1, p.X > 0, p.Y < -1, p.Y > 0:
panic(fmt.Sprintf("Reached leaf node with coordinates too big: (%d, %d)", p.X, p.Y))
case value == n.value:
return n
case value == 0:
Expand All @@ -108,49 +108,49 @@ func (n *Node) Set(x, y int, value int) *Node {

w := 1 << (n.level - 2)
switch {
case x >= 0:
case p.X >= 0:
switch {
case y >= 0:
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE, SW: n.SW, SE: n.SE.Set(x-w, y-w, value)})
case p.Y >= 0:
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE, SW: n.SW, SE: n.SE.Set(p.Sub(image.Pt(w, w)), value)})
default:
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE.Set(x-w, y+w, value), SW: n.SW, SE: n.SE})
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE.Set(p.Add(image.Pt(-w, w)), value), SW: n.SW, SE: n.SE})
}
case y >= 0:
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE, SW: n.SW.Set(x+w, y-w, value), SE: n.SE})
case p.Y >= 0:
return memoizedNew.Call(Children{NW: n.NW, NE: n.NE, SW: n.SW.Set(p.Add(image.Pt(w, -w)), value), SE: n.SE})
default:
return memoizedNew.Call(Children{NW: n.NW.Set(x+w, y+w, value), NE: n.NE, SW: n.SW, SE: n.SE})
return memoizedNew.Call(Children{NW: n.NW.Set(p.Add(image.Pt(w, w)), value), NE: n.NE, SW: n.SW, SE: n.SE})
}
}

func (n *Node) children() []*Node {
return []*Node{n.SE, n.SW, n.NW, n.NE}
}

func (n *Node) Get(x, y int, level uint8) *Node {
func (n *Node) Get(p image.Point, level uint8) *Node {
if n.level == level {
allowed := 1
if level != 0 {
allowed = 1 << (level - 1)
}
if x < -allowed || x > allowed || y < -allowed || y > allowed {
panic(fmt.Sprintf("Reached leaf node with coordinates too big: (%d, %d)", x, y))
if p.X < -allowed || p.X > allowed || p.Y < -allowed || p.Y > allowed {
panic(fmt.Sprintf("Reached leaf node with coordinates too big: (%d, %d)", p.X, p.Y))
}
return n
}

w := 1 << (n.level - 2)
switch {
case x >= 0:
case p.X >= 0:
switch {
case y >= 0:
return n.SE.Get(x-w, y-w, level)
case p.Y >= 0:
return n.SE.Get(p.Sub(image.Pt(w, w)), level)
default:
return n.NE.Get(x-w, y+w, level)
return n.NE.Get(p.Add(image.Pt(-w, w)), level)
}
case y >= 0:
return n.SW.Get(x+w, y-w, level)
case p.Y >= 0:
return n.SW.Get(p.Add(image.Pt(w, -w)), level)
default:
return n.NW.Get(x+w, y+w, level)
return n.NW.Get(p.Add(image.Pt(w, w)), level)
}
}

Expand Down Expand Up @@ -214,7 +214,7 @@ func (n *Node) ToSlice() [][]int {

for y := coords.Min.Y; y < coords.Max.Y; y++ {
for x := coords.Min.X; x < coords.Max.X; x++ {
result[y-coords.Min.Y][x-coords.Min.X] = n.Get(x, y, 0).value
result[y-coords.Min.Y][x-coords.Min.X] = n.Get(image.Pt(x, y), 0).value
}
}
return result
Expand Down
15 changes: 7 additions & 8 deletions internal/quadtree/quadtree_helpers_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package quadtree

import (
"image"
"math/big"
"math/rand"
"testing"
Expand All @@ -26,11 +27,9 @@ func treeWithRandomPattern(level uint) (*Node, *big.Int) {
for x := range edgeLength {
for y := range edgeLength {
bitPosition := x*edgeLength + y
ux := x - edgeLength/2
uy := y - edgeLength/2

if randomNumber.Bit(bitPosition) != 0 {
node = node.Set(ux, uy, 1)
p := image.Pt(x-edgeLength/2, y-edgeLength/2)
node = node.Set(p, 1)
}
}
}
Expand Down Expand Up @@ -58,15 +57,15 @@ func treeCorrectness(t *testing.T, node *Node) {
// 1 | 0
func slashLevelOne() *Node {
return Empty(1).
Set(0, -1, 1).
Set(-1, 0, 1)
Set(image.Pt(0, -1), 1).
Set(image.Pt(-1, 0), 1)
}

// backslashLevelOne returns a level one tree with the following pattern
// 1 | 0
// 0 | 1
func backslashLevelOne() *Node {
return Empty(1).
Set(0, 0, 1).
Set(-1, -1, 1)
Set(image.Pt(0, 0), 1).
Set(image.Pt(-1, -1), 1)
}
Loading

0 comments on commit bd6388a

Please sign in to comment.