gotak/gotak.go
changeset 0 00371339bbcc
child 1 6a396d691a7d
equal deleted inserted replaced
-1:000000000000 0:00371339bbcc
       
     1 package main
       
     2 
       
     3 import (
       
     4 	"fmt"
       
     5 	"log"
       
     6 	"os"
       
     7 	"time"
       
     8 
       
     9 	flag "github.com/docker/docker/pkg/mflag"
       
    10 
       
    11 	"mikael/takuzu"
       
    12 )
       
    13 
       
    14 var verbosity int
       
    15 
       
    16 func newTakuzuGameBoard(size int, simple bool, jobs int, buildBoardTimeout, reduceBoardTimeout time.Duration, minRatio, maxRatio int) *takuzu.Takuzu {
       
    17 	results := make(chan *takuzu.Takuzu)
       
    18 
       
    19 	newTak := func(i int) {
       
    20 		takuzu, err := takuzu.NewRandomTakuzu(size, simple, fmt.Sprintf("%v", i),
       
    21 			buildBoardTimeout, reduceBoardTimeout, minRatio, maxRatio)
       
    22 
       
    23 		if err == nil && takuzu != nil {
       
    24 			results <- takuzu
       
    25 			if verbosity > 0 && jobs > 1 {
       
    26 				log.Printf("Worker #%d done.", i)
       
    27 			}
       
    28 		} else {
       
    29 			results <- nil
       
    30 		}
       
    31 	}
       
    32 
       
    33 	if jobs == 0 {
       
    34 		return nil
       
    35 	}
       
    36 	for i := 0; i < jobs; i++ {
       
    37 		go newTak(i)
       
    38 	}
       
    39 	tak := <-results
       
    40 	return tak
       
    41 }
       
    42 
       
    43 func main() {
       
    44 	var game string
       
    45 
       
    46 	vbl := flag.Uint([]string{"-vl"}, 0, "Verbosity Level")
       
    47 	simple := flag.Bool([]string{"-simple"}, false, "Only look for trivial solutions")
       
    48 	out := flag.Bool([]string{"-out"}, false, "Send solution string to output")
       
    49 	flag.StringVar(&game, []string{"-game"}, "", "Load game string")
       
    50 	schrodLvl := flag.Uint([]string{"-x-sl"}, 0, "[Advanced] Schrödinger level")
       
    51 	resolveTimeout := flag.Duration([]string{"-x-timeout"}, 0, "[Advanced] Resolution timeout")
       
    52 	buildBoardTimeout := flag.Duration([]string{"-x-build-timeout"}, 5*time.Minute, "[Advanced] Build timeout per resolution")
       
    53 	reduceBoardTimeout := flag.Duration([]string{"-x-reduce-timeout"}, 20*time.Minute, "[Advanced] Reduction timeout")
       
    54 	buildMinRatio := flag.Uint([]string{"-x-new-min-ratio"}, 55, "[Advanced] Build empty cell ratio (40-60)")
       
    55 	buildMaxRatio := flag.Uint([]string{"-x-new-max-ratio"}, 62, "[Advanced] Build empty cell ratio (50-99)")
       
    56 	all := flag.Bool([]string{"-all"}, false, "Look for all possible solutions")
       
    57 	reduce := flag.Bool([]string{"-reduce"}, false, "Try to reduce the number of digits")
       
    58 	buildNewSize := flag.Uint([]string{"-new"}, 0, "Build a new takuzu board (with given size)")
       
    59 	pdfFileName := flag.String([]string{"-to-pdf"}, "", "PDF output file name")
       
    60 	workers := flag.Uint([]string{"-workers"}, 1, "Number of parallel workers (use with --new)")
       
    61 
       
    62 	flag.Parse()
       
    63 
       
    64 	verbosity = int(*vbl)
       
    65 	takuzu.SetVerbosityLevel(verbosity)
       
    66 	takuzu.SetSchrodingerLevel(*schrodLvl)
       
    67 
       
    68 	var tak *takuzu.Takuzu
       
    69 
       
    70 	if game != "" {
       
    71 		var err error
       
    72 		tak, err = takuzu.NewFromString(game)
       
    73 		if tak == nil || err != nil {
       
    74 			fmt.Fprintln(os.Stderr, "Error:", err)
       
    75 			tak = nil
       
    76 		}
       
    77 	}
       
    78 
       
    79 	if *buildNewSize > 0 {
       
    80 		if verbosity > 1 {
       
    81 			log.Printf("buildBoardTimeout:   %v", *buildBoardTimeout)
       
    82 			log.Printf("reduceBoardTimeout:  %v", *reduceBoardTimeout)
       
    83 			log.Printf("Free cell min ratio: %v", *buildMinRatio)
       
    84 			log.Printf("Free cell max ratio: %v", *buildMaxRatio)
       
    85 		}
       
    86 		tak = newTakuzuGameBoard(int(*buildNewSize), *simple,
       
    87 			int(*workers),
       
    88 			*buildBoardTimeout, *reduceBoardTimeout,
       
    89 			int(*buildMinRatio), int(*buildMaxRatio))
       
    90 	}
       
    91 
       
    92 	if tak == nil {
       
    93 		fmt.Fprintln(os.Stderr, "Could not create takuzu board.")
       
    94 		os.Exit(255)
       
    95 	}
       
    96 
       
    97 	tak.DumpBoard()
       
    98 	fmt.Println()
       
    99 
       
   100 	if *pdfFileName != "" {
       
   101 		if err := tak2pdf(tak, *pdfFileName); err != nil {
       
   102 			log.Println(err)
       
   103 			os.Exit(1)
       
   104 		}
       
   105 		if *out {
       
   106 			tak.DumpString()
       
   107 		}
       
   108 		os.Exit(0)
       
   109 	}
       
   110 
       
   111 	if *buildNewSize > 0 {
       
   112 		if *out {
       
   113 			tak.DumpString()
       
   114 		}
       
   115 		os.Exit(0)
       
   116 	}
       
   117 
       
   118 	if *reduce {
       
   119 		if verbosity > 1 {
       
   120 			log.Printf("buildBoardTimeout:   %v", *buildBoardTimeout)
       
   121 			log.Printf("reduceBoardTimeout:  %v", *reduceBoardTimeout)
       
   122 		}
       
   123 		var err error
       
   124 		if tak, err = tak.ReduceBoard(*simple, "0", *buildBoardTimeout, *reduceBoardTimeout); err != nil {
       
   125 			log.Println(err)
       
   126 			os.Exit(1)
       
   127 		}
       
   128 
       
   129 		tak.DumpBoard()
       
   130 		fmt.Println()
       
   131 
       
   132 		if *out {
       
   133 			tak.DumpString()
       
   134 		}
       
   135 
       
   136 		os.Exit(0)
       
   137 	}
       
   138 
       
   139 	if *simple {
       
   140 		full, err := tak.TrySolveTrivial()
       
   141 		if err != nil {
       
   142 			log.Println(err)
       
   143 			os.Exit(1)
       
   144 		}
       
   145 		if !full {
       
   146 			tak.DumpBoard()
       
   147 			log.Println("The takuzu could not be completed using trivial methods.")
       
   148 			os.Exit(2)
       
   149 		}
       
   150 
       
   151 		log.Println("The takuzu is correct and complete.")
       
   152 		tak.DumpBoard()
       
   153 		fmt.Println()
       
   154 
       
   155 		if *out {
       
   156 			tak.DumpString()
       
   157 		}
       
   158 		os.Exit(0)
       
   159 	}
       
   160 
       
   161 	var allSol *[]takuzu.Takuzu
       
   162 	if *all {
       
   163 		allSol = &[]takuzu.Takuzu{}
       
   164 	}
       
   165 	res, err := tak.TrySolveRecurse(allSol, *resolveTimeout)
       
   166 	if err != nil && verbosity > 1 {
       
   167 		// The last trivial resolution failed
       
   168 		log.Println("Trivial resolution failed:", err)
       
   169 	}
       
   170 
       
   171 	// Ignoring res & err if a full search was requested
       
   172 	if *all {
       
   173 		log.Println(len(*allSol), "solution(s) found.")
       
   174 		if len(*allSol) > 0 {
       
   175 			for _, s := range *allSol {
       
   176 				if *out {
       
   177 					s.DumpString()
       
   178 				} else {
       
   179 					s.DumpBoard()
       
   180 					fmt.Println()
       
   181 				}
       
   182 			}
       
   183 			if len(*allSol) > 1 {
       
   184 				os.Exit(3)
       
   185 			}
       
   186 			os.Exit(0)
       
   187 		}
       
   188 		fmt.Println("No solution found.")
       
   189 		os.Exit(2)
       
   190 	}
       
   191 
       
   192 	if err != nil {
       
   193 		log.Println(err)
       
   194 		os.Exit(1)
       
   195 	}
       
   196 	if res != nil {
       
   197 		res.DumpBoard()
       
   198 		fmt.Println()
       
   199 
       
   200 		if *out {
       
   201 			res.DumpString()
       
   202 		}
       
   203 		os.Exit(0)
       
   204 	}
       
   205 
       
   206 	fmt.Println("No solution found.")
       
   207 	os.Exit(2)
       
   208 }