diff -r 000000000000 -r 00371339bbcc gotak/gotak.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gotak/gotak.go Fri Sep 02 21:50:48 2016 +0200 @@ -0,0 +1,208 @@ +package main + +import ( + "fmt" + "log" + "os" + "time" + + flag "github.com/docker/docker/pkg/mflag" + + "mikael/takuzu" +) + +var verbosity int + +func newTakuzuGameBoard(size int, simple bool, jobs int, buildBoardTimeout, reduceBoardTimeout time.Duration, minRatio, maxRatio int) *takuzu.Takuzu { + results := make(chan *takuzu.Takuzu) + + newTak := func(i int) { + takuzu, err := takuzu.NewRandomTakuzu(size, simple, fmt.Sprintf("%v", i), + buildBoardTimeout, reduceBoardTimeout, minRatio, maxRatio) + + if err == nil && takuzu != nil { + results <- takuzu + if verbosity > 0 && jobs > 1 { + log.Printf("Worker #%d done.", i) + } + } else { + results <- nil + } + } + + if jobs == 0 { + return nil + } + for i := 0; i < jobs; i++ { + go newTak(i) + } + tak := <-results + return tak +} + +func main() { + var game string + + vbl := flag.Uint([]string{"-vl"}, 0, "Verbosity Level") + simple := flag.Bool([]string{"-simple"}, false, "Only look for trivial solutions") + out := flag.Bool([]string{"-out"}, false, "Send solution string to output") + flag.StringVar(&game, []string{"-game"}, "", "Load game string") + schrodLvl := flag.Uint([]string{"-x-sl"}, 0, "[Advanced] Schrödinger level") + resolveTimeout := flag.Duration([]string{"-x-timeout"}, 0, "[Advanced] Resolution timeout") + buildBoardTimeout := flag.Duration([]string{"-x-build-timeout"}, 5*time.Minute, "[Advanced] Build timeout per resolution") + reduceBoardTimeout := flag.Duration([]string{"-x-reduce-timeout"}, 20*time.Minute, "[Advanced] Reduction timeout") + buildMinRatio := flag.Uint([]string{"-x-new-min-ratio"}, 55, "[Advanced] Build empty cell ratio (40-60)") + buildMaxRatio := flag.Uint([]string{"-x-new-max-ratio"}, 62, "[Advanced] Build empty cell ratio (50-99)") + all := flag.Bool([]string{"-all"}, false, "Look for all possible solutions") + reduce := flag.Bool([]string{"-reduce"}, false, "Try to reduce the number of digits") + buildNewSize := flag.Uint([]string{"-new"}, 0, "Build a new takuzu board (with given size)") + pdfFileName := flag.String([]string{"-to-pdf"}, "", "PDF output file name") + workers := flag.Uint([]string{"-workers"}, 1, "Number of parallel workers (use with --new)") + + flag.Parse() + + verbosity = int(*vbl) + takuzu.SetVerbosityLevel(verbosity) + takuzu.SetSchrodingerLevel(*schrodLvl) + + var tak *takuzu.Takuzu + + if game != "" { + var err error + tak, err = takuzu.NewFromString(game) + if tak == nil || err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + tak = nil + } + } + + if *buildNewSize > 0 { + if verbosity > 1 { + log.Printf("buildBoardTimeout: %v", *buildBoardTimeout) + log.Printf("reduceBoardTimeout: %v", *reduceBoardTimeout) + log.Printf("Free cell min ratio: %v", *buildMinRatio) + log.Printf("Free cell max ratio: %v", *buildMaxRatio) + } + tak = newTakuzuGameBoard(int(*buildNewSize), *simple, + int(*workers), + *buildBoardTimeout, *reduceBoardTimeout, + int(*buildMinRatio), int(*buildMaxRatio)) + } + + if tak == nil { + fmt.Fprintln(os.Stderr, "Could not create takuzu board.") + os.Exit(255) + } + + tak.DumpBoard() + fmt.Println() + + if *pdfFileName != "" { + if err := tak2pdf(tak, *pdfFileName); err != nil { + log.Println(err) + os.Exit(1) + } + if *out { + tak.DumpString() + } + os.Exit(0) + } + + if *buildNewSize > 0 { + if *out { + tak.DumpString() + } + os.Exit(0) + } + + if *reduce { + if verbosity > 1 { + log.Printf("buildBoardTimeout: %v", *buildBoardTimeout) + log.Printf("reduceBoardTimeout: %v", *reduceBoardTimeout) + } + var err error + if tak, err = tak.ReduceBoard(*simple, "0", *buildBoardTimeout, *reduceBoardTimeout); err != nil { + log.Println(err) + os.Exit(1) + } + + tak.DumpBoard() + fmt.Println() + + if *out { + tak.DumpString() + } + + os.Exit(0) + } + + if *simple { + full, err := tak.TrySolveTrivial() + if err != nil { + log.Println(err) + os.Exit(1) + } + if !full { + tak.DumpBoard() + log.Println("The takuzu could not be completed using trivial methods.") + os.Exit(2) + } + + log.Println("The takuzu is correct and complete.") + tak.DumpBoard() + fmt.Println() + + if *out { + tak.DumpString() + } + os.Exit(0) + } + + var allSol *[]takuzu.Takuzu + if *all { + allSol = &[]takuzu.Takuzu{} + } + res, err := tak.TrySolveRecurse(allSol, *resolveTimeout) + if err != nil && verbosity > 1 { + // The last trivial resolution failed + log.Println("Trivial resolution failed:", err) + } + + // Ignoring res & err if a full search was requested + if *all { + log.Println(len(*allSol), "solution(s) found.") + if len(*allSol) > 0 { + for _, s := range *allSol { + if *out { + s.DumpString() + } else { + s.DumpBoard() + fmt.Println() + } + } + if len(*allSol) > 1 { + os.Exit(3) + } + os.Exit(0) + } + fmt.Println("No solution found.") + os.Exit(2) + } + + if err != nil { + log.Println(err) + os.Exit(1) + } + if res != nil { + res.DumpBoard() + fmt.Println() + + if *out { + res.DumpString() + } + os.Exit(0) + } + + fmt.Println("No solution found.") + os.Exit(2) +}