diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/field/set.go | 86 | ||||
-rw-r--r-- | pkg/field/set_test.go | 230 | ||||
-rw-r--r-- | pkg/field/utils.go | 85 | ||||
-rw-r--r-- | pkg/field/utils_test.go | 222 |
4 files changed, 316 insertions, 307 deletions
diff --git a/pkg/field/set.go b/pkg/field/set.go new file mode 100644 index 0000000..5044898 --- /dev/null +++ b/pkg/field/set.go @@ -0,0 +1,86 @@ +package field + +func (f *Field) Set(x, y, v int) { + if v == ' ' { + f.Blank(x, y) + return + } + 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 := x - l.x + 1 + 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-f.x < 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 := 1; i < l.x-x; i++ { + c[i] = ' ' + } + for i := l.x - x; i < newL; i++ { + c[i] = l.columns[i-l.x+x] + } + l.columns = c + l.x = x + l.l = newL + if f.x > x { + f.lx = f.lx + f.x - x + f.x = x + } + } + } 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.lx + f.x - x + f.x = x + } + 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 := f.y - y; j < newLy; j++ { + lines[j] = f.lines[j-f.y+y] + } + f.lines = lines + f.y = y + f.ly = newLy + if f.x > x { + f.lx = f.lx + f.x - x + f.x = x + } + if f.lx-f.x < x { + f.lx = x - f.x + 1 + } + } +} diff --git a/pkg/field/set_test.go b/pkg/field/set_test.go new file mode 100644 index 0000000..5b7f0ac --- /dev/null +++ b/pkg/field/set_test.go @@ -0,0 +1,230 @@ +package field + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +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 := Load(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 := Load(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 := Load(file) + field.Set(tc.inputX, tc.inputY, tc.inputV) + require.NoError(t, err) + require.Equal(t, tc.expected, field, "Invalid value") + }) + } +} diff --git a/pkg/field/utils.go b/pkg/field/utils.go index c513d96..ab5ff7a 100644 --- a/pkg/field/utils.go +++ b/pkg/field/utils.go @@ -14,91 +14,6 @@ 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 v == ' ' { - f.Blank(x, y) - return - } - 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 := x - l.x + 1 - 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-f.x < 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 := 1; i < l.x-x; i++ { - c[i] = ' ' - } - for i := l.x - x; i < newL; i++ { - c[i] = l.columns[i-l.x+x] - } - l.columns = c - l.x = x - l.l = newL - if f.x > x { - f.lx = f.lx + f.x - x - f.x = x - } - } - } 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.lx + f.x - x - f.x = x - } - 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 := f.y - y; j < newLy; j++ { - lines[j] = f.lines[j-f.y+y] - } - f.lines = lines - f.y = y - f.ly = newLy - if f.x > x { - f.lx = f.lx + f.x - x - f.x = x - } - if f.lx-f.x < x { - f.lx = x - f.x + 1 - } - } -} - func (f Field) Dump() (int, int, int, int) { return f.x, f.y, f.lx, f.ly } diff --git a/pkg/field/utils_test.go b/pkg/field/utils_test.go index 837f9fb..d1f4332 100644 --- a/pkg/field/utils_test.go +++ b/pkg/field/utils_test.go @@ -73,228 +73,6 @@ 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 := Load(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 := Load(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 := Load(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{ |