public void Undo(CrossPattern aCrossPattern) { //Console.WriteLine("Undo: {0}", new String(aCrossPattern.Pattern)); for (int i = 0; i < _changes.Count; i += 3) { var adjIdx = _changes[i]; var pos = _changes[i + 1]; char[] pattern; if (adjIdx == -1) { pattern = aCrossPattern.Pattern; } else { pattern = aCrossPattern.AdjacentPatterns[adjIdx].Pattern; } pattern[pos] = '.'; } for (int i = 0; i < _instChanges.Count; i += 3) { var adjIdx = _instChanges[i]; var old = _instChanges[i + 1]; if (adjIdx != -1) { aCrossPattern.AdjacentPatterns[adjIdx].InstantiationCount = old; } else { aCrossPattern.InstantiationCount = old; } } }
public void Transform(CrossPattern aCrossPattern) { for (int i = 0; i < _changes.Count; i += 3) { var adjIdx = _changes[i]; var pos = _changes[i + 1]; var newChar = (char)_changes[i + 2]; char[] pattern; if (adjIdx == -1) { pattern = aCrossPattern.Pattern; } else { pattern = aCrossPattern.AdjacentPatterns[adjIdx].Pattern; } pattern[pos] = newChar; } for (int i = 0; i < _instChanges.Count; i += 3) { var adjIdx = _instChanges[i]; var newInst = _instChanges[i + 2]; if (adjIdx != -1) { aCrossPattern.AdjacentPatterns[adjIdx].InstantiationCount = newInst; } else { aCrossPattern.InstantiationCount = newInst; } } //Console.WriteLine("Transform: {0}", new String(aCrossPattern.Pattern)); }
CrossPattern BackTrack(List <int> history, List <List <CrossTransformation> > historyTrans, HashSet <string> usedWords) { CrossPattern crossPatternToContinueWith = null; while (history.Count > 0) { int last = history.Count - 1; int item = history[last]; var succTrans = historyTrans[last]; var trans = succTrans[item]; trans.Undo(trans.Pattern); usedWords.Remove(trans.Word); item++; if (item < succTrans.Count) { var nextTrans = succTrans[item]; usedWords.Add(nextTrans.Word); nextTrans.Transform(nextTrans.Pattern); history[last] = item; crossPatternToContinueWith = _board.GetMostConstrainedPattern(_dict); break; } history.RemoveAt(last); historyTrans.RemoveAt(last); } return(crossPatternToContinueWith); }
public object Clone() { var result = new CrossPattern(_startX, _startY, _length, _isHorizontal); result._instantiationCount = _instantiationCount; result._pattern = new char[_pattern.Length]; Array.Copy(_pattern, result._pattern, _pattern.Length); return result; }
public CrossPattern(int startX, int startY, int length, bool isHorizontal) { _startX = startX; _startY = startY; _length = length; AdjacentPatterns = new CrossPattern[_length]; _isHorizontal = isHorizontal; _pattern = Enumerable.Repeat('.', length).ToArray(); }
public object Clone() { var result = new CrossPattern(_startX, _startY, _length, _isHorizontal); result._instantiationCount = _instantiationCount; result._pattern = new char[_pattern.Length]; Array.Copy(_pattern, result._pattern, _pattern.Length); return(result); }
public CrossWordGuardian ToCrossWordModelGuardian(ICrossDictionary dictionary) { var model = new CrossWordGuardian(); var clueList = new List <IClue>(); var patterns = new List <CrossPattern>(); // across = horizontal foreach (var p in _horizontalPatterns) { patterns.Add(p); } // down = vertical foreach (var p in _verticalPatterns) { patterns.Add(p); } var sortedPatterns = patterns.OrderBy(s => s.StartY).ThenBy(s => s.StartX); int gridNumber = 0; CrossPattern lastPattern = null; var coordinateMap = new Dictionary <CrossPattern, Coordinate>(); // when using a database - read in all descriptions once dictionary.AddAllDescriptions(patterns.Select(a => a.GetWord()).ToList()); foreach (var p in sortedPatterns) { if (lastPattern != null && lastPattern.StartX == p.StartX && lastPattern.StartY == p.StartY) { // patterns starts at same index } else { // pattern start at new index, increment gridNumber++; } // store grid number as a part of the coordinate coordinateMap.Add(p, new Coordinate(p.StartX, p.StartY, gridNumber)); // and store the clues var word = p.GetWord(); var description = p.IsPuzzle ? "[PUZZLE]" : GetDescription(dictionary, word); var clue = new IClue(); clue.Id = string.Format("{0}-{1}", gridNumber, p.IsHorizontal ? "across" : "down"); clue.Number = gridNumber; clue.HumanNumber = gridNumber.ToString(); clue.Clue = string.Format("{0} ({1})", description, p.Length); clue.Direction = p.IsHorizontal ? Direction.Across : Direction.Down; clue.Length = p.Length; clue.Group = new string[] { clue.Id }; clue.Position = new IPosition() { X = p.StartX, Y = p.StartY }; clue.Solution = word; clue.SeparatorLocations = new SeparatorLocations(); clueList.Add(clue); // save last pattern to compare with lastPattern = p; } model.Id = null; model.Name = "Generated Crossword"; model.Creator = new ICreator() { Name = "the amazing crossword generator", WebUrl = "" }; model.Entries = clueList.ToArray(); model.Dimensions = new IDimensions { Cols = _sizeX, Rows = _sizeY }; model.CrosswordType = CrosswordType.Quick; model.SolutionAvailable = true; model.Pdf = null; model.Instructions = null; model.Date = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); model.DateSolutionAvailable = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); return(model); }
public CrossWordTimes ToCrossWordModel(ICrossDictionary dictionary) { var model = new CrossWordTimes(); var board = new char[_sizeX, _sizeY]; foreach (var sw in _startWords) { board[sw.StartX, sw.StartY] = '-'; } var patterns = new List <CrossPattern>(); var stringWriter = new StringWriter(); // across = horizontal foreach (var p in _horizontalPatterns) { patterns.Add(p); for (int x = p.StartX; x < p.StartX + p.Length; x++) { if (p.Pattern != null) { board[x, p.StartY] = p.Pattern[x - p.StartX]; } else { board[x, p.StartY] = '.'; } } // stringWriter.WriteLine("{0}<br>", p); } // down = vertical foreach (var p in _verticalPatterns) { patterns.Add(p); for (int y = p.StartY; y < p.StartY + p.Length; y++) { if (p.Pattern != null) { var c = p.Pattern[y - p.StartY]; if (c != '.') { board[p.StartX, y] = c; } } } // stringWriter.WriteLine("{0}<br>", p); } // calculate grid numbers and build answer and clues lists var acrossAnswerList = new List <String>(); var downAnswerList = new List <String>(); var acrossClueList = new List <String>(); var downClueList = new List <String>(); model.Gridnums = new long[_sizeX * _sizeY]; model.Circles = new long[_sizeX * _sizeY]; var sortedPatterns = patterns.OrderBy(s => s.StartY).ThenBy(s => s.StartX); int gridNumber = 0; CrossPattern lastPattern = null; var coordinateMap = new Dictionary <CrossPattern, Coordinate>(); // when using a database - read in all descriptions once dictionary.AddAllDescriptions(patterns.Select(a => a.GetWord()).ToList()); foreach (var p in sortedPatterns) { if (lastPattern != null && lastPattern.StartX == p.StartX && lastPattern.StartY == p.StartY) { // patterns starts at same index } else { // pattern start at new index, increment gridNumber++; } // store grid number as a part of the coordinate coordinateMap.Add(p, new Coordinate(p.StartX, p.StartY, gridNumber)); // and store the clues var word = p.GetWord(); var description = p.IsPuzzle ? "[PUZZLE]" : GetDescription(dictionary, word); string clue = string.Format("{0}. {1}", gridNumber, description); if (p.IsHorizontal) { acrossAnswerList.Add(word); acrossClueList.Add(clue); } else { downAnswerList.Add(word); downClueList.Add(clue); } // save last pattern to compare with lastPattern = p; } // build output var grid = new List <String>(); for (int y = 0; y < _sizeY; y++) { string row = ""; for (int x = 0; x < _sizeX; x++) { row += board[x, y] + " "; // set grid but replace - with . grid.Add(board[x, y].ToString().Replace('-', '.')); if (board[x, y] != '-') { var coordinate = new Coordinate(x, y); if (coordinateMap.ContainsValue(coordinate)) { Coordinate foundCoordinate = null; var coordinates = coordinateMap.Where(v => v.Value == coordinate); if (coordinates.Count(a => a.Key.IsPuzzle) > 0) { var hit = coordinates.Where(a => a.Key.IsPuzzle).First(); var IsHorizontal = hit.Key.IsHorizontal; var letterCount = hit.Key.Length; // highlight all cells covered by the word foundCoordinate = hit.Value; if (IsHorizontal) { for (int i = 0; i < letterCount; i++) { model.Circles[(y * _sizeX) + x + i] = 1; } } else { for (int i = 0; i < letterCount; i++) { model.Circles[((y * _sizeX) + x) + (i * _sizeX)] = 1; } } } else { foundCoordinate = coordinates.First().Value; } model.Gridnums[(y * _sizeX) + x] = foundCoordinate.GridNumber; } } } // stringWriter.WriteLine("{0:00}: {1} <br>", y, row); } model.Title = "Generated Crossword"; model.Author = "the amazing crossword generator"; model.Copyright = "Crossword Generator"; model.Size = new Size { Cols = _sizeX, Rows = _sizeY }; // model.Notepad = "<br>" + stringWriter.ToString(); model.Grid = grid.ToArray(); model.Clues = new Answers() { Across = acrossClueList.ToArray(), Down = downClueList.ToArray() }; model.Answers = new Answers() { Across = acrossAnswerList.ToArray(), Down = downAnswerList.ToArray() }; model.Shadecircles = false; return(model); }
public void Preprocess(ICrossDictionary aDict) { _horizontalPatterns = new List <CrossPattern>(); _startWords.Sort(new YXStartWordComparer()); // first create horizontal patterns int wordIdx = 0; for (int y = 0; y < _sizeY; y++) { int nextX = 0; while (wordIdx < _startWords.Count) { var sw = _startWords[wordIdx]; // Console.WriteLine("StartWord x:{0} y:{1} idx:{2}/cnt:{3}",sw.StartX,sw.StartY,wordIdx,_startWords.Count); if (sw.StartY == y) { if (sw.StartX - nextX >= MinPatternLength) { var cp = new CrossPattern(nextX, y, sw.StartX - nextX, true); // Console.WriteLine("SW pattern startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _horizontalPatterns.Add(cp); } nextX = sw.StartX + 1; wordIdx++; } else { break; } } if (_sizeX - nextX >= MinPatternLength) { var cp = new CrossPattern(nextX, y, _sizeX - nextX, true); // Console.WriteLine("EL pattern startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _horizontalPatterns.Add(cp); } } _verticalPatterns = new List <CrossPattern>(); _startWords.Sort(new XYStartWordComparer()); // then create vertical patterns wordIdx = 0; for (int x = 0; x < _sizeX; x++) { int nextY = 0; while (wordIdx < _startWords.Count) { var sw = _startWords[wordIdx]; // Console.WriteLine("StartWord x:{0} y:{1} idx:{2}/cnt:{3}",sw.StartX,sw.StartY,wordIdx,_startWords.Count); if (sw.StartX == x) { if (sw.StartY - nextY >= MinPatternLength) { var cp = new CrossPattern(x, nextY, sw.StartY - nextY, false); // Console.WriteLine("SW patternY startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _verticalPatterns.Add(cp); } nextY = sw.StartY + 1; wordIdx++; } else { break; } } if (_sizeY - nextY >= MinPatternLength) { var cp = new CrossPattern(x, nextY, _sizeY - nextY, false); // Console.WriteLine("EL patternY startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _verticalPatterns.Add(cp); } } BindAdjacentPatterns(); // calculate instantiation count var wordLengthCount = new int[aDict.MaxWordLength + 1]; for (int i = 1; i <= aDict.MaxWordLength; i++) { wordLengthCount[i] = aDict.GetWordOfLengthCount(i); } int patternCount = GetPatternCount(); for (int i = 0; i < patternCount; i++) { var pattern = GetCrossPattern(i); if (pattern.Pattern == null) { // empty pattern.InstantiationCount = wordLengthCount[pattern.Length]; pattern.Pattern = Enumerable.Repeat('.', pattern.Length).ToArray(); } else { // already set some letters pattern.InstantiationCount = aDict.GetMatchCount(pattern.Pattern); } } }
/* * 1. Choosing which pattern to fill (i.e. which variable to solve for). * 2. Picking a suitable word (i.e. which value to select). * 3. Choosing where to backtrack to when we reach an impasse. */ public IEnumerable <ICrossBoard> Generate() { var history = new List <int>(); var historyTrans = new List <List <CrossTransformation> >(); var matchingWords = new List <string>(); var usedWords = new HashSet <string>(); CrossPattern pattern = _board.GetMostConstrainedPattern(_dict); Random rnd = new Random(); while (true) { DoCommands(); if (pattern != null) { matchingWords.Clear(); _dict.GetMatch(pattern.Pattern, matchingWords); var succTrans = new List <CrossTransformation>(); foreach (string t in matchingWords) { if (usedWords.Count > 0 && usedWords.Contains(t)) { continue; } // checking if there exist words in the dictionary matching each of the adjacent patterns var trans = pattern.TryFill(t, t.AsSpan(), _dict); if (trans != null) { succTrans.Add(trans); trans.Pattern = pattern; } } if (succTrans.Count > 0) { succTrans.Sort(new CrossTransformationComparer()); // using the successfull transform with most ?! // always use the first index (i.e. the one with the most possible adjacent hits) var trans = succTrans[0]; history.Add(0); // don't always use the "best" match to randomize the crossword better // var lowestIndexToUse = 0; // var highestIndexToUse = succTrans.Count > 10 ? 10 : succTrans.Count; // int index = rnd.Next(lowestIndexToUse, highestIndexToUse); // var trans = succTrans[index]; // history.Add(index); usedWords.Add(trans.Word); trans.Transform(pattern); historyTrans.Add(succTrans); pattern = _board.GetMostConstrainedPattern(_dict); } else { pattern = BackTrack(history, historyTrans, usedWords); if (pattern == null) { yield break; } } } else { yield return(_board.Clone()); pattern = BackTrack(history, historyTrans, usedWords); if (pattern == null) { yield break; } } } }
public void Preprocess(ICrossDictionary aDict) { _horizontalPatterns.Clear(); _startWords.Sort(new YXStartWordComparer()); //first create horizontal patterns int wordIdx = 0; for (int y = 0; y < _sizeY; y++) { int nextX = 0; while (wordIdx < _startWords.Count) { var sw = _startWords[wordIdx]; //Console.WriteLine("StartWord x:{0} y:{1} idx:{2}/cnt:{3}",sw.StartX,sw.StartY,wordIdx,_startWords.Count); if (sw.StartY == y) { if (sw.StartX - nextX >= MinPatternLength) { var cp = new CrossPattern(nextX, y, sw.StartX - nextX, true); //Console.WriteLine("SW pattern startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _horizontalPatterns.Add(cp); } nextX = sw.StartX + 1; wordIdx++; } else { break; } } if (_sizeX - nextX >= MinPatternLength) { var cp = new CrossPattern(nextX, y, _sizeX - nextX, true); //Console.WriteLine("EL pattern startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _horizontalPatterns.Add(cp); } } _verticalPatterns.Clear(); _startWords.Sort(new XYStartWordComparer()); //first create horizontal patterns wordIdx = 0; for (int x = 0; x < _sizeX; x++) { int nextY = 0; while (wordIdx < _startWords.Count) { var sw = _startWords[wordIdx]; //Console.WriteLine("StartWord x:{0} y:{1} idx:{2}/cnt:{3}",sw.StartX,sw.StartY,wordIdx,_startWords.Count); if (sw.StartX == x) { if (sw.StartY - nextY >= MinPatternLength) { var cp = new CrossPattern(x, nextY, sw.StartY - nextY, false); //Console.WriteLine("SW patternY startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _verticalPatterns.Add(cp); } nextY = sw.StartY + 1; wordIdx++; } else { break; } } if (_sizeY - nextY >= MinPatternLength) { var cp = new CrossPattern(x, nextY, _sizeY - nextY, false); //Console.WriteLine("EL patternY startX: {0} startY: {1} len: {2}",cp.StartX, cp.StartY, cp.Length); _verticalPatterns.Add(cp); } } BindAdjacentPatterns(); //set instantiation count int patternCount = GetPatternCount(); for (int i = 0; i < patternCount; i++) { var pattern = GetCrossPattern(i); pattern.InstantiationCount = aDict.GetWordOfLengthCount(pattern.Length); } }