build.go
author Mikael Berthe <mikael@lilotux.net>
Fri, 09 Sep 2016 23:28:58 +0200
changeset 5 733df0275d78
parent 0 00371339bbcc
child 10 8dc05ff5dbe2
permissions -rw-r--r--
Dump result board string even if the resolution fails (with --out)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     1
package takuzu
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     2
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     3
import (
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     4
	"fmt"
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     5
	"log"
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     6
	"math/rand"
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     7
	"time"
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     8
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     9
	"github.com/pkg/errors"
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    10
)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    11
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    12
func init() {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    13
	rand.Seed(time.Now().UTC().UnixNano())
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    14
}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    15
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    16
type buildTakuzuOptions struct {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    17
	size                                  int
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    18
	minRatio, maxRatio                    int
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    19
	simple                                bool
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    20
	buildBoardTimeout, reduceBoardTimeout time.Duration
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    21
}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    22
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    23
// ReduceBoard randomly removes as many numbers as possible from the
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    24
// takuzu board and returns a pointer to the new board.
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    25
// The initial takuzu might be modified.
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    26
func (tak Takuzu) ReduceBoard(trivial bool, wid string, buildBoardTimeout, reduceBoardTimeout time.Duration) (*Takuzu, error) {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    27
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    28
	size := tak.Size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    29
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    30
	// First check if the board is correct
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    31
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    32
		log.Printf("[%v]ReduceBoard: Checking for all grid solutions...", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    33
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    34
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    35
	allSol := &[]Takuzu{}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    36
	_, err := tak.Clone().TrySolveRecurse(allSol, buildBoardTimeout)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    37
	ns := len(*allSol)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    38
	if err != nil && errors.Cause(err).Error() == "timeout" {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    39
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    40
			log.Printf("[%v]ReduceBoard: There was a timeout (%d resolution(s) found).", wid, ns)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    41
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    42
		if ns == 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    43
			return nil, err
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    44
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    45
		//if ns < 10 { return nil, err }
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    46
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    47
			log.Printf("[%v]ReduceBoard: Going on anyway...", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    48
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    49
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    50
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    51
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    52
		log.Printf("[%v]ReduceBoard: %d solution(s) found.", wid, ns)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    53
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    54
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    55
	if ns == 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    56
		return nil, err
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    57
	} else if ns > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    58
		tak = (*allSol)[rand.Intn(ns)]
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    59
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    60
			log.Printf("[%v]ReduceBoard: Warning: there are %d solutions.", wid, ns)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    61
			log.Printf("[%v]ReduceBoard: Picking one randomly.", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    62
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    63
			if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    64
				tak.DumpBoard()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    65
				fmt.Println()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    66
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    67
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    68
		allSol = nil
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    69
	} else {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    70
		// 1 and only 1 solution
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    71
		if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    72
			tak.DumpBoard()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    73
			fmt.Println()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    74
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    75
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    76
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    77
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    78
		log.Printf("[%v]ReduceBoard: Grid reduction...", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    79
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    80
	fields := make([]*Cell, size*size)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    81
	n := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    82
	for l := range tak.Board {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    83
		for c := range tak.Board[l] {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    84
			if tak.Board[l][c].Defined {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    85
				fields[n] = &tak.Board[l][c]
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    86
				n++
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    87
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    88
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    89
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    90
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    91
	nDigits := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    92
	initialDigits := n
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    93
	ratio := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    94
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    95
		log.Printf("[%v]ReduceBoard: %d%%", wid, ratio)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    96
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    97
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    98
	for ; n > 0; n-- {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    99
		var rollback bool
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   100
		i := rand.Intn(n)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   101
		fields[i].Defined = false
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   102
		if trivial {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   103
			full, err := tak.Clone().TrySolveTrivial()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   104
			if err != nil || !full {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   105
				rollback = true
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   106
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   107
		} else {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   108
			allSol = &[]Takuzu{}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   109
			_, err := tak.Clone().TrySolveRecurse(allSol, reduceBoardTimeout)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   110
			if err != nil || len(*allSol) != 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   111
				rollback = true
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   112
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   113
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   114
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   115
		if rollback {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   116
			if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   117
				log.Printf("[%v]ReduceBoard: Backing out", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   118
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   119
			fields[i].Defined = true // Back out!
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   120
			nDigits++
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   121
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   122
		fields = append(fields[:i], fields[i+1:]...)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   123
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   124
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   125
			nr := (initialDigits - n) * 100 / initialDigits
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   126
			if nr > ratio {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   127
				ratio = nr
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   128
				log.Printf("[%v]ReduceBoard: %d%%", wid, ratio)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   129
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   130
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   131
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   132
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   133
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   134
		log.Printf("[%v]ReduceBoard: I have left %d digits.", wid, nDigits)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   135
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   136
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   137
	return &tak, nil
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   138
}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   139
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   140
// newRandomTakuzu creates a new Takuzu board with a given size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   141
// It is intended to be called by NewRandomTakuzu only.
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   142
func newRandomTakuzu(wid string, buildOpts buildTakuzuOptions) (*Takuzu, error) {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   143
	size := buildOpts.size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   144
	easy := buildOpts.simple
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   145
	buildBoardTimeout := buildOpts.buildBoardTimeout
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   146
	reduceBoardTimeout := buildOpts.reduceBoardTimeout
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   147
	minRatio := buildOpts.minRatio
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   148
	maxRatio := buildOpts.maxRatio
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   149
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   150
	tak := New(size)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   151
	n := size * size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   152
	fields := make([]*Cell, n)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   153
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   154
	i := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   155
	for l := range tak.Board {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   156
		for c := range tak.Board[l] {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   157
			fields[i] = &tak.Board[l][c]
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   158
			i++
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   159
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   160
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   161
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   162
	if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   163
		log.Printf("[%v]NewRandomTakuzu: Filling new board (%dx%[2]d)...", wid, size)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   164
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   165
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   166
	nop := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   167
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   168
	// #1. Loop until the ratio of empty cells is less than minRatio% (e.g. 55%)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   169
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   170
	for n > size*size*minRatio/100 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   171
		i := rand.Intn(n)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   172
		fields[i].Defined = true
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   173
		fields[i].Value = rand.Intn(2)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   174
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   175
		var err error
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   176
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   177
		if _, err = tak.Validate(); err != nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   178
			if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   179
				log.Printf("[%v]NewRandomTakuzu: Could not set cell value to %v", wid, fields[i].Value)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   180
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   181
		} else if _, err = tak.Clone().TrySolveTrivial(); err != nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   182
			if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   183
				log.Printf("[%v]NewRandomTakuzu: Trivial checks: Could not set cell value to %v", wid, fields[i].Value)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   184
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   185
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   186
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   187
		if err == nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   188
			fields = append(fields[:i], fields[i+1:]...)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   189
			n--
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   190
			continue
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   191
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   192
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   193
		// If any of the above checks fails, we roll back
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   194
		fields[i].Defined = false
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   195
		fields[i].Value = 0 // Let's reset but it is useless
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   196
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   197
		// Safety check to avoid deadlock on bad boards
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   198
		nop++
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   199
		if nop > 2*size*size {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   200
			log.Printf("[%v]NewRandomTakuzu: Could not fill up board!", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   201
			// Givin up on this board
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   202
			return nil, errors.New("could not fill up board") // Try again
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   203
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   204
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   205
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   206
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   207
	var ptak *Takuzu
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   208
	var removed int
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   209
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   210
	// #2. Try to solve the current board; try to remove some cells if it fails
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   211
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   212
	// Initial empty cells count
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   213
	iecc := n
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   214
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   215
	for {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   216
		// Current count of empty (i.e. undefined) cells
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   217
		ec := iecc + removed
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   218
		ecpc := ec * 100 / (size * size)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   219
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   220
			log.Printf("[%v]NewRandomTakuzu: Empty cells: %d (%d%%)", wid, ec, ecpc)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   221
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   222
		if ecpc > maxRatio {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   223
			if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   224
				log.Printf("[%v]NewRandomTakuzu: Too many empty cells (%d); giving up on this board", wid, ec)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   225
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   226
			break
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   227
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   228
		var err error
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   229
		ptak, err = tak.ReduceBoard(easy, wid, buildBoardTimeout, reduceBoardTimeout)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   230
		if err != nil && errors.Cause(err).Error() == "timeout" {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   231
			break
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   232
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   233
		if err == nil && ptak != nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   234
			break
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   235
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   236
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   237
			log.Printf("[%v]NewRandomTakuzu: Could not use this grid", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   238
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   239
		inc := size * size / 150
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   240
		if inc == 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   241
			inc = 1
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   242
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   243
		tak.removeRandomCell(inc)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   244
		removed += inc
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   245
		if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   246
			log.Printf("[%v]NewRandomTakuzu: Removed %d numbers", wid, removed)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   247
			if verbosity > 1 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   248
				tak.DumpBoard()
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   249
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   250
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   251
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   252
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   253
	if ptak == nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   254
		if verbosity > 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   255
			log.Printf("[%v]NewRandomTakuzu: Couldn't use this board, restarting from scratch...", wid)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   256
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   257
		return nil, errors.New("could not use current board") // Try again
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   258
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   259
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   260
	return ptak, nil
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   261
}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   262
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   263
// NewRandomTakuzu creates a new Takuzu board with a given size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   264
func NewRandomTakuzu(size int, simple bool, wid string, buildBoardTimeout, reduceBoardTimeout time.Duration, minRatio, maxRatio int) (*Takuzu, error) {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   265
	if size%2 != 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   266
		return nil, errors.New("board size should be an even value")
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   267
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   268
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   269
	if size < 4 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   270
		return nil, errors.New("board size is too small")
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   271
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   272
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   273
	// minRatio : percentage (1-100) of empty cells when creating a new board
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   274
	// If the board is wrong the cells will be removed until we reach maxRatio
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   275
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   276
	if minRatio < 40 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   277
		minRatio = 40
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   278
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   279
	if minRatio > maxRatio {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   280
		return nil, errors.New("minRatio/maxRatio incorrect")
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   281
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   282
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   283
	if maxRatio > 99 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   284
		maxRatio = 99
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   285
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   286
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   287
	buildOptions := buildTakuzuOptions{
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   288
		size:               size,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   289
		minRatio:           minRatio,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   290
		maxRatio:           maxRatio,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   291
		simple:             simple,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   292
		buildBoardTimeout:  buildBoardTimeout,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   293
		reduceBoardTimeout: reduceBoardTimeout,
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   294
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   295
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   296
	var takP *Takuzu
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   297
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   298
	for {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   299
		var err error
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   300
		takP, err = newRandomTakuzu(wid, buildOptions)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   301
		if err == nil {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   302
			break
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   303
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   304
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   305
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   306
	return takP, nil
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   307
}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   308
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   309
func (tak Takuzu) removeRandomCell(number int) {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   310
	size := tak.Size
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   311
	fields := make([]*Cell, size*size)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   312
	n := 0
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   313
	for l := range tak.Board {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   314
		for c := range tak.Board[l] {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   315
			if tak.Board[l][c].Defined {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   316
				fields[n] = &tak.Board[l][c]
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   317
				n++
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   318
			}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   319
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   320
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   321
	for i := 0; i < number; i++ {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   322
		if n == 0 {
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   323
			return
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   324
		}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   325
		fields[rand.Intn(n)].Defined = false
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   326
		fields = append(fields[:i], fields[i+1:]...)
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   327
		n--
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   328
	}
00371339bbcc Import refactored version
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   329
}