public Puzzle SetWord(CellRange cellRange, string word) { //if (!Matches(cellRange, word)) throw new ArgumentException("Mismatch"); var puzzle = new Puzzle(CopyOfCells(), this.cellRanges, this.Words.Where(w => w != word), this.solution); puzzle.SetLetters(cellRange, word); var newFilled = puzzle.FilledCellRanges.ToList(); var currentFilled = FilledCellRanges.ToList(); var diff = newFilled.Except(currentFilled).ToList(); diff.Remove(cellRange); if (diff.Count() > 0) { foreach (var cr in diff) { var extraWord = puzzle.GetWord(cr); if (!puzzle.Words.Remove(extraWord)) { return(null); // Fill was invalid } } } return(puzzle); }
public void Verify() { var notFilled = cellRanges.Where(cr => GetLetters(cr, cells).Any(l => !l.HasValue)).ToList(); if (Words.Count() != notFilled.Count()) { throw new Exception($"Expected {cellRanges.Count()} words, but got {Words.Count()}"); } var wordLengths = Words.GroupBy(w => w.Length).ToDictionary(g => g.Key, g => g.Count()); var rangeLengths = notFilled.GroupBy(cr => cr.Length).ToDictionary(g => g.Key, g => g.Count()); foreach (var kvp in rangeLengths) { if (wordLengths[kvp.Key] != kvp.Value) { throw new Exception($"Expected {kvp.Value} words of length {kvp.Key}, but got {wordLengths[kvp.Key]}"); } } if (!cellRanges.Any(cr => PartiallyFilled(cr))) { throw new Exception($"Expected at least one initial anchor word"); } if (solution != null) { var unsedWords = Words.Concat(FilledCellRanges.Select(cr => GetWord(cr))).ToList(); foreach (var cellRange in cellRanges) { var word = GetWord(cellRange, solution); if (!unsedWords.Remove(word)) { throw new Exception($"Solution word '{word}' is not a valid word or it was used more than once."); } } } }