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