From b83d6bdde40ae6d110d49ba4f434db775f58d83f Mon Sep 17 00:00:00 2001 From: Sacha Ligthert Date: Tue, 28 Jan 2025 18:12:03 +0100 Subject: [PATCH] Give each function its own file. --- export/{flat.go => PrintFlatSolutions.go} | 0 ...able.go => PrintHumanReadableSolutions.go} | 2 +- flags/{parse.go => ParseFlags.go} | 70 ----- flags/printUsage.go | 28 ++ flags/validateRow.go | 54 ++++ main.go | 2 +- solver/CheckCombinations.go | 24 ++ solver/{blocks.go => LoadBlocks.go} | 0 solver/PopulateBlocks.go | 27 ++ solver/SelectWorkload.go | 23 ++ solver/Tracker.go | 103 +++++++ solver/calcAVG.go | 14 + solver/findBlocks.go | 37 +++ solver/processing.go | 253 ------------------ solver/setWorkload.go | 21 ++ solver/split.go | 61 ----- solver/splitWorkload.go | 19 ++ solver/{timers.go => timeTrack.go} | 0 solver/validateCombination.go | 47 ++++ solver/validator.go | 12 + 20 files changed, 411 insertions(+), 386 deletions(-) rename export/{flat.go => PrintFlatSolutions.go} (100%) rename export/{human-readable.go => PrintHumanReadableSolutions.go} (91%) rename flags/{parse.go => ParseFlags.go} (67%) create mode 100644 flags/printUsage.go create mode 100644 flags/validateRow.go create mode 100644 solver/CheckCombinations.go rename solver/{blocks.go => LoadBlocks.go} (100%) create mode 100644 solver/PopulateBlocks.go create mode 100644 solver/SelectWorkload.go create mode 100644 solver/Tracker.go create mode 100644 solver/calcAVG.go create mode 100644 solver/findBlocks.go delete mode 100644 solver/processing.go create mode 100644 solver/setWorkload.go delete mode 100644 solver/split.go create mode 100644 solver/splitWorkload.go rename solver/{timers.go => timeTrack.go} (100%) create mode 100644 solver/validateCombination.go create mode 100644 solver/validator.go diff --git a/export/flat.go b/export/PrintFlatSolutions.go similarity index 100% rename from export/flat.go rename to export/PrintFlatSolutions.go diff --git a/export/human-readable.go b/export/PrintHumanReadableSolutions.go similarity index 91% rename from export/human-readable.go rename to export/PrintHumanReadableSolutions.go index b9c44ee..3ed2054 100644 --- a/export/human-readable.go +++ b/export/PrintHumanReadableSolutions.go @@ -6,7 +6,7 @@ import ( ) // Print solutions into a human friendly format for in the console. -func (export *Export) PrintHumanSolutions() { +func (export *Export) PrintHumanReadableSolutions() { for solutionIndex, solution := range export.Controller.Solutions { log.Printf("\nSolution #%d:", solutionIndex+1) fmt.Println("╔═══════════╗") diff --git a/flags/parse.go b/flags/ParseFlags.go similarity index 67% rename from flags/parse.go rename to flags/ParseFlags.go index 198f03e..f8175b0 100644 --- a/flags/parse.go +++ b/flags/ParseFlags.go @@ -2,7 +2,6 @@ package flags import ( "flag" - "fmt" "log" "os" "runtime" @@ -83,72 +82,3 @@ func (flags *Flags) ParseFlags() { } } - -// Validate if a row is properly set. -// This check for: -// - Correct length -// - Correct numbers -// - Numbers only present once -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) - } - -} - -// 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]) - 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() -} diff --git a/flags/printUsage.go b/flags/printUsage.go new file mode 100644 index 0000000..d224e14 --- /dev/null +++ b/flags/printUsage.go @@ -0,0 +1,28 @@ +package flags + +import ( + "flag" + "fmt" + "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]) + 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() +} diff --git a/flags/validateRow.go b/flags/validateRow.go new file mode 100644 index 0000000..cdb2b2a --- /dev/null +++ b/flags/validateRow.go @@ -0,0 +1,54 @@ +package flags + +import ( + "log" + "os" +) + +// Validate if a row is properly set. +// This check for: +// - Correct length +// - Correct numbers +// - Numbers only present once +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) + } + +} diff --git a/main.go b/main.go index 96b61b7..4a42b41 100644 --- a/main.go +++ b/main.go @@ -48,7 +48,7 @@ func main() { // Print the valid solutions switch controller.Output { case "human": - export.PrintHumanSolutions() + export.PrintHumanReadableSolutions() case "flat": export.PrintFlatSolutions() } diff --git a/solver/CheckCombinations.go b/solver/CheckCombinations.go new file mode 100644 index 0000000..6746d87 --- /dev/null +++ b/solver/CheckCombinations.go @@ -0,0 +1,24 @@ +package solver + +// Iterate through all combination of blocks and validate them. +func (solver *Solver) CheckCombinations() { + for rows1Index := range solver.row1s { + for rows2Index := range solver.row2s { + for rows3Index := range solver.row3s { + for rows4Index := range solver.row4s { + for rows5Index := range solver.row5s { + for rows6Index := range solver.row6s { + for rows7Index := range solver.row7s { + for rows8Index := range solver.row8s { + for rows9Index := range solver.row9s { + go solver.validator(rows1Index, rows2Index, rows3Index, rows4Index, rows5Index, rows6Index, rows7Index, rows8Index, rows9Index) + } + } + } + } + } + } + } + } + } +} diff --git a/solver/blocks.go b/solver/LoadBlocks.go similarity index 100% rename from solver/blocks.go rename to solver/LoadBlocks.go diff --git a/solver/PopulateBlocks.go b/solver/PopulateBlocks.go new file mode 100644 index 0000000..8c54287 --- /dev/null +++ b/solver/PopulateBlocks.go @@ -0,0 +1,27 @@ +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") + + solver.findBlocks(&solver.Controller.Row1, &solver.row1s) + solver.findBlocks(&solver.Controller.Row2, &solver.row2s) + solver.findBlocks(&solver.Controller.Row3, &solver.row3s) + solver.findBlocks(&solver.Controller.Row4, &solver.row4s) + solver.findBlocks(&solver.Controller.Row5, &solver.row5s) + solver.findBlocks(&solver.Controller.Row6, &solver.row6s) + solver.findBlocks(&solver.Controller.Row7, &solver.row7s) + solver.findBlocks(&solver.Controller.Row8, &solver.row8s) + solver.findBlocks(&solver.Controller.Row9, &solver.row9s) + + // This calculates and stores the total number of solutions to validate. + solver.Iter = uint64(len(solver.row1s)) * uint64(len(solver.row2s)) * uint64(len(solver.row3s)) * uint64(len(solver.row4s)) * uint64(len(solver.row5s)) * uint64(len(solver.row6s)) * uint64(len(solver.row7s)) * uint64(len(solver.row8s)) * uint64(len(solver.row9s)) + +} diff --git a/solver/SelectWorkload.go b/solver/SelectWorkload.go new file mode 100644 index 0000000..40a2692 --- /dev/null +++ b/solver/SelectWorkload.go @@ -0,0 +1,23 @@ +package solver + +import ( + "log" + "os" + "strconv" + "time" +) + +// Renders workload for an agent. +// Checks if this feature can be used, otherwise exits. +// 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") + 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)) + workloads := solver.splitWorkload() + solver.setWorkload(workloads) +} diff --git a/solver/Tracker.go b/solver/Tracker.go new file mode 100644 index 0000000..fdeca5a --- /dev/null +++ b/solver/Tracker.go @@ -0,0 +1,103 @@ +package solver + +import ( + "log" + "strconv" + "time" +) + +// Keep track and output progress. +// Calculate rates, display percentages, estimate the ETA till completion. +func (solver *Solver) Tracker() { + + // Add time tracking + defer solver.timeTrack(time.Now(), "Validated solutions") + log.Println("Validating solutions") + + // Determine if the main-loop is done + var done bool + + // Tracking progress in percentages + var percentage float32 + // Tracking progress in validated solutions + var track int + + // Tracking the rate, starting point + var rateStart uint64 + // Tracking the rate, difference between previous iterations + var rateDiff uint64 + + // Tracking duration + var timerStart = time.Now() + + // Estimation how long it will take + var est_fin string + + // While not needed for rateDiff anymore, it makes estimation calculations more accurate. ☹️ + time.Sleep(time.Second) + + // for solver.Iter != solver.counter { // Start for-loop + for !done { + + // Determine how far we are. + percentage = (float32(solver.counter.Load()) / (float32(solver.Iter) / 100)) + + // Reset the loop + rateDiff = solver.counter.Load() - rateStart + + if track <= int(percentage) || rateDiff == 0 { // Start if-statement + + // Make sure something happened, making rateStart the only reliable variable + if solver.Iter == solver.counter.Load() { + percentage = 100 + solver.counter.Store(solver.Iter) + done = true + } + + timer_elapsed := time.Since(timerStart) + solver.rates = append(solver.rates, rateDiff) + rate_avg := solver.calcAVG() + + // Estimate when this is finished + if rateDiff == 0 { + est_fin = "N/A" + } else { + duration_int := (solver.Iter - solver.counter.Load()) / rate_avg + duration_string := strconv.Itoa(int(duration_int)) + "s" + est, err := time.ParseDuration(duration_string) + if err != nil { + est_fin = "parse error" + } else { + est_fin = est.String() + } + } + + // 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) + + // After we are done printing, exit this for-loop + if percentage == 100 { + break + } + + // Wrap up the loop or break + if int(percentage) > track { + track = int(percentage) + } else { + track = track + 1 + } + + timerStart = time.Now() + + } + + // Resert the rate counter + rateStart = solver.counter.Load() + + // Sleep for a second + if solver.Iter != solver.counter.Load() { + time.Sleep(1 * time.Second) + } + } // End for-loop + +} diff --git a/solver/calcAVG.go b/solver/calcAVG.go new file mode 100644 index 0000000..1660bb6 --- /dev/null +++ b/solver/calcAVG.go @@ -0,0 +1,14 @@ +package solver + +// Calculate the average rate in a stored slice of rates. +func (solver *Solver) calcAVG() (avg uint64) { + var avgSum uint64 + + for _, value := range solver.rates { + avgSum += uint64(value) + } + + avg = avgSum / uint64(len(solver.rates)) + + return +} diff --git a/solver/findBlocks.go b/solver/findBlocks.go new file mode 100644 index 0000000..9a82b4a --- /dev/null +++ b/solver/findBlocks.go @@ -0,0 +1,37 @@ +package solver + +// The actual function that finds the blocks matching the partial blocks. +func (solver *Solver) findBlocks(row *string, rows *[]string) { + // Declare selection + var selection []string + var currBlocks []string + funcRow := *row + + for letter := range funcRow { + + if len(selection) == 0 { + currBlocks = solver.Controller.Blocks + } else { + currBlocks = selection + selection = nil + } + + for _, block := range currBlocks { + + currRow := block + + if funcRow[letter] == currRow[letter] { + foundRow := currRow + selection = append(selection, foundRow) + } + if funcRow[letter] == '0' { + foundRow := currRow + selection = append(selection, foundRow) + } + + } // End for-loop + + } // End for-loop + + *rows = selection +} diff --git a/solver/processing.go b/solver/processing.go deleted file mode 100644 index fc65601..0000000 --- a/solver/processing.go +++ /dev/null @@ -1,253 +0,0 @@ -package solver - -import ( - "log" - "strconv" - "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") - - solver.findBlocks(&solver.Controller.Row1, &solver.row1s) - solver.findBlocks(&solver.Controller.Row2, &solver.row2s) - solver.findBlocks(&solver.Controller.Row3, &solver.row3s) - solver.findBlocks(&solver.Controller.Row4, &solver.row4s) - solver.findBlocks(&solver.Controller.Row5, &solver.row5s) - solver.findBlocks(&solver.Controller.Row6, &solver.row6s) - solver.findBlocks(&solver.Controller.Row7, &solver.row7s) - solver.findBlocks(&solver.Controller.Row8, &solver.row8s) - solver.findBlocks(&solver.Controller.Row9, &solver.row9s) - - // This calculates and stores the total number of solutions to validate. - solver.Iter = uint64(len(solver.row1s)) * uint64(len(solver.row2s)) * uint64(len(solver.row3s)) * uint64(len(solver.row4s)) * uint64(len(solver.row5s)) * uint64(len(solver.row6s)) * uint64(len(solver.row7s)) * uint64(len(solver.row8s)) * uint64(len(solver.row9s)) - -} - -// The actual function that finds the blocks matching the partial blocks. -func (solver *Solver) findBlocks(row *string, rows *[]string) { - // Declare selection - var selection []string - var currBlocks []string - funcRow := *row - - for letter := range funcRow { - - if len(selection) == 0 { - currBlocks = solver.Controller.Blocks - } else { - currBlocks = selection - selection = nil - } - - for _, block := range currBlocks { - - currRow := block - - if funcRow[letter] == currRow[letter] { - foundRow := currRow - selection = append(selection, foundRow) - } - if funcRow[letter] == '0' { - foundRow := currRow - selection = append(selection, foundRow) - } - - } // End for-loop - - } // End for-loop - - *rows = selection -} - -// Iterate through all combination of blocks and validate them. -func (solver *Solver) CheckCombinations() { - for rows1Index := range solver.row1s { - for rows2Index := range solver.row2s { - for rows3Index := range solver.row3s { - for rows4Index := range solver.row4s { - for rows5Index := range solver.row5s { - for rows6Index := range solver.row6s { - for rows7Index := range solver.row7s { - for rows8Index := range solver.row8s { - for rows9Index := range solver.row9s { - go solver.validator(rows1Index, rows2Index, rows3Index, rows4Index, rows5Index, rows6Index, rows7Index, rows8Index, rows9Index) - } - } - } - } - } - } - } - } - } -} - -// Validate the provided rows and verify it is a valid solution. -func (solver *Solver) validator(rows1Index int, rows2Index int, rows3Index int, rows4Index int, rows5Index int, rows6Index int, rows7Index int, rows8Index int, rows9Index int) { - - solver.counter.Add(1) - - if solver.validateCombination(solver.row1s[rows1Index], solver.row2s[rows2Index], solver.row3s[rows3Index], solver.row4s[rows4Index], solver.row5s[rows5Index], solver.row6s[rows6Index], solver.row7s[rows7Index], solver.row8s[rows8Index], solver.row9s[rows9Index]) { - solver.Controller.Solutions = append(solver.Controller.Solutions, []string{solver.row1s[rows1Index], solver.row2s[rows2Index], solver.row3s[rows3Index], solver.row4s[rows4Index], solver.row5s[rows5Index], solver.row6s[rows6Index], solver.row7s[rows7Index], solver.row8s[rows8Index], solver.row9s[rows9Index]}) - } - -} - -// Keep track and output progress. -// Calculate rates, display percentages, estimate the ETA till completion. -func (solver *Solver) Tracker() { - - // Add time tracking - defer solver.timeTrack(time.Now(), "Validated solutions") - log.Println("Validating solutions") - - // Determine if the main-loop is done - var done bool - - // Tracking progress in percentages - var percentage float32 - // Tracking progress in validated solutions - var track int - - // Tracking the rate, starting point - var rateStart uint64 - // Tracking the rate, difference between previous iterations - var rateDiff uint64 - - // Tracking duration - var timerStart = time.Now() - - // Estimation how long it will take - var est_fin string - - // While not needed for rateDiff anymore, it makes estimation calculations more accurate. ☹️ - time.Sleep(time.Second) - - // for solver.Iter != solver.counter { // Start for-loop - for !done { - - // Determine how far we are. - percentage = (float32(solver.counter.Load()) / (float32(solver.Iter) / 100)) - - // Reset the loop - rateDiff = solver.counter.Load() - rateStart - - if track <= int(percentage) || rateDiff == 0 { // Start if-statement - - // Make sure something happened, making rateStart the only reliable variable - if solver.Iter == solver.counter.Load() { - percentage = 100 - solver.counter.Store(solver.Iter) - done = true - } - - timer_elapsed := time.Since(timerStart) - solver.rates = append(solver.rates, rateDiff) - rate_avg := solver.calcAVG() - - // Estimate when this is finished - if rateDiff == 0 { - est_fin = "N/A" - } else { - duration_int := (solver.Iter - solver.counter.Load()) / rate_avg - duration_string := strconv.Itoa(int(duration_int)) + "s" - est, err := time.ParseDuration(duration_string) - if err != nil { - est_fin = "parse error" - } else { - est_fin = est.String() - } - } - - // 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) - - // After we are done printing, exit this for-loop - if percentage == 100 { - break - } - - // Wrap up the loop or break - if int(percentage) > track { - track = int(percentage) - } else { - track = track + 1 - } - - timerStart = time.Now() - - } - - // Resert the rate counter - rateStart = solver.counter.Load() - - // Sleep for a second - if solver.Iter != solver.counter.Load() { - time.Sleep(1 * time.Second) - } - } // End for-loop - -} - -// Validate combination -func (solver *Solver) validateCombination(row1 string, row2 string, row3 string, row4 string, row5 string, row6 string, row7 string, row8 string, row9 string) (retval bool) { - retval = true - - for index := range 9 { - if row1[index] == row2[index] || row1[index] == row3[index] || row1[index] == row4[index] || row1[index] == row5[index] || row1[index] == row6[index] || row1[index] == row7[index] || row1[index] == row8[index] || row1[index] == row9[index] { - retval = false - } - - if row2[index] == row1[index] || row2[index] == row3[index] || row2[index] == row4[index] || row2[index] == row5[index] || row2[index] == row6[index] || row2[index] == row7[index] || row2[index] == row8[index] || row2[index] == row9[index] { - retval = false - } - - if row3[index] == row1[index] || row3[index] == row2[index] || row3[index] == row4[index] || row3[index] == row5[index] || row3[index] == row6[index] || row3[index] == row7[index] || row3[index] == row8[index] || row3[index] == row9[index] { - retval = false - } - - if row4[index] == row1[index] || row4[index] == row2[index] || row4[index] == row3[index] || row4[index] == row5[index] || row4[index] == row6[index] || row4[index] == row7[index] || row4[index] == row8[index] || row4[index] == row9[index] { - retval = false - } - - if row5[index] == row1[index] || row5[index] == row2[index] || row5[index] == row3[index] || row5[index] == row4[index] || row5[index] == row6[index] || row5[index] == row7[index] || row5[index] == row8[index] || row5[index] == row9[index] { - retval = false - } - - if row6[index] == row1[index] || row6[index] == row2[index] || row6[index] == row3[index] || row6[index] == row4[index] || row6[index] == row5[index] || row6[index] == row7[index] || row6[index] == row8[index] || row6[index] == row9[index] { - retval = false - } - - if row7[index] == row1[index] || row7[index] == row2[index] || row7[index] == row3[index] || row7[index] == row4[index] || row5[index] == row6[index] || row7[index] == row6[index] || row7[index] == row8[index] || row7[index] == row9[index] { - retval = false - } - - if row8[index] == row1[index] || row8[index] == row2[index] || row8[index] == row3[index] || row8[index] == row4[index] || row8[index] == row5[index] || row8[index] == row6[index] || row8[index] == row7[index] || row8[index] == row9[index] { - retval = false - } - - if row9[index] == row1[index] || row9[index] == row2[index] || row9[index] == row3[index] || row9[index] == row4[index] || row9[index] == row5[index] || row9[index] == row6[index] || row9[index] == row7[index] || row9[index] == row8[index] { - retval = false - } - - } - - return retval -} - -// Calculate the average rate in a stored slice of rates. -func (solver *Solver) calcAVG() (avg uint64) { - var avgSum uint64 - - for _, value := range solver.rates { - avgSum += uint64(value) - } - - avg = avgSum / uint64(len(solver.rates)) - - return -} diff --git a/solver/setWorkload.go b/solver/setWorkload.go new file mode 100644 index 0000000..ea5e0cc --- /dev/null +++ b/solver/setWorkload.go @@ -0,0 +1,21 @@ +package solver + +// Set the workload by setting solver.row1s +func (solver *Solver) setWorkload(agents []int) { + var start int = 0 + var finish int = 0 + for key, value := range agents { + if key == solver.Controller.Part-1 { + finish = start + value + break + } else { + start += value + } + } + + // Set the shortened set of instructions + solver.row1s = solver.row1s[start:finish] + + // Recalculate how much we need to grind through + solver.Iter = uint64(len(solver.row1s)) * uint64(len(solver.row2s)) * uint64(len(solver.row3s)) * uint64(len(solver.row4s)) * uint64(len(solver.row5s)) * uint64(len(solver.row6s)) * uint64(len(solver.row7s)) * uint64(len(solver.row8s)) * uint64(len(solver.row9s)) +} diff --git a/solver/split.go b/solver/split.go deleted file mode 100644 index b472e15..0000000 --- a/solver/split.go +++ /dev/null @@ -1,61 +0,0 @@ -package solver - -import ( - "log" - "os" - "strconv" - "time" -) - -// Renders workload for an agent. -// Checks if this feature can be used, otherwise exits. -// 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") - 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)) - workloads := solver.splitWorkload() - solver.setWorkload(workloads) -} - -// Determine how workload should be split among the agents -func (solver *Solver) splitWorkload() []int { - agents := make([]int, solver.Controller.Split) - var tracker int - var tasks int = len(solver.row1s) - - for tasks != 0 { - agents[tracker] += 1 - tasks -= 1 - tracker += 1 - if tracker == solver.Controller.Split { - tracker = 0 - } - } - - return agents -} - -// Set the workload by setting solver.row1s -func (solver *Solver) setWorkload(agents []int) { - var start int = 0 - var finish int = 0 - for key, value := range agents { - if key == solver.Controller.Part-1 { - finish = start + value - break - } else { - start += value - } - } - - // Set the shortened set of instructions - solver.row1s = solver.row1s[start:finish] - - // Recalculate how much we need to grind through - solver.Iter = uint64(len(solver.row1s)) * uint64(len(solver.row2s)) * uint64(len(solver.row3s)) * uint64(len(solver.row4s)) * uint64(len(solver.row5s)) * uint64(len(solver.row6s)) * uint64(len(solver.row7s)) * uint64(len(solver.row8s)) * uint64(len(solver.row9s)) -} diff --git a/solver/splitWorkload.go b/solver/splitWorkload.go new file mode 100644 index 0000000..a91c2d9 --- /dev/null +++ b/solver/splitWorkload.go @@ -0,0 +1,19 @@ +package solver + +// Determine how workload should be split among the agents +func (solver *Solver) splitWorkload() []int { + agents := make([]int, solver.Controller.Split) + var tracker int + var tasks int = len(solver.row1s) + + for tasks != 0 { + agents[tracker] += 1 + tasks -= 1 + tracker += 1 + if tracker == solver.Controller.Split { + tracker = 0 + } + } + + return agents +} diff --git a/solver/timers.go b/solver/timeTrack.go similarity index 100% rename from solver/timers.go rename to solver/timeTrack.go diff --git a/solver/validateCombination.go b/solver/validateCombination.go new file mode 100644 index 0000000..3ef4717 --- /dev/null +++ b/solver/validateCombination.go @@ -0,0 +1,47 @@ +package solver + +// Validate combination +func (solver *Solver) validateCombination(row1 string, row2 string, row3 string, row4 string, row5 string, row6 string, row7 string, row8 string, row9 string) (retval bool) { + retval = true + + for index := range 9 { + if row1[index] == row2[index] || row1[index] == row3[index] || row1[index] == row4[index] || row1[index] == row5[index] || row1[index] == row6[index] || row1[index] == row7[index] || row1[index] == row8[index] || row1[index] == row9[index] { + retval = false + } + + if row2[index] == row1[index] || row2[index] == row3[index] || row2[index] == row4[index] || row2[index] == row5[index] || row2[index] == row6[index] || row2[index] == row7[index] || row2[index] == row8[index] || row2[index] == row9[index] { + retval = false + } + + if row3[index] == row1[index] || row3[index] == row2[index] || row3[index] == row4[index] || row3[index] == row5[index] || row3[index] == row6[index] || row3[index] == row7[index] || row3[index] == row8[index] || row3[index] == row9[index] { + retval = false + } + + if row4[index] == row1[index] || row4[index] == row2[index] || row4[index] == row3[index] || row4[index] == row5[index] || row4[index] == row6[index] || row4[index] == row7[index] || row4[index] == row8[index] || row4[index] == row9[index] { + retval = false + } + + if row5[index] == row1[index] || row5[index] == row2[index] || row5[index] == row3[index] || row5[index] == row4[index] || row5[index] == row6[index] || row5[index] == row7[index] || row5[index] == row8[index] || row5[index] == row9[index] { + retval = false + } + + if row6[index] == row1[index] || row6[index] == row2[index] || row6[index] == row3[index] || row6[index] == row4[index] || row6[index] == row5[index] || row6[index] == row7[index] || row6[index] == row8[index] || row6[index] == row9[index] { + retval = false + } + + if row7[index] == row1[index] || row7[index] == row2[index] || row7[index] == row3[index] || row7[index] == row4[index] || row5[index] == row6[index] || row7[index] == row6[index] || row7[index] == row8[index] || row7[index] == row9[index] { + retval = false + } + + if row8[index] == row1[index] || row8[index] == row2[index] || row8[index] == row3[index] || row8[index] == row4[index] || row8[index] == row5[index] || row8[index] == row6[index] || row8[index] == row7[index] || row8[index] == row9[index] { + retval = false + } + + if row9[index] == row1[index] || row9[index] == row2[index] || row9[index] == row3[index] || row9[index] == row4[index] || row9[index] == row5[index] || row9[index] == row6[index] || row9[index] == row7[index] || row9[index] == row8[index] { + retval = false + } + + } + + return retval +} diff --git a/solver/validator.go b/solver/validator.go new file mode 100644 index 0000000..62152a7 --- /dev/null +++ b/solver/validator.go @@ -0,0 +1,12 @@ +package solver + +// Validate the provided rows and verify it is a valid solution. +func (solver *Solver) validator(rows1Index int, rows2Index int, rows3Index int, rows4Index int, rows5Index int, rows6Index int, rows7Index int, rows8Index int, rows9Index int) { + + solver.counter.Add(1) + + if solver.validateCombination(solver.row1s[rows1Index], solver.row2s[rows2Index], solver.row3s[rows3Index], solver.row4s[rows4Index], solver.row5s[rows5Index], solver.row6s[rows6Index], solver.row7s[rows7Index], solver.row8s[rows8Index], solver.row9s[rows9Index]) { + solver.Controller.Solutions = append(solver.Controller.Solutions, []string{solver.row1s[rows1Index], solver.row2s[rows2Index], solver.row3s[rows3Index], solver.row4s[rows4Index], solver.row5s[rows5Index], solver.row6s[rows6Index], solver.row7s[rows7Index], solver.row8s[rows8Index], solver.row9s[rows9Index]}) + } + +}