public bool Check(Soup soup, WordEntry entry) { var boundaries = new BoundariesManager(NullLogger <BoundariesManager> .Instance); boundaries.Soup = soup; return(boundaries.Check(entry)); }
private (Range left, Range right, bool hasCommon) FindCommonLetters(WordEntry a, WordEntry b) { int minLength = Math.Min(a.Name.Length, b.Name.Length); string nameA = a.Direction.IsReverse() ? Reverse(a.Name) : a.Name; string nameB = b.Direction.IsReverse() ? Reverse(b.Name) : b.Name; for (int i = 1; i < minLength; i++) { string e = nameA.Substring(nameA.Length - i); string c = nameB.Substring(0, i); if (e == c) { int leftInit = a.Direction.IsReverse() ? 0 : nameA.Length - i; int rightInit = b.Direction.IsReverse() ? nameB.Length - i : 0; return(left : new Range { Init = leftInit, Length = i }, right : new Range { Init = rightInit, Length = i }, hasCommon : true ); } } return(left : null, right : null, hasCommon : false); }
/// <summary> /// Computes the necessary delta to move the <see cref="WordEntry"/> inside the boundaries /// </summary> /// <param name="entry"><see cref="WordEntry"/> to test</param> /// <returns>Delta</returns> public Point GetDelta(WordEntry entry) { var size = new Point(Soup.Matrix.GetUpperBound(0), Soup.Matrix.GetUpperBound(1)); var origin = entry.Origin; var ending = entry.EndingCoordinate(); var result = new Point(); if (origin.X < 0) { result.X = origin.X * -1; } if (origin.Y < 0) { result.Y = origin.Y * -1; } if (ending.X > size.X) { result.X = size.X - ending.X; } if (ending.Y > size.Y) { result.Y = size.Y - ending.Y; } return(result); }
public bool Check(WordEntry entry) { var size = new Point(Soup.Matrix.GetUpperBound(0), Soup.Matrix.GetUpperBound(1)); var origin = entry.AbsoluteOrigin(); var ending = entry.AbsoluteEnding(); bool haveHorizontalSpace = origin.X >= 0 && ending.X <= size.X; bool haveVerticalSpace = origin.Y >= 0 && ending.Y <= size.Y; return(haveHorizontalSpace && haveVerticalSpace); }
/// <summary> /// Returns <c>true</c> if the <see cref="Candidate"/> entry intersects with other entries besides the <see cref="Existing"/> /// </summary> /// <param name="candidate">Candidate word to check with existing entries</param> /// <param name="entries">List of entries already set up in the <see cref="Soup"/></param> public bool IntersectsWithOthers(WordEntry candidate, IEnumerable <WordEntry> entries) { foreach (WordEntry entry in entries) { if (entry.Name != Existing.Name && entry.IntersectWith(candidate)) { Logger.LogDebug($"Also intersects with {entry}"); return(true); } } return(false); }
/// <summary> /// Initialize the words to check if have intersection /// </summary> /// <param name="existing"><see cref="WordEntry"/> already set in the <see cref="Soup"/></param> /// <param name="candidate"><see cref="WordEntry"/> to test if can be set in the <see cref="Soup"/></param> public void Check(WordEntry existing, WordEntry candidate) { if (Soup == null) { throw new InvalidOperationException($"{nameof(Soup)} must be initialized"); } Existing = existing ?? throw new ArgumentNullException(nameof(existing)); Candidate = candidate ?? throw new ArgumentNullException(nameof(candidate)); if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogDebug($"Comparing to ({Existing})"); } GetIntersection(); }
/// <summary> /// Fill the alphabet soup with random words in random coordinates and directions /// </summary> /// <returns>The reated <see cref="Soup"/></returns> public Soup Create() { Logger.LogInformation("==Starting generation=="); int total = 0; for (int i = 0; i < Options.NumWords; i++) { bool failed = false; WordEntry wordEntry = null; do { failed = false; wordEntry = NextEntry(); Logger.LogInformation($"Trying {wordEntry}"); foreach (WordEntry existing in Soup.UsedWords.Values) { IntersectionManager.Check(existing, wordEntry); if (IntersectionManager.Intersects) { wordEntry = IntersectionManager.RepositionEntry(); if (wordEntry == null) { failed = true; } } if (failed) { break; } } if (!failed) { foreach (IRule rule in Rules) { if (!rule.Check(Soup, wordEntry)) { Logger.LogWarning($"Word {wordEntry.Name} doesn't match '{rule.Name}' rule."); failed = true; break; } } } total++; } while (failed); System.Diagnostics.Debug.Assert(wordEntry != null); AddWord(wordEntry); } Logger.LogInformation($"==Finishing generation ({Options.NumWords}/{total})=="); return(Soup); }
/// <summary> /// Returns <c>true</c> if the <see cref="WordEntry"/> intersects in any point with <paramref name="other"/> /// </summary> /// <param name="other">The <see cref="WordEntry"/> to test</param> public bool IntersectWith(WordEntry other) { for (int i = 0; i < Name.Length; i++) { for (int j = 0; j < other.Name.Length; j++) { if (Coordinate(i) == other.Coordinate(j)) { return(true); } } } return(false); }
private bool IsOverlapped(WordEntry bigWord, WordEntry smallWord) { var big = bigWord.AbsoluteOrigin(); var small = smallWord.AbsoluteOrigin(); bool overlapp = false; if (bigWord.Direction.MovesHorizontal()) { overlapp = small.X >= big.X && small.X + smallWord.Name.Length <= big.X + bigWord.Name.Length; } if (!overlapp && bigWord.Direction.MovesVertical()) { overlapp = small.Y >= big.Y && small.Y + smallWord.Name.Length <= big.Y + bigWord.Name.Length; } return(overlapp); }
private void AddWord(WordEntry wordEntry) { for (int i = 0; i < wordEntry.Name.Length; i++) { char c = wordEntry.Name[i]; Point pt = wordEntry.Coordinate(i); try { Soup.Matrix[pt.X, pt.Y] = c; Soup.ShadowMatrix[pt.X, pt.Y] = true; } catch (Exception ex) { System.Diagnostics.Debug.Print($"{ex.Message} at ({pt.X}, {pt.Y}) with entry: {wordEntry}"); throw; } } Soup.UsedWords.Add(wordEntry.Name, wordEntry); }
/// <summary> /// Compute and set the new <see cref="WordEntry.Origin"/> of the <see cref="Candidate"/> entry, so this entry intersects in the common letter /// </summary> /// <exception cref="InvalidOperationException">If both entries do not intersect or do not have common letters</exception> public WordEntry RepositionEntry() { if (!Intersects) { throw new InvalidOperationException("Can't reposition an entry that do not intersects with others"); } if (!GetCommonLetters()) { Logger.LogWarning($"Words {Existing} and {Candidate} intersect but don't have common letters"); return(null); } bool reposition = false; WordEntry repositionedWord = null; if (Overlaps) { Logger.LogInformation($"Words {Existing} and {Candidate} overlap {Count} common letters"); Point target = Existing.Coordinate(ExistingRange.Init); int increment = Candidate.Direction.IsReverse() ? 1 : 0; Point delta = target.Delta(Candidate.Coordinate(CandidateRange.Init + increment)); repositionedWord = Candidate.Translate(delta); bool insideBoundaries = CheckBoundaries(repositionedWord.Origin); reposition = insideBoundaries && !IntersectsWithOthers(repositionedWord, Soup.UsedWords.Values); } else { int i = 0; bool insideBoundaries = false; Logger.LogInformation($"Candidate intersects at ({this[0]}) with ({Existing})"); do { Point target = Existing.Coordinate(CommonLetters[i].ExistingPos); Point delta = target.Delta(Candidate.Coordinate(CommonLetters[i].CandidatePos)); repositionedWord = Candidate.Translate(delta); Logger.LogDebug($"Try to reposition to: {repositionedWord}"); insideBoundaries = CheckBoundaries(repositionedWord.Origin); i++; } while (!insideBoundaries && i < CommonLetters.Count); reposition = insideBoundaries && !IntersectsWithOthers(repositionedWord, Soup.UsedWords.Values); } if (reposition) { Logger.LogWarning($"Candidate repositioned: {repositionedWord}"); return(repositionedWord); } return(null); }
public bool Check(Soup soup, WordEntry entry) { foreach (WordEntry item in soup.UsedWords.Values) { if (item.Direction.SameDirection(entry.Direction)) { if (item.Name.Length >= entry.Name.Length) { if (IsOverlapped(item, entry)) { return(false); } } else { if (IsOverlapped(entry, item)) { return(false); } } } } return(true); }
public bool Check(Soup soup, WordEntry entry) { return(entry.Name.Length >= _min && entry.Name.Length <= _max); }
public bool Check(Soup soup, WordEntry entry) { return(!soup.UsedWords.Keys.Contains(entry.Name)); }