// print a legend of the Surface output func PrintInfo() { log.Lock <- 1 log.A("Surface Field association:\n") log.A("EMPTY\t\t' '\n") log.A("BOX\t\t'$'\n") log.A("FIGURE\t\t'x'\n") log.A("EMPTY POINT\t'*'\n") log.A("BOX POINT\t'%'\n") log.A("FIGURE POINT\t'+'\n") log.A("WALL\t\t'#'\n") log.A("DEAD FIELD\t'☠'\n") <-log.Lock }
// run the algo, print some output and catch if won. // straightAhead: true: new direction are initialized with current dir, false: init with 0 func Run(e engine.Engine, single bool, outputFreq int32, printSurface bool, straightAhead bool, threads int) { steps, solutions, solSteps = 0, 0, []int32{} numWorkers = 0 running = true cDone = make(chan int8, threads) // queue for threads cHistory = make(chan bool, 1) // mutex on global history object // preprocessing MarkDeadFields(&e.Surface) e.Print() // init time counter syscall.Gettimeofday(&starttime) // ??? // runtime.GOMAXPROCS(runtime.NumCPU()) // init path path := Path{} path.Push(engine.NO_DIRECTION) // create history store and save initial constellation history = newHistoryTree(-1, -1) newHist := e.GetBoxesAndX() addHistory(&history, newHist) // prepare for starting workers wg.Add(1) cDone <- 1 go runWorker(e, path, threads, single, outputFreq, printSurface, straightAhead) // wait for all workers to finish wg.Wait() // time.Sleep(1 * time.Second) // print result min, sec, µsec := getTimePassed(starttime) log.A("Run finished with %d steps after %dm %ds %dµs.\n%d solutions found at following steps:\n%d\n", steps, min, sec, µsec, solutions, solSteps) }
// print the current Surface func (e *Engine) Print() { log.Lock <- 1 var x, y int8 for y = 0; y < int8(len(e.Surface)); y++ { log.A("%3d ", e.Id) for x = 0; x < int8(len(e.Surface[y])); x++ { switch field := e.Surface[y][x]; { case field.Wall: log.A("#") case e.figPos.X == x && e.figPos.Y == y: if field.Point { log.A("+") } else { log.A("x") } case field.Box == EMPTY: if field.Point { log.A("*") } else if field.Dead { log.A("☠") } else { log.A(" ") } default: // field has box if field.Point { log.A("%%") } else { log.A("$") } } log.A(" ") } log.A("\n") } fieldnr, deadnr := e.Surface.AmountOfFields() log.A("Boxes: %d\n", len(e.Boxes())) log.A("Points: %d\n", len(e.Points())) log.A("Fields: %d\n", fieldnr) log.A("DeadFields: %d\n", deadnr) <-log.Lock }
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) }
func printTree(history HistoryTree) { log.A("%d\n", history) }