func main() { log.DebugLevel = 4 runmode := false single := true level := "alevel" straightAhead := false outputFreq := int32(50000) printSurface := false threads := 1 e := engine.NewEngine() if len(os.Args) > 1 { for i, _ := range os.Args { switch os.Args[i] { case "-r": runmode = true case "-l": if len(os.Args) > i+1 { level = os.Args[i+1] } case "-i": engine.PrintInfo() case "-m": single = false case "-d": if len(os.Args) > i+1 { debuglevel, err := strconv.Atoi(os.Args[i+1]) if err == nil { log.DebugLevel = debuglevel } } case "-s": straightAhead = true case "-f": if len(os.Args) > i+1 { of, err := strconv.Atoi(os.Args[i+1]) if err == nil { outputFreq = int32(of) } } case "-p": printSurface = true case "-t": if len(os.Args) > i+1 { t, err := strconv.Atoi(os.Args[i+1]) if err != nil { panic(err) } else { threads = t } } } } } e.LoadLevel(level) log.I(e.Id, "Level: "+level) if runmode { ai.Run(e, single, outputFreq, printSurface, straightAhead, threads) return } // surface e.Print() var choice string for { choice = "" log.A("Press m for manual or r for run: ") fmt.Scanf("%s", &choice) if choice == "r" { ai.Run(e, single, outputFreq, printSurface, straightAhead, threads) break } else if choice == "m" { log.A("Manual mode\n") var input int for { fmt.Scanf("%d", &input) if input >= 0 && input <= 3 { e.Move(engine.Direction(input)) e.Print() } else { e.UndoStep() e.Print() } } break } } }
func runWorker(e engine.Engine, basePath Path, threads int, single bool, outputFreq int32, printSurface bool, straightAhead bool) { // make sure, process will wait for this worker defer wg.Done() gorNo := numWorkers numWorkers++ log.I(gorNo, "runWorker %d created, %d running", gorNo, runtime.NumGoroutine()) e.Id = gorNo // path := Path{basePath[len(basePath)-1].Clone()} path := basePath[len(basePath)-1:] basePath = basePath[:len(basePath)-1] // basePath = basePath.Clone() // log.I(gorNo, "path: %d, basePath: %d", path, basePath) for { var ignoredDir = false ignoredDir = false // ### 1. check if finished if path.Empty() || !running { log.D(e.Id, "Empty path / stopped executition. Hopefully all possibilities tried ;)") break } // ### 2. increase the current direction to try the next possibility path.IncCurrentDir() // ### 3. check if rotation is finished. Then backtrack if path.CurrentCounter() > 3 { var dir = path.Current().PopIgnored() if dir == -1 { log.D(e.Id, "Rotation finished. Deadlock. Backtrack.") e.UndoStep() path.Pop() continue } else { path.SetCurrentDir(dir) ignoredDir = true } } // ### 4a. check if there is a box in direction dir and if this box is on a point cf := e.FigPos() // current figureposition nf := cf.Add(path.CurrentDir().Point()) // potential new figureposition if e.Surface[nf.Y][nf.X].Point && e.Surface[nf.Y][nf.X].Box != 0 && !ignoredDir { log.D(e.Id, "Do not moving a box from a point") path.Current().PushIgnored(path.CurrentDir()) continue } // ### 4b. Try moving log.D(e.Id, "Try moving in dir=%d", path.CurrentDir()) moved, boxMoved := e.Move(path.CurrentDir()) if !moved { log.D(e.Id, "Could not move.") continue } // ### 5. If moved, first check if not in a loop newHist := e.GetBoxesAndX() if everBeenHere(&history, newHist) { log.D(e.Id, "I'v been here already. Backtrack: %d", newHist) e.UndoStep() continue } // ### 6. If not in a loop, append history and go on addHistory(&history, newHist) if straightAhead { path.Push(path.CurrentDir() - 1) } else { path.Push(-1) } log.D(e.Id, "Moved. Path added.") // ### 7. Do some statistics incSteps() if printSurface { e.Print() } if steps%outputFreq == 0 { min, sec, µsec := getTimePassed(starttime) log.I(gorNo, "Steps: %9d; %4dm %2ds %6dµs", steps, min, sec, µsec) } // ### 8. Do we already won? :) if boxMoved != 0 && e.Won() { incSolutions() min, sec, µsec := getTimePassed(starttime) stepsCpy := steps log.Lock <- 1 log.A("%d. solution found after %d steps, %4dm %2ds %6dµs.\nPath: %d%d\n", solutions, stepsCpy, min, sec, µsec, basePath.Directions(), path.Directions()) <-log.Lock e.Print() solSteps = append(solSteps, stepsCpy) if single { running = false break } e.UndoStep() path.Pop() } // ### 9. Decide if we just go on or if we start a new thread if len(cDone) < threads { wg.Add(1) cDone <- 1 ne := e.Clone() log.I(gorNo, "Creating new worker") go runWorker(ne, path.Clone(), threads, single, outputFreq, printSurface, straightAhead) // go back, as we deligated current dir go worker // time.Sleep(3 * time.Second) e.UndoStep() path.Pop() } } <-cDone log.I(gorNo, "runWorker %d finished", gorNo) }