func markDeadWall(surface *engine.Surface, start engine.Point, end engine.Point) { if start.X == end.X && start.Y != end.Y { if start.Y < end.Y { for i := start.Y; i <= end.Y; i++ { (*surface)[i][start.X].Dead = true } } else { for i := start.Y; i >= end.Y; i-- { (*surface)[i][start.X].Dead = true } } } else if start.Y == end.Y && start.X != end.X { if start.X < end.X { for i := start.X; i <= end.X; i++ { (*surface)[start.Y][i].Dead = true } } else { for i := start.X; i >= end.X; i-- { (*surface)[start.Y][i].Dead = true } } } else { log.D(-1, "Solo dead end") } return }
/* try moving figure in specified direction. * Returns, if figure was moved and if figure moved a box. */ func (e *Engine) Move(dir Direction) (success bool, boxMoved int8) { success = false boxMoved = EMPTY cf := e.FigPos() // current figureposition nf := cf.Add(dir.Point()) // potential new figureposition if !e.Surface.In(nf) { log.D(e.Id, "Can not move: surface border") return } // check type of field of new figureposition switch f := e.Surface[nf.Y][nf.X]; { case f.Wall == true: log.D(e.Id, "Can not move: wall") return case f.Box != EMPTY: // if box nnf := nf.Add(dir.Point()) // potential new boxposition if !e.Surface.In(nnf) { log.D(e.Id, "Can not move: blocked box (surface border)") return } if e.Surface[nnf.Y][nnf.X].Dead { log.D(e.Id, "Can not move: Dead field") return } if e.Surface[nnf.Y][nnf.X].Wall || e.Surface[nnf.Y][nnf.X].Box != EMPTY { log.D(e.Id, "Can not move: blocked box") return } log.D(e.Id, "Move box") boxMoved = f.Box e.boxes[f.Box].SetPos(nnf) // nnf is position that box should move to, f.Box is current box e.reOrderBoxes(f.Box, dir) e.Surface[nnf.Y][nnf.X].Box = e.Surface[nf.Y][nf.X].Box fallthrough // go to next case statment to also move the figure case f.Box >= EMPTY: // actually always... var hist HistoryType hist.NewPos = nf hist.OldPos = cf hist.BoxMoved = boxMoved e.History = append(e.History, hist) e.Surface[nf.Y][nf.X].Box = e.Surface[cf.Y][cf.X].Box e.Surface[cf.Y][cf.X].Box = EMPTY e.figPos = nf // refresh figureposition success = true default: log.E(e.Id, "Unknown field") } return }
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) }