takuzu.go
changeset 8 955d3add9426
parent 7 e284e3ad2800
child 10 8dc05ff5dbe2
equal deleted inserted replaced
7:e284e3ad2800 8:955d3add9426
   254 	for i := range b.Board {
   254 	for i := range b.Board {
   255 		dumpRange(b.Board[i])
   255 		dumpRange(b.Board[i])
   256 	}
   256 	}
   257 }
   257 }
   258 
   258 
   259 // CheckLine returns an error if the line i fails validation
       
   260 func (b Takuzu) CheckLine(i int) error {
       
   261 	_, err := checkRange(b.GetLine(i))
       
   262 	return err
       
   263 }
       
   264 
       
   265 // CheckColumn returns an error if the column i fails validation
       
   266 func (b Takuzu) CheckColumn(i int) error {
       
   267 	_, err := checkRange(b.GetColumn(i))
       
   268 	return err
       
   269 }
       
   270 
       
   271 // Validate checks a whole board for errors (not completeness)
       
   272 // Returns true if all cells are defined.
       
   273 func (b Takuzu) Validate() (bool, error) {
       
   274 	finished := true
       
   275 
       
   276 	computeVal := func(cells []Cell) (val int) {
       
   277 		for i := 0; i < len(cells); i++ {
       
   278 			val += cells[i].Value * 1 << uint(i)
       
   279 		}
       
   280 		return
       
   281 	}
       
   282 
       
   283 	lineVals := make(map[int]bool)
       
   284 	colVals := make(map[int]bool)
       
   285 
       
   286 	for i := 0; i < b.Size; i++ {
       
   287 		var d []Cell
       
   288 		var full bool
       
   289 		var err error
       
   290 
       
   291 		// Let's check line i
       
   292 		d = b.GetLine(i)
       
   293 		full, err = checkRange(d)
       
   294 		if err != nil {
       
   295 			return false, errors.Wrapf(err, "line %d", i)
       
   296 		}
       
   297 		if full {
       
   298 			hv := computeVal(d)
       
   299 			if lineVals[hv] {
       
   300 				return false, fmt.Errorf("duplicate lines (%d)", i)
       
   301 			}
       
   302 			lineVals[hv] = true
       
   303 		} else {
       
   304 			finished = false
       
   305 		}
       
   306 
       
   307 		// Let's check column i
       
   308 		d = b.GetColumn(i)
       
   309 		full, err = checkRange(d)
       
   310 		if err != nil {
       
   311 			return false, errors.Wrapf(err, "column %d", i)
       
   312 		}
       
   313 		if full {
       
   314 			hv := computeVal(d)
       
   315 			if colVals[hv] {
       
   316 				return false, fmt.Errorf("duplicate columns (%d)", i)
       
   317 			}
       
   318 			colVals[hv] = true
       
   319 		} else {
       
   320 			finished = false
       
   321 		}
       
   322 	}
       
   323 	return finished, nil
       
   324 }
       
   325 
       
   326 func dumpRange(cells []Cell) {
   259 func dumpRange(cells []Cell) {
   327 	for _, c := range cells {
   260 	for _, c := range cells {
   328 		if !c.Defined {
   261 		if !c.Defined {
   329 			fmt.Printf(". ")
   262 			fmt.Printf(". ")
   330 			continue
   263 			continue
   331 		}
   264 		}
   332 		fmt.Printf("%d ", c.Value)
   265 		fmt.Printf("%d ", c.Value)
   333 	}
   266 	}
   334 	fmt.Println()
   267 	fmt.Println()
   335 }
   268 }
   336 
       
   337 // checkRange returns true if the range is completely defined, and an error
       
   338 // if it doesn't follow the rules for a takuzu line or column
       
   339 // Note that the boolean might be invalid if the error is not nil.
       
   340 func checkRange(cells []Cell) (bool, error) {
       
   341 	full := true
       
   342 	size := len(cells)
       
   343 	counters := []int{0, 0}
       
   344 
       
   345 	var prevCell Cell
       
   346 	var prevCellCount int
       
   347 
       
   348 	for _, c := range cells {
       
   349 		if !c.Defined {
       
   350 			full = false
       
   351 			prevCell.Defined = false
       
   352 			prevCellCount = 0
       
   353 			continue
       
   354 		}
       
   355 		counters[c.Value]++
       
   356 		if prevCellCount == 0 {
       
   357 			prevCellCount = 1
       
   358 		} else {
       
   359 			if c.Value == prevCell.Value {
       
   360 				prevCellCount++
       
   361 				if prevCellCount > 2 {
       
   362 					return full, errors.Errorf("3+ same values %d", c.Value)
       
   363 				}
       
   364 			} else {
       
   365 				prevCellCount = 1
       
   366 			}
       
   367 
       
   368 		}
       
   369 		prevCell = c
       
   370 	}
       
   371 	if counters[0] > size/2 {
       
   372 		return full, errors.Errorf("too many zeroes")
       
   373 	}
       
   374 	if counters[1] > size/2 {
       
   375 		return full, errors.Errorf("too many ones")
       
   376 	}
       
   377 	return full, nil
       
   378 }
       
   379 
       
   380 // CheckRangeCounts returns true if all cells of the provided range are defined,
       
   381 // as well as the number of 0s and the number of 1s in the range.
       
   382 func CheckRangeCounts(cells []Cell) (full bool, n0, n1 int) {
       
   383 	counters := []int{0, 0}
       
   384 	full = true
       
   385 
       
   386 	for _, c := range cells {
       
   387 		if c.Defined {
       
   388 			counters[c.Value]++
       
   389 		} else {
       
   390 			full = false
       
   391 		}
       
   392 	}
       
   393 	return full, counters[0], counters[1]
       
   394 }