aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorJulien Dessaux2021-09-19 02:19:58 +0200
committerJulien Dessaux2021-09-19 02:20:23 +0200
commitfc132c3deaa2f93dc5d610286d02d216eef2bd66 (patch)
tree0a37f032a43a246f2b51331c26118c45a4eb8c0b /pkg
parentImplemented function to get a field value (diff)
downloadgofunge98-fc132c3deaa2f93dc5d610286d02d216eef2bd66.tar.gz
gofunge98-fc132c3deaa2f93dc5d610286d02d216eef2bd66.tar.bz2
gofunge98-fc132c3deaa2f93dc5d610286d02d216eef2bd66.zip
Implemented function to set a field value
Diffstat (limited to 'pkg')
-rw-r--r--pkg/field/utils.go83
-rw-r--r--pkg/field/utils_test.go257
2 files changed, 340 insertions, 0 deletions
diff --git a/pkg/field/utils.go b/pkg/field/utils.go
index 769af37..4c4774c 100644
--- a/pkg/field/utils.go
+++ b/pkg/field/utils.go
@@ -13,3 +13,86 @@ func (f Field) Get(x, y int) int {
func (f Field) isIn(x, y int) bool {
return x >= f.x && x < f.x+f.lx && y >= f.y && y < f.y+f.ly
}
+
+func (f *Field) Set(x, y, v int) {
+ if y >= f.y {
+ if y < f.y+f.ly {
+ l := &f.lines[y-f.y]
+ if l.l == 0 {
+ // an empty line is a special case
+ l.x = x
+ l.l = 1
+ l.columns = append(l.columns, v)
+ } else if x >= l.x {
+ if x < l.x+l.l {
+ // just set the value
+ l.columns[x-l.x] = v
+ } else {
+ // append columns
+ newL := l.l + x - l.x
+ for i := l.l; i < newL-1; i++ {
+ l.columns = append(l.columns, ' ')
+ }
+ l.columns = append(l.columns, v)
+ l.l = newL
+ if f.lx < l.l-l.x {
+ f.lx = l.l - l.x
+ }
+ }
+ } else {
+ // prepend columns
+ newL := l.l + l.x - x
+ c := make([]int, newL)
+ c[0] = v
+ for i := 0; i < l.x-x; i++ {
+ c[i+1] = ' '
+ }
+ for j := 0; j < l.l; j++ {
+ c[j+l.x-x] = l.columns[j]
+ }
+ l.columns = c
+ l.x = x
+ l.l = newL
+ if f.x > x {
+ f.x = x
+ f.lx = newL
+ }
+ }
+ } else {
+ // append lines
+ newLy := y - f.y + 1
+ for i := f.ly; i < newLy-1; i++ {
+ f.lines = append(f.lines, Line{})
+ }
+ f.lines = append(f.lines, Line{x: x, l: 1, columns: []int{v}})
+ f.ly = newLy
+ if f.x > x {
+ f.lx += f.x - x
+ f.x = x
+ } else if f.lx-f.x < x {
+ f.lx = x - f.x
+ }
+ }
+ } else {
+ // prepend lines
+ newLy := f.ly + f.y - y
+ lines := make([]Line, newLy)
+ lines[0] = Line{
+ x: x,
+ l: 1,
+ columns: []int{v},
+ }
+ for j := 0; j < f.ly; j++ {
+ lines[j+f.y-y] = f.lines[j]
+ }
+ f.lines = lines
+ f.y = y
+ f.ly = newLy
+ if f.x > x {
+ f.lx += f.x - x
+ f.x = x
+ } else if f.lx-f.x < x {
+ f.lx = x - f.x + 1
+ }
+ }
+}
diff --git a/pkg/field/utils_test.go b/pkg/field/utils_test.go
index 89b4d39..52916e3 100644
--- a/pkg/field/utils_test.go
+++ b/pkg/field/utils_test.go
@@ -72,3 +72,260 @@ func TestIsIn(t *testing.T) {
})
}
}
+
+func TestSetMinimalAppendOne(t *testing.T) {
+ hashField := Field{
+ x: 0,
+ y: 0,
+ lx: 1,
+ ly: 1,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ },
+ }
+ xAppendField := Field{
+ x: 0,
+ y: 0,
+ lx: 2,
+ ly: 1,
+ lines: []Line{
+ Line{x: 0, l: 2, columns: []int{'@', '#'}},
+ },
+ }
+ xPrependField := Field{
+ x: -1,
+ y: 0,
+ lx: 2,
+ ly: 1,
+ lines: []Line{
+ Line{x: -1, l: 2, columns: []int{'#', '@'}},
+ },
+ }
+ yAppendField := Field{
+ x: 0,
+ y: 0,
+ lx: 1,
+ ly: 2,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ },
+ }
+ yPrependField := Field{
+ x: 0,
+ y: -1,
+ lx: 1,
+ ly: 2,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ },
+ }
+ // Test cases
+ testCases := []struct {
+ name string
+ input string
+ inputX int
+ inputY int
+ inputV int
+ expected *Field
+ }{
+ {"simple", "test_data/minimal.b98", 0, 0, '#', &hashField},
+ {"xappend", "test_data/minimal.b98", 1, 0, '#', &xAppendField},
+ {"xprepend", "test_data/minimal.b98", -1, 0, '#', &xPrependField},
+ {"yappend", "test_data/minimal.b98", 0, 1, '#', &yAppendField},
+ {"yprepend", "test_data/minimal.b98", 0, -1, '#', &yPrependField},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ file, err := os.Open(tc.input)
+ require.NoError(t, err, "Failed to open file")
+ defer file.Close()
+ field, err := LoadFile(file)
+ field.Set(tc.inputX, tc.inputY, tc.inputV)
+ require.NoError(t, err)
+ require.Equal(t, tc.expected, field, "Invalid value")
+ })
+ }
+}
+
+func TestSetMinimalAppendTwo(t *testing.T) {
+ bottomRight := Field{
+ x: 0,
+ y: 0,
+ lx: 5,
+ ly: 3,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ Line{},
+ Line{x: 5, l: 1, columns: []int{'#'}},
+ },
+ }
+ bottomLeft := Field{
+ x: -5,
+ y: 0,
+ lx: 6,
+ ly: 4,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ Line{},
+ Line{},
+ Line{x: -5, l: 1, columns: []int{'#'}},
+ },
+ }
+ topRight := Field{
+ x: 0,
+ y: -3,
+ lx: 9,
+ ly: 4,
+ lines: []Line{
+ Line{x: 8, l: 1, columns: []int{'#'}},
+ Line{},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ },
+ }
+ topLeft := Field{
+ x: -12,
+ y: -4,
+ lx: 13,
+ ly: 5,
+ lines: []Line{
+ Line{x: -12, l: 1, columns: []int{'#'}},
+ Line{},
+ Line{},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ },
+ }
+ // Test cases
+ testCases := []struct {
+ name string
+ input string
+ inputX int
+ inputY int
+ inputV int
+ expected *Field
+ }{
+ {"bottomRight", "test_data/minimal.b98", 5, 2, '#', &bottomRight},
+ {"bottomLeft", "test_data/minimal.b98", -5, 3, '#', &bottomLeft},
+ {"topRight", "test_data/minimal.b98", 8, -3, '#', &topRight},
+ {"topLeft", "test_data/minimal.b98", -12, -4, '#', &topLeft},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ file, err := os.Open(tc.input)
+ require.NoError(t, err, "Failed to open file")
+ defer file.Close()
+ field, err := LoadFile(file)
+ field.Set(tc.inputX, tc.inputY, tc.inputV)
+ require.NoError(t, err)
+ require.Equal(t, tc.expected, field, "Invalid value")
+ })
+ }
+}
+
+func TestSetMinimalAppendThree(t *testing.T) {
+ xAppendField := Field{
+ x: 0,
+ y: 0,
+ lx: 4,
+ ly: 1,
+ lines: []Line{
+ Line{x: 0, l: 4, columns: []int{'@', ' ', ' ', '#'}},
+ },
+ }
+ xPrependField := Field{
+ x: -3,
+ y: 0,
+ lx: 4,
+ ly: 1,
+ lines: []Line{
+ Line{x: -3, l: 4, columns: []int{'#', ' ', ' ', '@'}},
+ },
+ }
+ yAppendField := Field{
+ x: 0,
+ y: 0,
+ lx: 1,
+ ly: 4,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ Line{},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ },
+ }
+ yPrependField := Field{
+ x: 0,
+ y: -3,
+ lx: 1,
+ ly: 4,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ Line{},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ },
+ }
+ // Test cases
+ testCases := []struct {
+ name string
+ input string
+ inputX int
+ inputY int
+ inputV int
+ expected *Field
+ }{
+ {"xappend", "test_data/minimal.b98", 3, 0, '#', &xAppendField},
+ {"xprepend", "test_data/minimal.b98", -3, 0, '#', &xPrependField},
+ {"yappend", "test_data/minimal.b98", 0, 3, '#', &yAppendField},
+ {"yprepend", "test_data/minimal.b98", 0, -3, '#', &yPrependField},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ file, err := os.Open(tc.input)
+ require.NoError(t, err, "Failed to open file")
+ defer file.Close()
+ field, err := LoadFile(file)
+ field.Set(tc.inputX, tc.inputY, tc.inputV)
+ require.NoError(t, err)
+ require.Equal(t, tc.expected, field, "Invalid value")
+ })
+ }
+}
+
+// get and put on an empty line
+func TestGetAndSetOnEmptyLines(t *testing.T) {
+ f := Field{
+ x: 0,
+ y: -4,
+ lx: 1,
+ ly: 8,
+ lines: []Line{
+ Line{x: 0, l: 1, columns: []int{'b'}},
+ Line{},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'c'}},
+ Line{x: 0, l: 1, columns: []int{'@'}},
+ Line{},
+ Line{x: 0, l: 1, columns: []int{'a'}},
+ Line{x: 0, l: 1, columns: []int{'#'}},
+ },
+ }
+ file, err := os.Open("test_data/minimal.b98")
+ require.NoError(t, err, "Failed to open file")
+ defer file.Close()
+ field, err := LoadFile(file)
+ field.Set(0, 3, '#')
+ v := field.Get(0, 3)
+ require.Equal(t, v, int('#'))
+ v = field.Get(0, 2)
+ require.Equal(t, v, int(' '))
+ field.Set(0, 2, 'a')
+ field.Set(0, -4, 'b')
+ v = field.Get(0, -1)
+ require.Equal(t, v, int(' '))
+ field.Set(0, -1, 'c')
+ require.Equal(t, field, &f)
+}