go: lay groundwork for matrix traversal

This commit is contained in:
surtur 2022-09-13 23:39:52 +02:00
parent 76421d76a8
commit 1b361e5146
Signed by: wanderer
SSH Key Fingerprint: SHA256:MdCZyJ2sHLltrLBp0xQO0O1qTW9BT/xl5nXkDvhlMCI
3 changed files with 201 additions and 1 deletions

63
main.go
View File

@ -3,10 +3,71 @@
package main
import "log"
import (
"encoding/csv"
"flag"
"fmt"
"log"
"os"
)
const (
mFlagDescr = "path to a CSV file containing matrix values"
aFlagDescr = "read matrix from stdin-provided arg"
usage = `Usage of diwt:
-m, --matrixfile ` + mFlagDescr + `
-a, --stdin ` + aFlagDescr + `
-h, --help prints help information
`
)
var version = "development"
func main() {
log.Println("starting diwt, version", version)
var f string
var a string
flag.StringVar(&f, "matrixfile", "", mFlagDescr)
flag.StringVar(&f, "m", "", mFlagDescr)
flag.StringVar(&a, "stdin", "", aFlagDescr)
flag.StringVar(&a, "a", "", aFlagDescr)
flag.Usage = func() { fmt.Fprint(os.Stderr, usage) }
flag.Parse()
var r csv.Reader
switch {
case f == "" && a == "":
log.Println("no file provided, bailing...")
os.Exit(3)
case a != "" && f != "":
log.Println(
"only provide one of the flags (file or stdin), not both. " +
"exiting.",
)
os.Exit(4)
case f != "":
r = readFile(f)
case a != "":
r = readArg(a)
}
records, err := r.ReadAll()
if err != nil {
log.Fatalln("error reading records:", err)
}
m := convertMatrix(records)
traverseMatrixMinSumPath(m)
log.Println("looks like we're done here.")
}

104
matrix.go Normal file
View File

@ -0,0 +1,104 @@
// Copyright 2022 wanderer <wanderer at dotya.ml>
// SPDX-License-Identifier: GPL-3.0-or-later
package main
import (
"log"
"os"
"strconv"
"time"
)
type matrix struct {
rows [][]int
}
// stoi attempts to convert a supposed int in string form to an actual int,
// fails loudly if it doesn't work.
func stoi(s string) int {
val, err := strconv.Atoi(s)
if err != nil {
log.Fatalln("could not convert from string to int:", s, err)
}
return val
}
// rowtoi converts a row (a []string) to an []int and returns it.
func rowtoi(row []string) []int {
cols := len(row)
// prealloc, when the size is known, gosimple is wrong here.
intRow := make([]int, cols, cols) //nolint:gosimple
for i, v := range row {
intRow[i] = stoi(v)
}
return intRow
}
// isNonEmptyMatrix checks the [][]string input and determines whether it is a
// non-empty matrix, since that is the kind we care about.
func isNonEmptyMatrix(strmatrix [][]string) bool {
initCols := len(strmatrix[0])
if initCols == 0 || len(strmatrix) == 0 {
log.Printf("emptymatrix: we don't want those")
return false
}
for i, v := range strmatrix {
cols := len(v)
if cols != initCols {
log.Printf("notamatrix: all rows until now were of '%d' columns\noffending row: #%d, size: %d", initCols, i, cols)
return false
}
}
return true
}
func initMatrix(strmatrix [][]string) matrix {
m := &matrix{}
// we can now safely do this because at this point we have already checked
// that strmatrix is a "valid" matrix.
cols := len(strmatrix[0])
rows := len(strmatrix)
// prealloc, when the size is known, gosimple is wrong here.
m.rows = make([][]int, rows, rows) //nolint:gosimple
for i := range strmatrix {
// prealloc, when the size is known, gosimple is wrong here.
m.rows[i] = make([]int, cols, cols) //nolint:gosimple
}
return *m
}
// convertMatrix attempts to convert the whole string matrix to an int matrix.
func convertMatrix(strmatrix [][]string) matrix {
if !isNonEmptyMatrix(strmatrix) {
log.Fatalln("bailing...")
os.Exit(2)
}
m := initMatrix(strmatrix)
for i, v := range strmatrix {
m.rows[i] = rowtoi(v)
}
return m
}
// traverseMatrix traverses the given matrix in such a manner as to accumulate
// the smallest possible sum. allowed movements are down and to the right.
func traverseMatrixMinSumPath(m matrix) { //nolint:unparam
// ad unparam: m will be used shortly.
start := time.Now()
log.Printf("traversing the matrix took: %s", time.Since(start))
}

35
read.go Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2022 wanderer <wanderer at dotya.ml>
// SPDX-License-Identifier: GPL-3.0-or-later
package main
import (
"encoding/csv"
"log"
"os"
"strings"
)
var csvreader *csv.Reader
// readFile tries to open the file passed in func argument and returns a
// *csvreader if the file could be open.
func readFile(fname string) csv.Reader {
f, err := os.Open(fname)
if err != nil {
log.Fatalf("error reading file %s, bailing...\n", fname)
}
csvreader = csv.NewReader(f)
return *csvreader
}
// readArg returns a *csvreader that reads from the passed arg.
func readArg(arg string) csv.Reader {
if arg == "" {
log.Fatalf("the arg is empty, bailing...\n")
}
return *csv.NewReader(strings.NewReader(arg))
}