Move solver.Run() into main(). Split flags into its own separate interface.

This commit is contained in:
2025-01-27 21:47:35 +01:00
parent 51f5d6d77d
commit 38207ceda3
11 changed files with 256 additions and 252 deletions

136
flags/parse.go Normal file
View File

@ -0,0 +1,136 @@
package flags
import (
"flag"
"fmt"
"log"
"os"
"runtime"
)
func (flags *Flags) ParseFlags() {
// Define parameters
flag.StringVar(&flags.Row1, "row1", "000000000", "1st row of the sudoku puzzle.")
flag.StringVar(&flags.Row2, "row2", "000000000", "2nd row of the sudoku puzzle.")
flag.StringVar(&flags.Row3, "row3", "000000000", "4rd row of the sudoku puzzle.")
flag.StringVar(&flags.Row4, "row4", "000000000", "4th row of the sudoku puzzle.")
flag.StringVar(&flags.Row5, "row5", "000000000", "5th row of the sudoku puzzle.")
flag.StringVar(&flags.Row6, "row6", "000000000", "6th row of the sudoku puzzle.")
flag.StringVar(&flags.Row7, "row7", "000000000", "7th row of the sudoku puzzle.")
flag.StringVar(&flags.Row8, "row8", "000000000", "8th row of the sudoku puzzle.")
flag.StringVar(&flags.Row9, "row9", "000000000", "9th row of the sudoku puzzle.")
flag.IntVar(&flags.NumCPUs, "numcpu", runtime.NumCPU(), "Number of CPU cores to assign to this task.")
flag.IntVar(&flags.Split, "split", 1, "Split the tasks in n parts. This depends on the availability of the first row.")
flag.IntVar(&flags.Part, "part", 1, "Process part x in n parts. Cannot be lower than 1, or higher than specified in split.")
// Parse the flags
flag.Parse()
// Process any changes to the CPU usage.
if flags.NumCPUs <= 0 {
log.Printf("ERROR: Number of CPU cores must be 1 or higher.\n\n")
flags.printUsage()
os.Exit(1)
}
if flags.NumCPUs != runtime.NumCPU() {
runtime.GOMAXPROCS(flags.NumCPUs)
}
// Process rows
if flags.Row1 == "000000000" || flags.Row2 == "000000000" || flags.Row3 == "000000000" || flags.Row4 == "000000000" || flags.Row5 == "000000000" || flags.Row6 == "000000000" || flags.Row7 == "000000000" || flags.Row8 == "000000000" || flags.Row9 == "000000000" {
log.Printf("ERROR: All parameters must be entered.\n\n")
flags.printUsage()
os.Exit(1)
}
// Validate the row (never trust user input)
flags.validateRow("row1", flags.Row1)
flags.validateRow("row2", flags.Row2)
flags.validateRow("row3", flags.Row3)
flags.validateRow("row4", flags.Row4)
flags.validateRow("row5", flags.Row5)
flags.validateRow("row6", flags.Row6)
flags.validateRow("row7", flags.Row7)
flags.validateRow("row8", flags.Row8)
flags.validateRow("row9", flags.Row9)
// Process workload splitting
// Ensure split and part are 1 or higher
if flags.Split <= 0 || flags.Part <= 0 {
log.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.Part > flags.Split {
log.Printf("ERROR: '-part' cannot be bigger than `-split`.\n")
flags.printUsage()
os.Exit(1)
}
}
func (flags *Flags) validateRow(name string, row string) {
var found bool
var double bool
count := make(map[rune]int)
// 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)
flags.printUsage()
os.Exit(1)
}
// 2. Ensure all digits are numbers
for _, value := range row {
found = flags.validChar(value)
}
if !found {
log.Printf("ERROR: Invalid character of %s (%s), must be 9 numbers\n\n", name, row)
flags.printUsage()
os.Exit(1)
}
// 3. Ensure all digits (except zero) are there only once
for _, digits := range row {
count[digits] = count[digits] + 1
}
for key, value := range count {
if value > 1 && key != 48 {
double = true
}
}
if double {
log.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)
}
}
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
}
func (flags *Flags) printUsage() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0])
fmt.Fprintf(flag.CommandLine.Output(), "\nPut every row of a Sudoku puzzle as paramters.\nUse '0' for what is currently blank in the puzzle you wish to solve.\n\n")
fmt.Fprintf(flag.CommandLine.Output(), "Example: %s -row1 ... -row2 ... -row3 ... (etc)\n\n", os.Args[0])
flag.PrintDefaults()
}

19
flags/transfer.go Normal file
View File

@ -0,0 +1,19 @@
package flags
import "gitea.ligthert.net/golang/sudoku-funpark/solver"
func (flags *Flags) TransferConfig(solver *solver.Solver) {
// Parse variables parsed from the flags to solver
solver.NumCPUs = flags.NumCPUs
solver.Split = flags.Split
solver.Part = flags.Part
solver.Row1 = flags.Row1
solver.Row2 = flags.Row2
solver.Row3 = flags.Row3
solver.Row4 = flags.Row4
solver.Row5 = flags.Row5
solver.Row6 = flags.Row6
solver.Row7 = flags.Row7
solver.Row8 = flags.Row8
solver.Row9 = flags.Row9
}

16
flags/types.go Normal file
View File

@ -0,0 +1,16 @@
package flags
type Flags struct {
Row1 string
Row2 string
Row3 string
Row4 string
Row5 string
Row6 string
Row7 string
Row8 string
Row9 string
NumCPUs int
Split int
Part int
}