// Will return -1 if the word cannot be placed. private int CountIntersections(Word word, Point start) { int intersections = 0; if (!CanWordFit(word, start)) { return(-1); } for (int i = 0; i < word.GetLength(); ++i) { Point p = GetWordCoord(word, start, i); if (blocks[p.X, p.Y] != null) { if (blocks[p.X, p.Y].GetAnswer() == word.GetCorrectWord()[i]) { intersections++; } else if (!blocks[p.X, p.Y].CanOverwrite(word.GetDirection())) { return(-1); } } } return(intersections); }
private bool TryPlace(Word w, Point start, int minIntersections) { int inters = CountIntersections(w, start); // "Useless" condition for a special case. Handled seperately for clarity. if (inters < 0) { return(false); } else if (inters < minIntersections) { return(false); } else if (inters == w.GetCorrectWord().Length) { return(false); } PlaceWord(w, start); return(true); }
// Excpects a word that can be placed private void PlaceWord(Word word, Point start) { Point before = GetWordCoord(word, start, -1); Point after = GetWordCoord(word, start, word.GetLength()); // Its ok to overwrite the old block here since black blocks do not get stored anywhere else than the block[,] array blocks[before.X, before.Y] = new BlackBlock(BlockOverwrite.None); blocks[after.X, after.Y] = new BlackBlock(BlockOverwrite.None); for (int i = 0; i < word.GetLength(); i++) { Point p = GetWordCoord(word, start, i); if (blocks[p.X, p.Y] == null || blocks[p.X, p.Y] is BlackBlock) { blocks[p.X, p.Y] = new CharacterBlock(word.GetCorrectWord()[i]); } word.SetSharedBlock(blocks[p.X, p.Y] as CharacterBlock, i); ProhibitOverwrite(GetWordCoord(word, start, i, 1), word.GetDirection()); ProhibitOverwrite(GetWordCoord(word, start, i, -1), word.GetDirection()); } words.Add(word); }
public void GenerateNewCrossword(CrosswordSize newSize = CrosswordSize.UsePrevious) { if (newSize != CrosswordSize.UsePrevious) { size = newSize; } switch (size) { case CrosswordSize.Small: SizeX = SizeY = 17; break; case CrosswordSize.Normal: SizeX = SizeY = 24; break; case CrosswordSize.Large: SizeX = SizeY = 31; break; case CrosswordSize.VeryLarge: SizeX = SizeY = 45; break; } words.Clear(); if (initialWords.Count < 4) { MessageBox.Show("Not enough words left for a new crossword. Reloading wordlist file.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning); InitialiseFromFile(); } const float GenerationComplexityFactor = 2.0f; blocks = new IBlock[SizeX, SizeY]; int InitialSizeWords = initialWords.Count; Random r = new Random(); DateTime timeStart = DateTime.Now; // Place first word at random bool Placed = false; while (!Placed) { int x = r.Next((int)Math.Ceiling(SizeX * 0.30), (int)Math.Floor(SizeX * 0.70)); int y = r.Next((int)Math.Ceiling(SizeY * 0.30), (int)Math.Floor(SizeY * 0.70)); int index = r.Next(initialWords.Count); Word w = GenerateWord(index, r); if (TryPlace(w, new Point(x, y), 0)) { initialWords.RemoveAt(index); Placed = true; } } int LoopsWithoutProgress = 0; float GenerationFactor = InitialSizeWords * GenerationComplexityFactor; int SingleIntersectionCount = 0; while (initialWords.Count > 0 && LoopsWithoutProgress < GenerationFactor) { int wordsPlaced = InitialSizeWords - initialWords.Count; float wordsPlacedPercent = wordsPlaced / InitialSizeWords; int index = r.Next(initialWords.Count); Word w = GenerateWord(index, r); int minIntersections = 1; if (wordsPlaced < 3) { if (w.GetCorrectWord().Length > 5) { minIntersections = 1; } else { continue; } } else if (LoopsWithoutProgress < GenerationFactor * 0.1) { minIntersections = 4; } else if (LoopsWithoutProgress < GenerationFactor * 0.3) { minIntersections = 3; } else if (LoopsWithoutProgress < GenerationFactor * 0.9) { minIntersections = 2; } else { minIntersections = 1; } LoopsWithoutProgress++; if (TryPlaceEverywhere(w, minIntersections, r)) { if (minIntersections == 1) { SingleIntersectionCount++; } LoopsWithoutProgress = 0; initialWords.RemoveAt(index); } } TimeSpan ts = DateTime.Now - timeStart; int ms = (int)ts.TotalMilliseconds; if (ms > 3000) { MessageBox.Show("Took " + ms + "ms to make this crossword.", "", MessageBoxButtons.OK, MessageBoxIcon.Information); } // Fill empty blocks for (int row = 0; row < blocks.GetLength(0); row++) { for (int col = 0; col < blocks.GetLength(1); col++) { if (blocks[row, col] == null) { blocks[row, col] = new BlackBlock(); } } } }