diff --git a/go/matrix/matrix.go b/go/matrix/matrix.go index c2bbfcf..342c7a2 100644 --- a/go/matrix/matrix.go +++ b/go/matrix/matrix.go @@ -1,32 +1,76 @@ package matrix -import "strings" +import ( + "errors" + "strconv" + "strings" +) +// Matrix is a grid of ints type Matrix struct { vals [][]int } +// New creates a new Matrix from a string of numbers func New(in string) (*Matrix, error) { ret := Matrix{} rows := strings.Split(in, "\n") + for i := range rows { + flds := strings.Fields(rows[i]) + var ints []int + for j := range flds { + if v, err := strconv.Atoi(flds[j]); err != nil { + return &ret, err + } else { + ints = append(ints, v) + } + } + ret.vals = append(ret.vals, ints) + } + numInRow := -1 + for i := range ret.vals { + if numInRow != -1 { + if len(ret.vals[i]) != numInRow { + return &ret, errors.New("All rows must be equal length") + } + } + numInRow = len(ret.vals[i]) + } return &ret, nil } +// Rows returns the values of the rows in the matrix func (m *Matrix) Rows() [][]int { - return m.vals -} - -func (m *Matrix) Cols() [][]int { - ret := [][]int{} - if len(m.vals) > 0 { - // for i := 0; i < len(m.vals[0]); i++ { - // } + var ret [][]int + for i := range m.vals { + var row []int + for j := range m.vals[i] { + row = append(row, m.vals[i][j]) + } + ret = append(ret, row) } return ret } +// Cols returns the values of the cols in the matrix +func (m *Matrix) Cols() [][]int { + var ret [][]int + for i := range m.vals[0] { + var row []int + for j := range m.vals { + row = append(row, m.vals[j][i]) + } + ret = append(ret, row) + } + return ret +} + +// Set sets the value at r,c to val func (m *Matrix) Set(r, c int, val int) bool { - if len(m.vals) < r || len(m.vals[r]) < c { + if r < 0 || c < 0 { + return false + } + if len(m.vals) <= r || len(m.vals[r]) <= c { return false } m.vals[r][c] = val diff --git a/go/saddle-points/README.md b/go/saddle-points/README.md new file mode 100644 index 0000000..2aabcf5 --- /dev/null +++ b/go/saddle-points/README.md @@ -0,0 +1,45 @@ +# Saddle Points + +Write a program that detects saddle points in a matrix. + +So say you have a matrix like so: + +```plain + 0 1 2 + |--------- +0 | 9 8 7 +1 | 5 3 2 <--- saddle point at (1,0) +2 | 6 6 7 +``` + +It has a saddle point at (1, 0). + +It's called a "saddle point" because it is greater than or equal to +every element in its row and the less than or equal to every element in +its column. + +A matrix may have zero or more saddle points. + +Your code should be able to provide the (possibly empty) list of all the +saddle points for any given matrix. + +Note that you may find other definitions of matrix saddle points online, +but the tests for this exercise follow the above unambiguous definition. + +To run the tests simply run the command `go test` in the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +For more detailed info about the Go track see the [help +page](http://exercism.io/languages/go). + +## Source + +J Dalbey's Programming Practice problems [http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/saddle-points/saddle.go b/go/saddle-points/saddle.go new file mode 100644 index 0000000..559f703 --- /dev/null +++ b/go/saddle-points/saddle.go @@ -0,0 +1,109 @@ +package matrix + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +// Matrix is a grid of ints +type Matrix struct { + vals [][]int +} + +type Pair [2]int + +// New creates a new Matrix from a string of numbers +func New(in string) (*Matrix, error) { + ret := Matrix{} + rows := strings.Split(in, "\n") + for i := range rows { + flds := strings.Fields(rows[i]) + var ints []int + for j := range flds { + if v, err := strconv.Atoi(flds[j]); err != nil { + return &ret, err + } else { + ints = append(ints, v) + } + } + ret.vals = append(ret.vals, ints) + } + numInRow := -1 + for i := range ret.vals { + if numInRow != -1 { + if len(ret.vals[i]) != numInRow { + return &ret, errors.New("All rows must be equal length") + } + } + numInRow = len(ret.vals[i]) + } + return &ret, nil +} + +func (m *Matrix) Saddle() []Pair { + var ret []Pair + // We're going to get a list of coords for row highs + // then compare that to a list of coords for col lows + var testRows []Pair + for i := range m.vals { + testRows = append(testRows, Pair{i, m.findRowHigh(i)}) + } + fmt.Println(testRows) + return ret + for j := range m.vals[0] { + v := Pair{m.findColLow(j), j} + // If this pair is in testRows, it's a saddle point + for i := range testRows { + if v[0] == testRows[i][0] && v[1] == testRows[i][1] { + ret = append(ret, v) + } + } + } + return ret +} + +// Cols returns the values of the cols in the matrix +func (m *Matrix) Cols() [][]int { + var ret [][]int + for i := range m.vals[0] { + var row []int + for j := range m.vals { + row = append(row, m.vals[j][i]) + } + ret = append(ret, row) + } + return ret +} + +// findColLow finds the lowest value in a column +func (m *Matrix) findColLow(c int) int { + cols := m.Cols() + var idx int + val := -1 + if c >= 0 && c < len(cols) { + for i := range cols[c] { + if cols[c][i] < val || val == -1 { + val = cols[c][i] + idx = i + } + } + } + return idx +} + +// findColLow finds the lowest value in a column +func (m *Matrix) findRowHigh(r int) int { + var idx int + val := -1 + if r >= 0 && r < len(m.vals) { + for i := range m.vals[r] { + if m.vals[r][i] < val || val == -1 { + val = m.vals[r][i] + idx = i + } + } + } + return idx +} diff --git a/go/saddle-points/saddle_points_test.go b/go/saddle-points/saddle_points_test.go new file mode 100644 index 0000000..81e620b --- /dev/null +++ b/go/saddle-points/saddle_points_test.go @@ -0,0 +1,67 @@ +// Short cut! Have you already done the matrix exercise? +// If it seems helpful, copy your code from the matrix exercise +// to this directory so you have access to it. You can leave it as matrix.go +// and start a new file saddle_points.go with additional code that completes +// this exercise. Submit only saddle_points.go for this exercise. + +package matrix + +import "testing" + +var tests = []struct { + m string + sp []Pair +}{ + {"2 1\n1 2", nil}, + {"1 2\n3 4", []Pair{{0, 1}}}, + {"18 3 39 19 91\n38 10 8 77 320\n3 4 8 6 7", []Pair{{2, 2}}}, + {"4 5 4\n3 5 5\n1 5 4", []Pair{{0, 1}, {1, 1}, {2, 1}}}, +} + +func TestSaddle(t *testing.T) { + for _, test := range tests { + m, err := New(test.m) + if err != nil { + t.Fatalf("TestSaddle needs working New. "+ + "New(%s) returned %s. Error not expected.", + test.m, err) + } + if sp := m.Saddle(); !eq(sp, test.sp) { + t.Fatalf("%v.Saddle() = %v, want %v", m, sp, test.sp) + } + } +} + +func eq(got, exp []Pair) bool { + if len(got) != len(exp) { + return false + } +exp: + for _, e := range exp { + for _, g := range got { + if g == e { + continue exp + } + } + return false + } + return true +} + +func BenchmarkSaddle(b *testing.B) { + ms := make([]*Matrix, len(tests)) + var err error + for i, test := range tests { + if ms[i], err = New(test.m); err != nil { + b.Fatalf("BenchmarkSaddle needs working New. "+ + "New(%s) returned %s. Error not expected.", + test.m, err) + } + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, m := range ms { + m.Saddle() + } + } +}