Compare commits
5 Commits
b83d6bdde4
...
v20250128
Author | SHA1 | Date | |
---|---|---|---|
cd54fdf345 | |||
cced4f04b2 | |||
2bdcdcb1dd | |||
71fefd760e | |||
2461f5b417 |
74
README.md
74
README.md
@ -15,13 +15,17 @@ I wrote [a blog post](https://blog.ligthert.net/posts/exploration-fun-and-proces
|
||||
* Split workloads among several computers
|
||||
|
||||
## Usage
|
||||
To use the sudoku solver, run the binary with all the parameters available:
|
||||
To use the sudoku solver, run the binary with all the `-row` parameters available. Use other parameters to tune our output or CPU usage.
|
||||
```
|
||||
Usage of ./sudoku-funpark:
|
||||
-numcpu int
|
||||
Number of CPU cores to assign to this task. (default 12)
|
||||
-output string
|
||||
Type of output. 'human' for human readable. 'flat' for flat as stored in memory output. 'json' for JSON output. (default "human")
|
||||
-part int
|
||||
Process part x in n parts. Cannot be lower than 1, or higher than specified in split. (default 1)
|
||||
-print string
|
||||
'short': normal output;'long': normal output with timestamps; 'silent': Only print the results; (default "short")
|
||||
-row1 string
|
||||
1st row of the sudoku puzzle. (default "000000000")
|
||||
-row2 string
|
||||
@ -50,7 +54,7 @@ Instead of using the 3x3 blocks with 3x3 digits, it uses horizontal rows from to
|
||||
## Example
|
||||
To see the solver in action, run the tool with the following parameters.
|
||||
|
||||
For a short running (~15 seconds) example:
|
||||
For a short running (~14 seconds) example:
|
||||
> $ ./sudoku-funpark -row1 769104802 -row2 154800060 -row3 832700154 -row4 600900328 -row5 045328670 -row6 328670945 -row7 597410280 -row8 006283090 -row9 200590006
|
||||
|
||||
For a long running (~1 hours 15 minutes) example:
|
||||
@ -58,40 +62,40 @@ For a long running (~1 hours 15 minutes) example:
|
||||
|
||||
The outpot (of the short running parameters) will look something like this:
|
||||
```
|
||||
./sudoku-funpark -row1 769104802 -row2 154800060 -row3 832700154 -row4 600900328 -row5 045328670 -row6 328670945 -row7 597410280 -row8 006283090 -row9 200590006
|
||||
2025/01/24 00:05:58 Loading blocks
|
||||
2025/01/24 00:05:58 Loaded blocks (34.587221ms)
|
||||
2025/01/24 00:05:58 Populating blocks
|
||||
2025/01/24 00:05:58 Populated blocks (438.73054ms)
|
||||
2025/01/24 00:05:58 Number of (potential) solutions: 26542080
|
||||
2025/01/24 00:05:58 Validating solutions
|
||||
2025/01/24 00:05:59 Processing: 6% (1729332/26542080); Rate (avg): 1729330/sec for 1.000003166s; Time left (est.): 14 seconds
|
||||
2025/01/24 00:06:00 Processing: 13% (3461753/26542080); Rate (avg): 1732418/sec for 1.000002285s; Time left (est.): 13 seconds
|
||||
2025/01/24 00:06:01 Processing: 19% (5228965/26542080); Rate (avg): 1767215/sec for 1.000019297s; Time left (est.): 12 seconds
|
||||
2025/01/24 00:06:02 Processing: 26% (6996958/26542080); Rate (avg): 1767992/sec for 1.000200176s; Time left (est.): 11 seconds
|
||||
2025/01/24 00:06:03 Processing: 33% (8767450/26542080); Rate (avg): 1770495/sec for 1.000016352s; Time left (est.): 10 seconds
|
||||
2025/01/24 00:06:04 Processing: 39% (10576900/26542080); Rate (avg): 1809450/sec for 1.000014638s; Time left (est.): 8 seconds
|
||||
2025/01/24 00:06:05 Processing: 46% (12400058/26542080); Rate (avg): 1823158/sec for 1.000352862s; Time left (est.): 7 seconds
|
||||
2025/01/24 00:06:06 Processing: 53% (14185155/26542080); Rate (avg): 1785095/sec for 1.000254888s; Time left (est.): 6 seconds
|
||||
2025/01/24 00:06:07 Processing: 60% (15968402/26542080); Rate (avg): 1783245/sec for 1.000002305s; Time left (est.): 5 seconds
|
||||
2025/01/24 00:06:08 Processing: 66% (17655770/26542080); Rate (avg): 1687370/sec for 1.000068309s; Time left (est.): 5 seconds
|
||||
2025/01/24 00:06:09 Processing: 73% (19442885/26542080); Rate (avg): 1787111/sec for 1.000006984s; Time left (est.): 3 seconds
|
||||
2025/01/24 00:06:10 Processing: 79% (21183545/26542080); Rate (avg): 1740661/sec for 1.000002395s; Time left (est.): 3 seconds
|
||||
2025/01/24 00:06:11 Processing: 86% (22998945/26542080); Rate (avg): 1815402/sec for 1.000113534s; Time left (est.): 1 second
|
||||
2025/01/24 00:06:12 Processing: 90% (24109203/26542080); Rate (avg): 1110261/sec for 1.000312346s; Time left (est.): 2 seconds
|
||||
2025/01/24 00:06:13 Processing: 100% (26542080/26542080); Rate (avg): 0/sec for 1.000117421s; Time left (est.): N/A
|
||||
2025/01/24 00:06:13 Validated solutions (15.002654066s)
|
||||
2025/01/24 00:06:13
|
||||
./sudoku-funpark -row1 769104802 -row2 154800060 -row3 832700154 -row4 600900328 -row5 045328670 -row6 328670945 -row7 597410280 -row8 006283090 -row9 200590006
|
||||
Loading blocks... Done! (38.957376ms)
|
||||
Populating blocks... Done! (92.087174ms)
|
||||
Number of (potential) solutions: 26542080
|
||||
Validating solutions
|
||||
Processing: 8% (2131893/26542080); Rate: 2131884/sec for 1.000028115s; Time left (est.): 11s
|
||||
Processing: 16% (4292163/26542080); Rate: 2160219/sec for 1.000087826s; Time left (est.): 10s
|
||||
Processing: 24% (6438334/26542080); Rate: 2146157/sec for 1.000017364s; Time left (est.): 9s
|
||||
Processing: 32% (8529362/26542080); Rate: 2090965/sec for 1.000367121s; Time left (est.): 8s
|
||||
Processing: 40% (10737065/26542080); Rate: 2207530/sec for 1.000072427s; Time left (est.): 7s
|
||||
Processing: 48% (12958905/26542080); Rate: 2221755/sec for 1.000003187s; Time left (est.): 6s
|
||||
Processing: 57% (15163877/26542080); Rate: 2204929/sec for 1.000002717s; Time left (est.): 5s
|
||||
Processing: 65% (17254760/26542080); Rate: 2090742/sec for 1.00008452s; Time left (est.): 4s
|
||||
Processing: 73% (19513142/26542080); Rate: 2258348/sec for 1.000071076s; Time left (est.): 3s
|
||||
Processing: 82% (21795213/26542080); Rate: 2282028/sec for 1.000076024s; Time left (est.): 2s
|
||||
Processing: 90% (24048891/26542080); Rate: 2253645/sec for 1.000146957s; Time left (est.): 1s
|
||||
Processing: 98% (26226252/26542080); Rate: 2177215/sec for 1.000129955s; Time left (est.): 0s
|
||||
Processing: 100% (26542080/26542080); Rate: 315792/sec for 1.000105149s; Time left (est.): 0s
|
||||
Validated solutions (13.001683829s)
|
||||
|
||||
Solution #1:
|
||||
769154832
|
||||
154832769
|
||||
832769154
|
||||
671945328
|
||||
945328671
|
||||
328671945
|
||||
597416283
|
||||
416283597
|
||||
283597416
|
||||
╔═══════════╗
|
||||
║769│154│832╢
|
||||
║154│832│769╢
|
||||
║832│769│154╢
|
||||
╟───┼───┼───╢
|
||||
║671│945│328╢
|
||||
║945│328│671╢
|
||||
║328│671│945╢
|
||||
╟───┼───┼───╢
|
||||
║597│416│283╢
|
||||
║416│283│597╢
|
||||
║283│597│416╢
|
||||
╚═══════════╝
|
||||
```
|
||||
|
||||
## Caveats
|
||||
|
@ -1,5 +1,7 @@
|
||||
package controller
|
||||
|
||||
import "gitea.ligthert.net/golang/sudoku-funpark/outputter"
|
||||
|
||||
// Simple interface to store values shared amongst packages.
|
||||
type Controller struct {
|
||||
// All possible blocks/rows available
|
||||
@ -32,4 +34,8 @@ type Controller struct {
|
||||
Part int
|
||||
// Type of output requested
|
||||
Output string
|
||||
// Select printing method
|
||||
Print string
|
||||
// Outputter package
|
||||
Outputter *outputter.Outputter
|
||||
}
|
||||
|
14
export/Export.go
Normal file
14
export/Export.go
Normal file
@ -0,0 +1,14 @@
|
||||
package export
|
||||
|
||||
func (export *Export) Export() (render string) {
|
||||
// Print the valid solutions
|
||||
switch export.Controller.Output {
|
||||
case "human":
|
||||
render = export.renderHumanReadable()
|
||||
case "flat":
|
||||
render = export.renderFlat()
|
||||
case "json":
|
||||
render = export.renderJSON()
|
||||
}
|
||||
return
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Print solutions into a human friendly format for in the console.
|
||||
func (export *Export) PrintFlatSolutions() {
|
||||
for solutionIndex, solution := range export.Controller.Solutions {
|
||||
log.Printf("\nSolution #%d:", solutionIndex+1)
|
||||
fmt.Println(solution)
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// Print solutions into a human friendly format for in the console.
|
||||
func (export *Export) PrintHumanReadableSolutions() {
|
||||
for solutionIndex, solution := range export.Controller.Solutions {
|
||||
log.Printf("\nSolution #%d:", solutionIndex+1)
|
||||
fmt.Println("╔═══════════╗")
|
||||
for rowIndex, row := range solution {
|
||||
if rowIndex == 3 || rowIndex == 6 {
|
||||
fmt.Println("╟───┼───┼───╢")
|
||||
}
|
||||
fmt.Println("║" + row[0:3] + "│" + row[3:6] + "│" + row[6:9] + "╢")
|
||||
}
|
||||
fmt.Println("╚═══════════╝")
|
||||
}
|
||||
}
|
15
export/renderFlat.go
Normal file
15
export/renderFlat.go
Normal file
@ -0,0 +1,15 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Render output as stored internally.
|
||||
func (export *Export) renderFlat() (render string) {
|
||||
for solutionIndex, solution := range export.Controller.Solutions {
|
||||
render += fmt.Sprintln("\nSolution #" + strconv.Itoa(solutionIndex+1) + ":")
|
||||
render += fmt.Sprintln(solution)
|
||||
}
|
||||
return
|
||||
}
|
22
export/renderHumanReadable.go
Normal file
22
export/renderHumanReadable.go
Normal file
@ -0,0 +1,22 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Render solutions in a human friendly format.
|
||||
func (export *Export) renderHumanReadable() (render string) {
|
||||
for solutionIndex, solution := range export.Controller.Solutions {
|
||||
render += fmt.Sprintln("\nSolution #" + strconv.Itoa(solutionIndex+1) + ":")
|
||||
render += fmt.Sprintln("╔═══════════╗")
|
||||
for rowIndex, row := range solution {
|
||||
if rowIndex == 3 || rowIndex == 6 {
|
||||
render += fmt.Sprintln("╟───┼───┼───╢")
|
||||
}
|
||||
render += fmt.Sprintln("║" + row[0:3] + "│" + row[3:6] + "│" + row[6:9] + "╢")
|
||||
}
|
||||
render += fmt.Sprintln("╚═══════════╝")
|
||||
}
|
||||
return
|
||||
}
|
35
export/renderJSON.go
Normal file
35
export/renderJSON.go
Normal file
@ -0,0 +1,35 @@
|
||||
package export
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Render JSON output.
|
||||
func (export *Export) renderJSON() (render string) {
|
||||
type solution_type map[string]any
|
||||
solutions := make([]solution_type, 0)
|
||||
|
||||
for solutionIndex, solution := range export.Controller.Solutions {
|
||||
solutionMap := map[string]any{
|
||||
"order": solutionIndex,
|
||||
"row1": solution[0],
|
||||
"row2": solution[1],
|
||||
"row3": solution[2],
|
||||
"row4": solution[3],
|
||||
"row5": solution[4],
|
||||
"row6": solution[5],
|
||||
"row7": solution[6],
|
||||
"row8": solution[7],
|
||||
"row9": solution[8],
|
||||
}
|
||||
solutions = append(solutions, solutionMap)
|
||||
}
|
||||
renderBytes, err := json.Marshal(solutions)
|
||||
if err != nil {
|
||||
export.Controller.Outputter.Println("ERROR: json.Marshal error:", err)
|
||||
export.Controller.Outputter.Println("Printing solution as-is:", solutions)
|
||||
return ""
|
||||
}
|
||||
render = string(renderBytes)
|
||||
return
|
||||
}
|
@ -2,7 +2,7 @@ package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -24,14 +24,15 @@ func (flags *Flags) ParseFlags() {
|
||||
flag.IntVar(&flags.Controller.NumCPUs, "numcpu", runtime.NumCPU(), "Number of CPU cores to assign to this task.")
|
||||
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.StringVar(&flags.Controller.Output, "output", "human", "Type of output. 'human' for human readable. 'flat' for flat as stored in memory 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
|
||||
flag.Parse()
|
||||
|
||||
// Process any changes to the CPU usage.
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -42,7 +43,7 @@ func (flags *Flags) ParseFlags() {
|
||||
|
||||
// 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" {
|
||||
log.Printf("ERROR: All parameters must be entered.\n\n")
|
||||
fmt.Printf("ERROR: All parameters must be entered.\n\n")
|
||||
flags.printUsage()
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -61,22 +62,30 @@ func (flags *Flags) ParseFlags() {
|
||||
// Process workload splitting
|
||||
// Ensure split and part are 1 or higher
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Ensure part is between 1 and 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()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Process output selection
|
||||
flags.Controller.Output = strings.ToLower(flags.Controller.Output)
|
||||
if flags.Controller.Output != "human" && flags.Controller.Output != "flat" {
|
||||
log.Printf("ERROR: Invalid output, can only be 'human' or 'flat'.\n")
|
||||
if flags.Controller.Output != "human" && flags.Controller.Output != "flat" && flags.Controller.Output != "json" {
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
@ -6,19 +6,6 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// Validate if the char provided is 0-9
|
||||
func (flags *Flags) validChar(char rune) (valid bool) {
|
||||
decvals := [10]int{48, 49, 50, 51, 52, 53, 54, 55, 56, 57}
|
||||
|
||||
for _, value := range decvals {
|
||||
if char == rune(value) {
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Print help information for the end-user
|
||||
func (flags *Flags) printUsage() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0])
|
||||
|
14
flags/validChar.go
Normal file
14
flags/validChar.go
Normal file
@ -0,0 +1,14 @@
|
||||
package flags
|
||||
|
||||
// Validate if the char provided is 0-9
|
||||
func (flags *Flags) validChar(char rune) (valid bool) {
|
||||
decvals := [10]int{48, 49, 50, 51, 52, 53, 54, 55, 56, 57}
|
||||
|
||||
for _, value := range decvals {
|
||||
if char == rune(value) {
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
@ -18,7 +18,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
||||
|
||||
// 1. Make sure the row is 9 in length
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -29,7 +29,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
||||
}
|
||||
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
@ -46,7 +46,7 @@ func (flags *Flags) validateRow(name string, row string) {
|
||||
}
|
||||
|
||||
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()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
21
main.go
21
main.go
@ -1,29 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"gitea.ligthert.net/golang/sudoku-funpark/controller"
|
||||
"gitea.ligthert.net/golang/sudoku-funpark/export"
|
||||
"gitea.ligthert.net/golang/sudoku-funpark/flags"
|
||||
"gitea.ligthert.net/golang/sudoku-funpark/outputter"
|
||||
"gitea.ligthert.net/golang/sudoku-funpark/solver"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Instantiate the interfaces
|
||||
controller := controller.Controller{}
|
||||
outp := outputter.Outputter{}
|
||||
export := export.Export{Controller: &controller}
|
||||
flags := flags.Flags{Controller: &controller}
|
||||
solver := solver.Solver{Controller: &controller}
|
||||
solver := solver.Solver{Controller: &controller, Outp: &outp}
|
||||
|
||||
// Parse and handle flags
|
||||
flags.ParseFlags()
|
||||
|
||||
// Tell outp what kind of output is expected.
|
||||
outp.OutputType = controller.Print
|
||||
|
||||
// Report number of CPUs being used, if set.
|
||||
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
|
||||
@ -39,18 +44,12 @@ func main() {
|
||||
}
|
||||
|
||||
// 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
|
||||
go solver.CheckCombinations()
|
||||
solver.Tracker()
|
||||
|
||||
// Print the valid solutions
|
||||
switch controller.Output {
|
||||
case "human":
|
||||
export.PrintHumanReadableSolutions()
|
||||
case "flat":
|
||||
export.PrintFlatSolutions()
|
||||
}
|
||||
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 (
|
||||
"embed"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -15,8 +14,8 @@ var f embed.FS
|
||||
// Load all possible blocks from CSV in to memory
|
||||
func (solver *Solver) LoadBlocks() {
|
||||
|
||||
defer solver.timeTrack(time.Now(), "Loaded blocks")
|
||||
log.Println("Loading blocks")
|
||||
defer solver.timeTrack(time.Now(), "Done!")
|
||||
solver.Outp.Printf("Loading blocks... ")
|
||||
|
||||
var blocks []string
|
||||
|
||||
|
@ -1,15 +1,14 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Find all possible blocks that can be used to find a solution.
|
||||
func (solver *Solver) PopulateBlocks() {
|
||||
|
||||
defer solver.timeTrack(time.Now(), "Populated blocks")
|
||||
log.Println("Populating blocks")
|
||||
defer solver.timeTrack(time.Now(), "Done!")
|
||||
solver.Outp.Printf("Populating blocks... ")
|
||||
|
||||
solver.findBlocks(&solver.Controller.Row1, &solver.row1s)
|
||||
solver.findBlocks(&solver.Controller.Row2, &solver.row2s)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -12,12 +11,12 @@ import (
|
||||
// Modify solver.row1s so it limits the workload to what is only desired
|
||||
func (solver *Solver) SelectWorkload() {
|
||||
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)
|
||||
}
|
||||
defer solver.timeTrack(time.Now(), "Workload set")
|
||||
log.Println("Setting workload")
|
||||
log.Println("We are agent " + strconv.Itoa(solver.Controller.Part) + " of " + strconv.Itoa(solver.Controller.Split))
|
||||
solver.Outp.Println("Setting workload")
|
||||
solver.Outp.Println("We are agent " + strconv.Itoa(solver.Controller.Part) + " of " + strconv.Itoa(solver.Controller.Split))
|
||||
workloads := solver.splitWorkload()
|
||||
solver.setWorkload(workloads)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
@ -12,7 +11,7 @@ func (solver *Solver) Tracker() {
|
||||
|
||||
// Add time tracking
|
||||
defer solver.timeTrack(time.Now(), "Validated solutions")
|
||||
log.Println("Validating solutions")
|
||||
solver.Outp.Println("Validating solutions")
|
||||
|
||||
// Determine if the main-loop is done
|
||||
var done bool
|
||||
@ -73,7 +72,7 @@ func (solver *Solver) Tracker() {
|
||||
}
|
||||
|
||||
// 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
|
||||
if percentage == 100 {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package solver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -9,5 +8,5 @@ import (
|
||||
// Use with `defer`
|
||||
func (solver *Solver) timeTrack(start time.Time, msg string) {
|
||||
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"
|
||||
|
||||
"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.
|
||||
@ -33,4 +34,6 @@ type Solver struct {
|
||||
counter atomic.Uint64
|
||||
// Slice of rates for accurate duration estimation.
|
||||
rates []uint64
|
||||
// Reference to Outputter interface
|
||||
Outp *outputter.Outputter
|
||||
}
|
||||
|
Reference in New Issue
Block a user