Allow to set verbosity of output (Closes #26)
This commit is contained in:
parent
2bdcdcb1dd
commit
cced4f04b2
@ -1,5 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
|
import "gitea.ligthert.net/golang/sudoku-funpark/outputter"
|
||||||
|
|
||||||
// Simple interface to store values shared amongst packages.
|
// Simple interface to store values shared amongst packages.
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
// All possible blocks/rows available
|
// All possible blocks/rows available
|
||||||
@ -32,4 +34,8 @@ type Controller struct {
|
|||||||
Part int
|
Part int
|
||||||
// Type of output requested
|
// Type of output requested
|
||||||
Output string
|
Output string
|
||||||
|
// Select printing method
|
||||||
|
Print string
|
||||||
|
// Outputter package
|
||||||
|
Outputter *outputter.Outputter
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package export
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Render JSON output.
|
// Render JSON output.
|
||||||
@ -27,8 +26,8 @@ func (export *Export) renderJSON() (render string) {
|
|||||||
}
|
}
|
||||||
renderBytes, err := json.Marshal(solutions)
|
renderBytes, err := json.Marshal(solutions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR: json.Marshal error:", err)
|
export.Controller.Outputter.Println("ERROR: json.Marshal error:", err)
|
||||||
log.Println("Printing solution as-is:", solutions)
|
export.Controller.Outputter.Println("Printing solution as-is:", solutions)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
render = string(renderBytes)
|
render = string(renderBytes)
|
||||||
|
@ -2,7 +2,7 @@ package flags
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
@ -25,13 +25,14 @@ func (flags *Flags) ParseFlags() {
|
|||||||
flag.IntVar(&flags.Controller.Split, "split", 1, "Split the tasks in n parts. This depends on the availability of the first row.")
|
flag.IntVar(&flags.Controller.Split, "split", 1, "Split the tasks in n parts. This depends on the availability of the first row.")
|
||||||
flag.IntVar(&flags.Controller.Part, "part", 1, "Process part x in n parts. Cannot be lower than 1, or higher than specified in split.")
|
flag.IntVar(&flags.Controller.Part, "part", 1, "Process part x in n parts. Cannot be lower than 1, or higher than specified in split.")
|
||||||
flag.StringVar(&flags.Controller.Output, "output", "human", "Type of output. 'human' for human readable. 'flat' for flat as stored in memory output. 'json' for JSON output.")
|
flag.StringVar(&flags.Controller.Output, "output", "human", "Type of output. 'human' for human readable. 'flat' for flat as stored in memory output. 'json' for JSON output.")
|
||||||
|
flag.StringVar(&flags.Controller.Print, "print", "short", "'short': normal output;'long': normal output with timestamps; 'silent': Only print the results;")
|
||||||
|
|
||||||
// Parse the flags
|
// Parse the flags
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Process any changes to the CPU usage.
|
// Process any changes to the CPU usage.
|
||||||
if flags.Controller.NumCPUs <= 0 {
|
if flags.Controller.NumCPUs <= 0 {
|
||||||
log.Printf("ERROR: Number of CPU cores must be 1 or higher.\n\n")
|
fmt.Printf("ERROR: Number of CPU cores must be 1 or higher.\n\n")
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ func (flags *Flags) ParseFlags() {
|
|||||||
|
|
||||||
// Process rows
|
// Process rows
|
||||||
if flags.Controller.Row1 == "000000000" || flags.Controller.Row2 == "000000000" || flags.Controller.Row3 == "000000000" || flags.Controller.Row4 == "000000000" || flags.Controller.Row5 == "000000000" || flags.Controller.Row6 == "000000000" || flags.Controller.Row7 == "000000000" || flags.Controller.Row8 == "000000000" || flags.Controller.Row9 == "000000000" {
|
if flags.Controller.Row1 == "000000000" || flags.Controller.Row2 == "000000000" || flags.Controller.Row3 == "000000000" || flags.Controller.Row4 == "000000000" || flags.Controller.Row5 == "000000000" || flags.Controller.Row6 == "000000000" || flags.Controller.Row7 == "000000000" || flags.Controller.Row8 == "000000000" || flags.Controller.Row9 == "000000000" {
|
||||||
log.Printf("ERROR: All parameters must be entered.\n\n")
|
fmt.Printf("ERROR: All parameters must be entered.\n\n")
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -61,14 +62,14 @@ func (flags *Flags) ParseFlags() {
|
|||||||
// Process workload splitting
|
// Process workload splitting
|
||||||
// Ensure split and part are 1 or higher
|
// Ensure split and part are 1 or higher
|
||||||
if flags.Controller.Split <= 0 || flags.Controller.Part <= 0 {
|
if flags.Controller.Split <= 0 || flags.Controller.Part <= 0 {
|
||||||
log.Printf("ERROR: '-split' and '-part' need to be 1 or higher.\n")
|
fmt.Printf("ERROR: '-split' and '-part' need to be 1 or higher.\n")
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure part is between 1 and split
|
// Ensure part is between 1 and split
|
||||||
if flags.Controller.Part > flags.Controller.Split {
|
if flags.Controller.Part > flags.Controller.Split {
|
||||||
log.Printf("ERROR: '-part' cannot be bigger than `-split`.\n")
|
fmt.Printf("ERROR: '-part' cannot be bigger than `-split`.\n")
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -76,7 +77,15 @@ func (flags *Flags) ParseFlags() {
|
|||||||
// Process output selection
|
// Process output selection
|
||||||
flags.Controller.Output = strings.ToLower(flags.Controller.Output)
|
flags.Controller.Output = strings.ToLower(flags.Controller.Output)
|
||||||
if flags.Controller.Output != "human" && flags.Controller.Output != "flat" && flags.Controller.Output != "json" {
|
if flags.Controller.Output != "human" && flags.Controller.Output != "flat" && flags.Controller.Output != "json" {
|
||||||
log.Printf("ERROR: Invalid output, can only be 'human' or 'flat'.\n")
|
fmt.Printf("ERROR: Invalid output, can only be 'human' or 'flat' or 'json'.\n")
|
||||||
|
flags.printUsage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process print selection
|
||||||
|
flags.Controller.Print = strings.ToLower(flags.Controller.Print)
|
||||||
|
if flags.Controller.Print != "short" && flags.Controller.Print != "long" && flags.Controller.Print != "silent" {
|
||||||
|
fmt.Printf("ERROR: Invalid Print, can only be 'short' or 'long' or 'silent'.\n")
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package flags
|
package flags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
|||||||
|
|
||||||
// 1. Make sure the row is 9 in length
|
// 1. Make sure the row is 9 in length
|
||||||
if len(row) != 9 {
|
if len(row) != 9 {
|
||||||
log.Printf("ERROR: Invalid length of %s (%s), must be 9 numbers\n\n", name, row)
|
fmt.Printf("ERROR: Invalid length of %s (%s), must be 9 numbers\n\n", name, row)
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
log.Printf("ERROR: Invalid character of %s (%s), must be 9 numbers\n\n", name, row)
|
fmt.Printf("ERROR: Invalid character of %s (%s), must be 9 numbers\n\n", name, row)
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if double {
|
if double {
|
||||||
log.Printf("ERROR: Double character of %s (%s), numbers between 1 and 9 may only be entered once\n\n", name, row)
|
fmt.Printf("ERROR: Double character of %s (%s), numbers between 1 and 9 may only be entered once\n\n", name, row)
|
||||||
flags.printUsage()
|
flags.printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
15
main.go
15
main.go
@ -1,29 +1,34 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"gitea.ligthert.net/golang/sudoku-funpark/controller"
|
"gitea.ligthert.net/golang/sudoku-funpark/controller"
|
||||||
"gitea.ligthert.net/golang/sudoku-funpark/export"
|
"gitea.ligthert.net/golang/sudoku-funpark/export"
|
||||||
"gitea.ligthert.net/golang/sudoku-funpark/flags"
|
"gitea.ligthert.net/golang/sudoku-funpark/flags"
|
||||||
|
"gitea.ligthert.net/golang/sudoku-funpark/outputter"
|
||||||
"gitea.ligthert.net/golang/sudoku-funpark/solver"
|
"gitea.ligthert.net/golang/sudoku-funpark/solver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Instantiate the interfaces
|
// Instantiate the interfaces
|
||||||
controller := controller.Controller{}
|
controller := controller.Controller{}
|
||||||
|
outp := outputter.Outputter{}
|
||||||
export := export.Export{Controller: &controller}
|
export := export.Export{Controller: &controller}
|
||||||
flags := flags.Flags{Controller: &controller}
|
flags := flags.Flags{Controller: &controller}
|
||||||
solver := solver.Solver{Controller: &controller}
|
solver := solver.Solver{Controller: &controller, Outp: &outp}
|
||||||
|
|
||||||
// Parse and handle flags
|
// Parse and handle flags
|
||||||
flags.ParseFlags()
|
flags.ParseFlags()
|
||||||
|
|
||||||
|
// Tell outp what kind of output is expected.
|
||||||
|
outp.OutputType = controller.Print
|
||||||
|
|
||||||
// Report number of CPUs being used, if set.
|
// Report number of CPUs being used, if set.
|
||||||
if runtime.NumCPU() != controller.NumCPUs {
|
if runtime.NumCPU() != controller.NumCPUs {
|
||||||
log.Println("Using " + strconv.Itoa(controller.NumCPUs) + " CPUs, (was " + strconv.Itoa(runtime.NumCPU()) + ")")
|
outp.Println("Using " + strconv.Itoa(controller.NumCPUs) + " CPUs, (was " + strconv.Itoa(runtime.NumCPU()) + ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load blocks from CSV file
|
// Load blocks from CSV file
|
||||||
@ -39,12 +44,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print the total number of solutions to validate
|
// Print the total number of solutions to validate
|
||||||
log.Println("Number of (potential) solutions:", solver.Iter)
|
outp.Println("Number of (potential) solutions:", solver.Iter)
|
||||||
|
|
||||||
// Check the number of solutions
|
// Check the number of solutions
|
||||||
go solver.CheckCombinations()
|
go solver.CheckCombinations()
|
||||||
solver.Tracker()
|
solver.Tracker()
|
||||||
|
|
||||||
log.Println(export.Export())
|
fmt.Println(export.Export())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
17
outputter/Printf.go
Normal file
17
outputter/Printf.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package outputter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (outputter *Outputter) Printf(format string, args ...any) {
|
||||||
|
switch outputter.OutputType {
|
||||||
|
case "short":
|
||||||
|
fmt.Printf(format, args...)
|
||||||
|
case "long":
|
||||||
|
log.Printf(format, args...)
|
||||||
|
case "silent":
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
17
outputter/Println.go
Normal file
17
outputter/Println.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package outputter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (outputter *Outputter) Println(msg ...any) {
|
||||||
|
switch outputter.OutputType {
|
||||||
|
case "short":
|
||||||
|
fmt.Println(msg...)
|
||||||
|
case "long":
|
||||||
|
log.Println(msg...)
|
||||||
|
case "silent":
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
5
outputter/types.go
Normal file
5
outputter/types.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package outputter
|
||||||
|
|
||||||
|
type Outputter struct {
|
||||||
|
OutputType string
|
||||||
|
}
|
@ -2,7 +2,6 @@ package solver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"log"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -15,8 +14,8 @@ var f embed.FS
|
|||||||
// Load all possible blocks from CSV in to memory
|
// Load all possible blocks from CSV in to memory
|
||||||
func (solver *Solver) LoadBlocks() {
|
func (solver *Solver) LoadBlocks() {
|
||||||
|
|
||||||
defer solver.timeTrack(time.Now(), "Loaded blocks")
|
defer solver.timeTrack(time.Now(), "Done!")
|
||||||
log.Println("Loading blocks")
|
solver.Outp.Printf("Loading blocks... ")
|
||||||
|
|
||||||
var blocks []string
|
var blocks []string
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
package solver
|
package solver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Find all possible blocks that can be used to find a solution.
|
// Find all possible blocks that can be used to find a solution.
|
||||||
func (solver *Solver) PopulateBlocks() {
|
func (solver *Solver) PopulateBlocks() {
|
||||||
|
|
||||||
defer solver.timeTrack(time.Now(), "Populated blocks")
|
defer solver.timeTrack(time.Now(), "Done!")
|
||||||
log.Println("Populating blocks")
|
solver.Outp.Printf("Populating blocks... ")
|
||||||
|
|
||||||
solver.findBlocks(&solver.Controller.Row1, &solver.row1s)
|
solver.findBlocks(&solver.Controller.Row1, &solver.row1s)
|
||||||
solver.findBlocks(&solver.Controller.Row2, &solver.row2s)
|
solver.findBlocks(&solver.Controller.Row2, &solver.row2s)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package solver
|
package solver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -12,12 +11,12 @@ import (
|
|||||||
// Modify solver.row1s so it limits the workload to what is only desired
|
// Modify solver.row1s so it limits the workload to what is only desired
|
||||||
func (solver *Solver) SelectWorkload() {
|
func (solver *Solver) SelectWorkload() {
|
||||||
if solver.Controller.Split > len(solver.row1s) {
|
if solver.Controller.Split > len(solver.row1s) {
|
||||||
log.Println("ERROR: Unable to divide the workload in " + strconv.Itoa(solver.Controller.Split) + " parts, when only " + strconv.Itoa(len(solver.row1s)) + " are available.\n\n")
|
solver.Outp.Println("ERROR: Unable to divide the workload in " + strconv.Itoa(solver.Controller.Split) + " parts, when only " + strconv.Itoa(len(solver.row1s)) + " are available.\n\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer solver.timeTrack(time.Now(), "Workload set")
|
defer solver.timeTrack(time.Now(), "Workload set")
|
||||||
log.Println("Setting workload")
|
solver.Outp.Println("Setting workload")
|
||||||
log.Println("We are agent " + strconv.Itoa(solver.Controller.Part) + " of " + strconv.Itoa(solver.Controller.Split))
|
solver.Outp.Println("We are agent " + strconv.Itoa(solver.Controller.Part) + " of " + strconv.Itoa(solver.Controller.Split))
|
||||||
workloads := solver.splitWorkload()
|
workloads := solver.splitWorkload()
|
||||||
solver.setWorkload(workloads)
|
solver.setWorkload(workloads)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package solver
|
package solver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -12,7 +11,7 @@ func (solver *Solver) Tracker() {
|
|||||||
|
|
||||||
// Add time tracking
|
// Add time tracking
|
||||||
defer solver.timeTrack(time.Now(), "Validated solutions")
|
defer solver.timeTrack(time.Now(), "Validated solutions")
|
||||||
log.Println("Validating solutions")
|
solver.Outp.Println("Validating solutions")
|
||||||
|
|
||||||
// Determine if the main-loop is done
|
// Determine if the main-loop is done
|
||||||
var done bool
|
var done bool
|
||||||
@ -73,7 +72,7 @@ func (solver *Solver) Tracker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Printing the progress
|
// Printing the progress
|
||||||
log.Println("Processing: " + strconv.Itoa(int(percentage)) + "% (" + strconv.FormatUint(solver.counter.Load(), 10) + "/" + strconv.Itoa(int(solver.Iter)) + "); Rate: " + strconv.FormatUint(rateDiff, 10) + "/sec for " + timer_elapsed.String() + "; Time left (est.): " + est_fin)
|
solver.Outp.Println("Processing: " + strconv.Itoa(int(percentage)) + "% (" + strconv.FormatUint(solver.counter.Load(), 10) + "/" + strconv.Itoa(int(solver.Iter)) + "); Rate: " + strconv.FormatUint(rateDiff, 10) + "/sec for " + timer_elapsed.String() + "; Time left (est.): " + est_fin)
|
||||||
|
|
||||||
// After we are done printing, exit this for-loop
|
// After we are done printing, exit this for-loop
|
||||||
if percentage == 100 {
|
if percentage == 100 {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package solver
|
package solver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -9,5 +8,5 @@ import (
|
|||||||
// Use with `defer`
|
// Use with `defer`
|
||||||
func (solver *Solver) timeTrack(start time.Time, msg string) {
|
func (solver *Solver) timeTrack(start time.Time, msg string) {
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
log.Printf("%s (%s)", msg, elapsed)
|
solver.Outp.Printf("%s (%s)\n", msg, elapsed)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"gitea.ligthert.net/golang/sudoku-funpark/controller"
|
"gitea.ligthert.net/golang/sudoku-funpark/controller"
|
||||||
|
"gitea.ligthert.net/golang/sudoku-funpark/outputter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Solve a given Sudoku puzzle by iterating through all possible solutions.
|
// Solve a given Sudoku puzzle by iterating through all possible solutions.
|
||||||
@ -33,4 +34,6 @@ type Solver struct {
|
|||||||
counter atomic.Uint64
|
counter atomic.Uint64
|
||||||
// Slice of rates for accurate duration estimation.
|
// Slice of rates for accurate duration estimation.
|
||||||
rates []uint64
|
rates []uint64
|
||||||
|
// Reference to Outputter interface
|
||||||
|
Outp *outputter.Outputter
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user