aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2016-06-26 14:38:01 +0200
committerCamil Staps2016-06-26 14:38:01 +0200
commita360c0089a3680655ca8ea6aa5b03ff652054c04 (patch)
treec01564b6c3902f2f5ae81320052288c867f9f33c
parentUpdate readme (diff)
Don't fill squares on the border; command line argumentsHEADmaster
-rw-r--r--Crosswords.icl54
-rw-r--r--README.md8
2 files changed, 43 insertions, 19 deletions
diff --git a/Crosswords.icl b/Crosswords.icl
index 038dc5b..324f484 100644
--- a/Crosswords.icl
+++ b/Crosswords.icl
@@ -2,6 +2,7 @@ module Crosswords
import StdEnv, StdDebug, StdOverloadedList
import MersenneTwister
+import ArgEnv
instance + String where (+) x y = x +++ y
@@ -24,28 +25,33 @@ instance zero Crossword where zero = []
:: RandomSeed :== Int
-dictionary :== "dictionary.txt"
-
// Reads words from stdin (end with empty line) and builds a crossword that
// connects all these words (if possible); then fills the crossword with words
// from dict-3-6.txt. Outputs LaTeX code (uses cwpuzzle.dtx from the crossword
// package).
Start w
-# (rand,w) = time 0 w
-# (fillwords,w) = readFillWords w
+// Read dictionary
+# cmd = getCommandLine
+# dictionary = if (size cmd > 1) cmd.[1] "dictionary.txt"
+# (fillwords,w) = readFillWords dictionary w
# fillwords = sortl fillwords
+// Read input
# (io,w) = stdio w
# (words,io) = readWords [] io
# (ok,w) = fclose io w
+| not ok = abort "Couldn't close stdio\n"
+// Make crossword
+# (rand,w) = time 0 w
+# rand = if (size cmd > 2) (toInt cmd.[2]) rand
# cw = makeCrossword rand words
# cw = trace_n ("\nIntermediate:\n" + toString cw) cw
# cw = fill rand fillwords cw
# cw = trace_n ("\nResult:\n" + toString cw) cw
-= toLaTeX cw
+= toLaTeX False cw
where
- readFillWords :: *World -> *([[#Char]], *World)
- readFillWords w
- # (ok,f,w) = fopen dictionary FReadText w
+ readFillWords :: String *World -> *([[#Char]], *World)
+ readFillWords fname w
+ # (ok,f,w) = fopen fname FReadText w
| not ok = ([], w)
# (words,f) = readWords [] f
# (ok,w) = fclose f w
@@ -72,8 +78,8 @@ miny cw :== minList [wp.y \\ wp <- cw]
maxx cw :== maxList [minx cw:[wp.x+Length wp.word-1 \\ wp<-cw | wp.dir==Hor]]
maxy cw :== maxList [miny cw:[wp.y+Length wp.word-1 \\ wp<-cw | wp.dir==Ver]]
-toLaTeX :: Crossword -> String
-toLaTeX cw
+toLaTeX :: Bool Crossword -> String
+toLaTeX fillBorders cw
= "\\begin{Puzzle}{" + toString width + "}{" + toString height + "}%\n" +
tex (minx cw) (miny cw) 1 (fromString (toString cw)) +
"\\end{Puzzle}\n"
@@ -82,9 +88,14 @@ where
height = maxy cw - miny cw + 1
tex :: Int Int Int [Char] -> String
- tex _ _ _ [] = ""
- tex x y n [' ':cs] = "|* " + tex (x+1) y n cs
- tex x y n ['\n':cs] = "|.\n" + tex (minx cw) (y+1) n cs
+ tex _ _ _ []
+ = ""
+ tex x y n [' ':cs]
+ | pathToBorder [] x y && not fillBorders
+ = "|{} " + tex (x+1) y n cs
+ = "|* " + tex (x+1) y n cs
+ tex x y n ['\n':cs]
+ = "|.\n" + tex (minx cw) (y+1) n cs
tex x y n [c:cs]
| occ (x+1) y && not (occ (x-1) y) || occ x (y+1) && not (occ x (y-1))
= "|[" + toString n + "]" + {c} + pad + " " + tex (x+1) y (n+1) cs
@@ -94,6 +105,19 @@ where
occ :: Int Int -> Bool
occ x y = any (any (\(_,x`,y`) -> x`==x && y`==y) o poss) cw
+ pathToBorder :: [(Int,Int)] Int Int -> Bool
+ pathToBorder seen x y
+ | isMember (x,y) seen = False
+ | occ x y = False
+ | x <= minx cw || x >= maxx cw = True
+ | y <= miny cw || y >= maxy cw = True
+ = any
+ (app2 (pathToBorder [(x,y):seen]))
+ [(x-1,y),(x+1,y),(x,y-1),(x,y+1)]
+ where
+ app2 :: (a a -> b) (a,a) -> b
+ app2 f (x,y) = f x y
+
instance toString Crossword
where
toString cw = foldl (+) ""
@@ -139,7 +163,7 @@ where
// Make a crossword, try to lay all words connected
makeCrossword :: RandomSeed [[#Char]] -> Crossword
-makeCrossword r words = place r fits words 0 zero
+makeCrossword r words = place r fits (sortl words) 0 zero
// Place a number of words in a crossword, satisfying a predicate
place :: RandomSeed PlacementOK [[#Char]] Int Crossword -> Crossword
@@ -160,7 +184,7 @@ placements :: RandomSeed PlacementOK [#Char] Crossword -> [WordPlacement]
placements _ fits word [] = [{word=word, dir=Hor, x=0, y=0}]
placements r fits word cw = (flatten o flatten)
[[[wp
- \\ wp <- [{word=word,dir=Hor,x=x-i,y=y},{word=word,dir=Ver,x=x,y=y-i}]
+ \\ wp <- [if (fixedwp.dir == Ver) {word=word,dir=Hor,x=x-i,y=y} {word=word,dir=Ver,x=x,y=y-i}]
| fits wp cw]
\\ (x,y) <- letterPositions letter fixedwp]
\\ letter <|- word & i <- [0..], fixedwp <- shuffle r cw]
diff --git a/README.md b/README.md
index 2d42e33..8eb52f3 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Crosswords
Crossword generator tool
-![Example](http://i.stack.imgur.com/Wc8e2.png)
+![Example](http://i.stack.imgur.com/I5r7L.png)
### Features
@@ -18,15 +18,15 @@ Crossword generator tool
### Installation
- $ clm -I $CLEAN_HOME/lib/MersenneTwister -b -h 100M Crosswords -o cwgen
+ $ clm -I $CLEAN_HOME/lib/ArgEnv -I $CLEAN_HOME/lib/MersenneTwister -b -h 100M Crosswords -o cwgen
### Usage example
Words are read from stdin, ended with an empty line or `EOF`, and of course
from the dictionary installed. The example above was created with the words
-`crossword`, `english` and `puzzling`.
+`newspaper`, `crossword`, `english` and `puzzling`.
- $ ./cwgen < words.txt > cw-gen.tex
+ $ ./cwgen [dictionary.txt] < words.txt > cw-gen.tex
$ pdflatex cw.tex
Remove `\PuzzleSolution[true]` from `cw.tex` to not show the solution in the