Advertisement
StupidSolver

Crossword Generator

Feb 21st, 2015
616
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 3.39 KB | None | 0 0
  1. import java.io.File
  2. import java.util.Scanner
  3.  
  4. import scala.collection.mutable
  5. import scala.io.Source
  6. import scala.util.Random
  7.  
  8. class Word(val letters: Seq[Letter])
  9.  
  10. sealed abstract class Cell {
  11.   def char(assignment: Map[Word, String]): Char
  12. }
  13. case class Letter() extends Cell {
  14.   var words = Array.empty[(Word, Int)]
  15.   override def char(assignment: Map[Word, String]): Char = assignment.get(words(0)._1).map(_(words(0)._2)).getOrElse('?')
  16. }
  17. case object Empty extends Cell {
  18.   override def char(assignment: Map[Word, String]): Char = '#'
  19. }
  20.  
  21. object Cross {
  22.   def main(args: Array[String]): Unit = {
  23.  
  24.     val dictionary: Map[Int, Set[String]] = readWords("cross.txt", "WINDOWS-1251").groupBy(_.length)
  25.     val field: List[List[Cell]] = readField("cross.in")
  26.  
  27.     val random = new Random(/*345345073895L*/)
  28.     val start = System.currentTimeMillis()
  29.     def dump(result: Map[Word, String]) =
  30.       println(field.map(_.map(_.char(result)).mkString("")).mkString("\n"))
  31.  
  32.     val cache = new mutable.HashMap[String, Array[String]]()
  33.     val words = (field.flatMap(extractWords) ++ field.transpose.flatMap(extractWords)).filter(_.letters.size != 1)
  34.     for (word <- words; (letter, index) <- word.letters.zipWithIndex) {
  35.       letter.words :+= (word, index)
  36.     }
  37.  
  38.     var min = words.size
  39.     def search(masks: Map[Word, String], assignment: Map[Word, String]) {
  40.       val level = masks.size
  41.       if (min > level) {
  42.         min = level
  43.         dump(assignment)
  44.         println(min + " " + (System.currentTimeMillis() - start) + " " + cache.size)
  45.       }
  46.       if (masks.isEmpty) {
  47.         dump(assignment)
  48.       } else {
  49.         val (word, mask) = masks.minBy(w => cache(w._2).size)
  50.         for (variant <- cache(mask)) {
  51.           var newVariants = masks - word
  52.           for ((letter, char) <- word.letters.zip(variant); (other, index) <- letter.words; if newVariants.contains(other)) {
  53.             val oldMask = masks(other)
  54.             val newMask = oldMask.updated(index, char)
  55.             cache.getOrElseUpdate(newMask, cache(oldMask).filter(_(index) == char))
  56.             newVariants = newVariants.updated(other, newMask)
  57.           }
  58.           search(newVariants, assignment.updated(word, variant))
  59.         }
  60.       }
  61.     }
  62.     for ((length, variants) <- dictionary) {
  63.       cache.getOrElseUpdate("?" * length, random.shuffle(variants.toList).toArray)
  64.     }
  65.     search(words.map(w => (w, "?" * w.letters.length)).toMap, Map.empty)
  66.   }
  67.  
  68.   def readField(file: String): List[List[Cell]] =
  69.     readTextField(file).map(_.toList.map(c => if (c == '#') Empty else Letter()))
  70.  
  71.   def readTextField(file: String): List[String] = {
  72.     val in = new Scanner(new File(file))
  73.     val w = in.nextInt()
  74.     val h = in.nextInt()
  75.     in.nextLine()
  76.     val lineFormat = s"#%-${w}s#"
  77.     List("#" * (w + 2)) ++ (for (i <- 0 until h) yield lineFormat.format(in.nextLine())) ++ List("#" * (w + 2))
  78.   }
  79.  
  80.   def substringBefore(string: String, substring: String) =
  81.     string.substring(0, string.indexOf(substring))
  82.  
  83.   def readWords(file: String, encoding: String) =
  84.     Source.fromFile("cross.txt", "WINDOWS-1251").getLines().map(substringBefore(_, " - ")).toSet
  85.  
  86.   def extractWords(row: List[Cell]): Seq[Word] = {
  87.     val rest = row.dropWhile(_ == Empty)
  88.     if (rest.isEmpty) Seq()
  89.     else new Word(rest.takeWhile(_ != Empty).map(_.asInstanceOf[Letter])) +: extractWords(rest.dropWhile(_ != Empty))
  90.   }
  91. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement