<commit_before>package sudoku

// Sudoku has one rule - no value can be repeated horizontally, vertically,
// or in the same section. This gives rise to a few simple rules - and those
// rules are applied across each cluster - without even knowning the orientation
// of the cluster.
//
// In order to make solving possible however, that one rule is enforced with
// the following rules:
//
// 1) If all cells are solved, that cluster is solved.
// 2) If any cell is solved, it has no possibles.
// 3) If any cell is solved, that value is not possible in other cells.
// 4) If any cell only has one possible value, that is that cell's value.
// 5)If any x cells have x possible values, other cells in the cluster cannot be
//  those values - those values are constrained to those cells.
// 6) If any value only has one possible cell, that is that cell's value.
// 7) If any x values have x possible cells, other values are not possible
//  in those cells - those cells are constrained to those values.
//
// Additional Helper functions are included and explained later.

// indexedCLuster is a datatype for an index for the values of the cluster.
// Each possible value is a key in the map. THe value of each key is an array of
// possible locations for that value - the index and order are not defined,
// instead the values of the array are the indexes of possible cells in for that
// value.
type intArray []int
type indexedCluster map[int]intArray

func indexCluster(in []cell) (out indexedCluster) {
	for id, each := range in {
		for onePossible, _ := range each.possible {
			out[onePossible] = append(out[onePossible], id)
		}
	}
	return out
}

// look at the possible values for a cell - if there's only one, mark that cell as solved
func confirmCell(workingCell cell, u chan cell) bool {
	var firstFind int

	for loc, each := range workingCell.possible {
		if each {
			if firstFind != 0 {
				// I found two possible values for this cell
				return false
			}
			firstFind = loc
		}
		if firstFind != 0 {
			// send back an update and return true - you changed something
			u <- cell{
				location: workingCell.location,
				actual:   firstFind,
			}
			return true
		}
	}
	return false
}

// Removes known values from other possibles in the same cluster
func eliminatePossibles(workingCluster []cell, u chan cell) bool {
	var solved map[int]bool
	var remove map[int]bool
	var changed bool

	for _, each := range workingCluster {
		if each.actual != 0 {
			solved[each.actual] = true
		}
	}
<commit_msg>rewrote function for the 4th rule and renamed it to `singleValueSolver`<commit_after>package sudoku

// Sudoku has one rule - no value can be repeated horizontally, vertically,
// or in the same section. This gives rise to a few simple rules - and those
// rules are applied across each cluster - without even knowning the orientation
// of the cluster.
//
// In order to make solving possible however, that one rule is enforced with
// the following rules:
//
// 1) If all cells are solved, that cluster is solved.
// 2) If any cell is solved, it has no possibles.
// 3) If any cell is solved, that value is not possible in other cells.
// 4) If any cell only has one possible value, that is that cell's value.
// 5)If any x cells have x possible values, other cells in the cluster cannot be
//  those values - those values are constrained to those cells.
// 6) If any value only has one possible cell, that is that cell's value.
// 7) If any x values have x possible cells, other values are not possible
//  in those cells - those cells are constrained to those values.
//
// Additional Helper functions are included and explained later.

// indexedCLuster is a datatype for an index for the values of the cluster.
// Each possible value is a key in the map. THe value of each key is an array of
// possible locations for that value - the index and order are not defined,
// instead the values of the array are the indexes of possible cells in for that
// value.
type intArray []int
type indexedCluster map[int]intArray

func indexCluster(in []cell) (out indexedCluster) {
	for id, each := range in {
		for onePossible, _ := range each.possible {
			out[onePossible] = append(out[onePossible], id)
		}
	}
	return out
}

// This covers the 4th rule from above:
// 4) If any cell only has one possible value, that is that cell's value.
func singleValueSolver(cluster []cell, u chan cell) (changed bool) {
	for _, workingCell := range cluster {
		// if the cell is already solved, skip this.
		if workingCell.actual != 0 {
			continue
		}

		// if there is more than one possible value for this cell, you should be good
		if len(workingCell.possible) > 1 {
			continue
		}

		// should never happen
		if len(workingCell.possible) < 1 {
			panic("Found an unsolved cell with no possible values")
		}

		changed = true

		// this empty for loop will set value to each key in the map
		// since there's one key, it gives me that one key
		var key int
		for key, _ = range workingCell.possible {
		}

		// send back an update for this cell
		u <- cell{
			location: workingCell.location,
			actual:   key,
		}
	}
	return changed
}

// Removes known values from other possibles in the same cluster
func eliminatePossibles(workingCluster []cell, u chan cell) bool {
	var solved map[int]bool
	var remove map[int]bool
	var changed bool

	for _, each := range workingCluster {
		if each.actual != 0 {
			solved[each.actual] = true
		}
	}

{'fraction_non_alphanumeric': 0.07627274398088586, 'fraction_numerical': 0.0044109538687741225, 'mean_word_length': 3.18293620292083, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '429728', 'n_tokens_mistral': 1640, 'n_tokens_neox': 1494, 'n_words': 799}