rcrossword 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-06-22
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 FIXME full name
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README.txt
6
+ Rakefile
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/rcrossword.rb
10
+ lib/rcrossword/version.rb
11
+ lib/rcrossword/grid.rb
12
+ lib/rcrossword/generator.rb
13
+ script/console
14
+ script/destroy
15
+ script/generate
16
+ script/txt2html
17
+ setup.rb
18
+ tasks/deployment.rake
19
+ tasks/environment.rake
20
+ tasks/website.rake
21
+ test/test_helper.rb
22
+ test/test_rcrossword.rb
23
+ website/index.html
24
+ website/index.txt
25
+ website/javascripts/rounded_corners_lite.inc.js
26
+ website/stylesheets/screen.css
27
+ website/template.html.erb
@@ -0,0 +1,7 @@
1
+
2
+ For more information on rcrossword, see http://rcrossword.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
@@ -0,0 +1,84 @@
1
+ = rcrossword
2
+
3
+ * FIX (url)
4
+
5
+ == DESCRIPTION:
6
+
7
+ Dieses Projekt besteht zur Zeit im Wesentlichen aus der Klasse Grid, welche
8
+ grundlegende und allgemeine Methoden zum Arbeiten mit einer Kreuzwortraetsel-
9
+ Matrix zur Verfuegung stellt, sowie der Klasse Generator, welche die Algorithmen
10
+ zur Verfuegung stellt, mit denen ein Kreuzwortraetsel erstellt wird.
11
+
12
+ Aus den Test-Skripts ist ersichtlich, wie diese Klassen verwendet werden
13
+ koennen.
14
+
15
+ Die zentrale Methode zum Erzeugen eines Raetsel ist die Methode #generate.
16
+ Diese bekommt eine Liste mit Worten und Hinweistexten, und weiteren Parametern
17
+ uebergeben und versucht, daraus ein Raetsel zu generieren.
18
+
19
+ Momentan ist diese Methode noch nicht der Weisheit letzter Schluss. Sie funktioniert,
20
+ ist aber weder effizient noch wirklich gut (d. h. die Positionierung von Worten
21
+ muss noch besser werden).
22
+
23
+ Einige Verbesserungen sind schon angedacht, aber noch nicht implemetiert:
24
+ - Einfuegeposition nich rein zufaellig sondern nur an den Stellen, die noch
25
+ frei sind. D. h. man muesste irgendwie eine Liste von noch freien Positionen
26
+ verwalten
27
+ - Zur Zeit werden Worte aus der Liste noch mehrfach eingesetzt. Dies ist ein
28
+ eher triviales Problem und hat auf den grundlegenden Algorithmus keine
29
+ Auswirkungen. Man muss einfach nur das einmal eingesetzt Wort aus der Liste
30
+ entfernen, so dass es nicht mehrfach verwendet wird.
31
+ - Worte sollten nicht zufaellig plaziert werden, sondern nach einem intelligenteren
32
+ Algorithmus, der versucht, moeglichst Kreuzungen mit anderen Worten zu nutzen
33
+
34
+ Gff. wird es einen Mechanismus geben, um innerhalb des Programms mit
35
+ unterschiedlichen generate-Methoden zu arbeiten, bzw. zwischen ihnen umzuschalten.
36
+ Das würde bedeuten, es gibt mehrere Generator#generate Methoden, z.B. von
37
+ verschiedenen Leuten implementiert, um daraus fuer die Zukunft die beste
38
+ Strategie fuer das Programm auszuwaehlen.
39
+
40
+ Beim erfolgreichen Generieren wird daraus eine HTML-Datei zum bequemeren
41
+ Anschauen im Browser erzeugt. Weitere Methoden
42
+ ein Raetsel auszugeben sind geplant - beispielsweise waere eine LaTeX-Datei oder
43
+ eine XML-Datei moeglich.
44
+
45
+ == FEATURES/PROBLEMS:
46
+
47
+ * FIX (list of features or problems)
48
+
49
+ == SYNOPSIS:
50
+
51
+ FIX (code sample of usage)
52
+
53
+ == REQUIREMENTS:
54
+
55
+ * FIX (list of requirements)
56
+
57
+ == INSTALL:
58
+
59
+ * FIX (sudo gem install, anything else)
60
+
61
+ == LICENSE:
62
+
63
+ (The MIT License)
64
+
65
+ Copyright (c) 2008 FIXME full name
66
+
67
+ Permission is hereby granted, free of charge, to any person obtaining
68
+ a copy of this software and associated documentation files (the
69
+ 'Software'), to deal in the Software without restriction, including
70
+ without limitation the rights to use, copy, modify, merge, publish,
71
+ distribute, sublicense, and/or sell copies of the Software, and to
72
+ permit persons to whom the Software is furnished to do so, subject to
73
+ the following conditions:
74
+
75
+ The above copyright notice and this permission notice shall be
76
+ included in all copies or substantial portions of the Software.
77
+
78
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
79
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
80
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
81
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
82
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
83
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
84
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,73 @@
1
+ require 'rcrossword/version'
2
+
3
+ AUTHOR = 'Thomas Preymesser' # can also be an array of Authors
4
+ EMAIL = "thopre@gmail.com"
5
+ DESCRIPTION = "Generating crossword puzzles with ruby"
6
+ GEM_NAME = 'rcrossword' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'rcrossword' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+ EXTRA_DEPENDENCIES = [
11
+ # ['activesupport', '>= 1.3.1']
12
+ ] # An array of rubygem dependencies [name, version]
13
+
14
+ @config_file = "~/.rubyforge/user-config.yml"
15
+ @config = nil
16
+ RUBYFORGE_USERNAME = "thopre"
17
+ def rubyforge_username
18
+ unless @config
19
+ begin
20
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
21
+ rescue
22
+ puts <<-EOS
23
+ ERROR: No rubyforge config file found: #{@config_file}
24
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
25
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
26
+ EOS
27
+ exit
28
+ end
29
+ end
30
+ RUBYFORGE_USERNAME.replace @config["username"]
31
+ end
32
+
33
+
34
+ REV = nil
35
+ # UNCOMMENT IF REQUIRED:
36
+ # REV = YAML.load(`svn info`)['Revision']
37
+ VERS = Rcrossword::VERSION::STRING + (REV ? ".#{REV}" : "")
38
+ RDOC_OPTS = ['--quiet', '--title', 'rcrossword documentation',
39
+ "--opname", "index.html",
40
+ "--line-numbers",
41
+ "--main", "README",
42
+ "--inline-source"]
43
+
44
+ class Hoe
45
+ def extra_deps
46
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
47
+ @extra_deps
48
+ end
49
+ end
50
+
51
+ # Generate all the Rake tasks
52
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
53
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
54
+ p.developer(AUTHOR, EMAIL)
55
+ p.description = DESCRIPTION
56
+ p.summary = DESCRIPTION
57
+ p.url = HOMEPATH
58
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
59
+ p.test_globs = ["test/**/test_*.rb"]
60
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
61
+
62
+ # == Optional
63
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
64
+ #p.extra_deps = EXTRA_DEPENDENCIES
65
+
66
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
67
+ end
68
+
69
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
72
+ $hoe.rsync_args = '-av --delete --ignore-errors'
73
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Rcrossword
5
+
6
+ end
7
+ require 'rcrossword/grid'
8
+ require 'rcrossword/generator'
@@ -0,0 +1,137 @@
1
+ class Generator
2
+ attr_reader :title
3
+
4
+ def initialize(width,height,title)
5
+ @width = width
6
+ @height = height
7
+ @title = title
8
+ @matrix = Grid.new(width,height)
9
+ @hinweisliste = Hash.new
10
+ end
11
+
12
+ def can_insert?(line,column,orientation,word)
13
+ @matrix.insert_possible?(line,column,orientation,word)
14
+ end
15
+
16
+ # bekommt Worteliste (als Array) uebergeben und soll daraus ein Raetsel
17
+ # mit maximal N unbelegten Feldern erzeugen
18
+ def generate(wordlist,max_empty,max_tries,max_cycles)
19
+ empty = empty_cells
20
+ tries = 0
21
+ for cycle in 1..max_cycles
22
+ @matrix = Grid.new(@width,@height)
23
+ success = true
24
+ while empty > max_empty
25
+ if tries > max_tries
26
+ success = false
27
+ break # raise "max tries reached"
28
+ end
29
+ #puts "noch zu viele freie Zellen (#{empty})"
30
+ r = rand(wordlist.size)
31
+ random_word = wordlist[r][0]
32
+ random_hint = wordlist[r][1]
33
+ random_orientation = [:horizontal,:vertical][rand(2)]
34
+ while true
35
+ random_line = 1+rand(@height)
36
+ break if random_orientation == :horizontal
37
+ break if random_orientation == :vertical and random_line + random_word.length <= @height
38
+ end
39
+ while true
40
+ random_column = 1+rand(@width)
41
+ break if random_orientation == :vertical
42
+ break if random_orientation == :horizontal and random_column + random_word.length <= @width
43
+ end
44
+ # p random_word
45
+ # p random_line
46
+ # p random_column
47
+ # p random_orientation
48
+ tries += 1
49
+ if @matrix.insert(random_line,random_column,random_orientation,random_word)
50
+ puts @matrix.to_s
51
+
52
+ puts "(#{cycle}/#{tries}) '#{random_word}' konnte eingefügt werden"
53
+ $stdout.flush
54
+ key = [random_line,random_column]
55
+ value = [random_hint,random_orientation]
56
+ @hinweisliste[key] = value
57
+ else
58
+ #puts "konnte nicht eingefügt werden"
59
+ end
60
+ empty = empty_cells
61
+
62
+ end # while
63
+ break if success == true
64
+ end # for
65
+ unless success
66
+ raise "no success in #{max_cycles} cycles with #{max_tries} retries"
67
+ end
68
+ blank_to_slash
69
+ puts @matrix.to_s
70
+ puts "in #{tries} tries"
71
+ to_html("lalala.html")
72
+ true
73
+ end
74
+
75
+ private
76
+
77
+ def empty_cells
78
+ total = 0
79
+ for y in 1..@height
80
+ for x in 1..@width
81
+ total += 1 if @matrix.cell(y,x) == '.'
82
+ end
83
+ end
84
+ total
85
+ end
86
+
87
+ def blank_to_slash
88
+ for y in 1..@height
89
+ for x in 1..@width
90
+ @matrix.set(y,x,'/') if @matrix.cell(y,x) == '.'
91
+ end
92
+ end
93
+ end
94
+
95
+ def to_html(filename)
96
+ File.open(filename,"w") {|file|
97
+ file.puts("<html>")
98
+ file.puts(" <head>")
99
+ file.puts(" </head>")
100
+ file.puts(" <body>")
101
+ file.puts(" <table border=\"1\"")
102
+ for y in 1..@height
103
+ file.puts("<tr>")
104
+ for x in 1..@width
105
+ #@matrix.set(y,x,'/') if @matrix.cell(y,x) == '.'
106
+ if @matrix.cell(y,x) == '#'
107
+ file.puts("<td>")
108
+ file.puts("<font size=\"-4\">")
109
+ file.puts(@hinweisliste[[y,x]][0])
110
+ if @hinweisliste[[y,x]][1] == :horizontal
111
+ file.puts("-->")
112
+ else
113
+ file.puts("V")
114
+ end
115
+ file.puts("</font>")
116
+ file.puts("</td>")
117
+ #file.puts(@hinweisliste[[y,x]][1])
118
+ elsif @matrix.cell(y,x) == '/'
119
+ file.puts("<td bgcolor=\"black\">")
120
+ file.puts("&nbsp;")
121
+ file.puts("</td>")
122
+ else
123
+ file.puts("<td>")
124
+ file.puts(@matrix.cell(y,x))
125
+ file.puts("</td>")
126
+ end
127
+ end
128
+ file.puts("</tr>")
129
+ end
130
+ file.puts(" </table")
131
+ file.puts(" <body>")
132
+ file.puts("<html>")
133
+ }
134
+
135
+ end
136
+
137
+ end # Generator
@@ -0,0 +1,111 @@
1
+ class Grid
2
+ def initialize(width,height)
3
+ @width = width
4
+ @height = height
5
+ @matrix = Array.new(height+1)
6
+ for i in 1..@height
7
+ @matrix[i] = "."*(@width+1)
8
+ end
9
+ end
10
+
11
+ # returns the content of one line
12
+ def line(n)
13
+ @matrix[n][1..-1]
14
+ end
15
+
16
+ # returns the content of one cell
17
+ def cell(line,column)
18
+ if column >= 1 and column <= @width
19
+ self.line(line)[column-1..column-1]
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ # sets one cell with a character
26
+ def set(line,column,character)
27
+ begin
28
+ @matrix[line][column] = character
29
+ rescue NoMethodError
30
+ puts "Fehler: line #{line}, column #{column}, character #{character}"
31
+ raise
32
+ end
33
+ end
34
+
35
+ def insert_possible?(line,column,orientation,word)
36
+ raise ArgumentError if orientation != :horizontal and orientation != :vertical
37
+ l = line
38
+ c = column
39
+ if cell(l,c) != '.'
40
+ return false
41
+ end
42
+ l += 1 if orientation == :vertical
43
+ c += 1 if orientation == :horizontal
44
+ for pos in 0...word.size
45
+ # Kollision?
46
+ if cell(l,c) != '.' and cell(l,c) != word[pos..pos].upcase
47
+ return false
48
+ end
49
+ #self.set(l,c,word[pos..pos].upcase)
50
+ l += 1 if orientation == :vertical
51
+ c += 1 if orientation == :horizontal
52
+ end
53
+ # danach entweder Erklaerungszelle oder Stopzelle oder schon letzte Position im Grid
54
+ if orientation == :horizontal and c > @width
55
+ #OK
56
+ elsif orientation == :vertical and l > @height
57
+ #OK
58
+ else
59
+ if cell(l,c) == '#' or cell(l,c) == '/' or cell(l,c) == '.'
60
+ #OK
61
+ else
62
+ return false
63
+ end
64
+ end
65
+ true
66
+ end
67
+
68
+ # inserts a word. orientation is either :horizontal or :vertical
69
+ def insert(line,column,orientation,word)
70
+ raise ArgumentError if orientation != :horizontal and orientation != :vertical
71
+ l = line
72
+ c = column
73
+ if ! insert_possible?(l,c,orientation,word)
74
+ #puts "cannot insert #{word}"
75
+ return false
76
+ end
77
+ self.set(l,c,'#') # explanation cell
78
+ l += 1 if orientation == :vertical
79
+ c += 1 if orientation == :horizontal
80
+ for pos in 0...word.size
81
+ # Kollision?
82
+ if cell(l,c) != '.' and cell(l,c) != word[pos..pos].upcase
83
+ return false
84
+ end
85
+ self.set(l,c,word[pos..pos].upcase)
86
+ l += 1 if orientation == :vertical
87
+ c += 1 if orientation == :horizontal
88
+ end
89
+ if orientation == :horizontal and c <= @width
90
+ if cell(l,c) != '#'
91
+ self.set(l,c,'/')
92
+ end
93
+ end
94
+ if orientation == :vertical and l <= @height
95
+ if cell(l,c) != '#'
96
+ self.set(l,c,'/')
97
+ end
98
+ end
99
+ true
100
+ end
101
+
102
+ # returns an ASCII representation of the matrix
103
+ def to_s
104
+ result = ''
105
+ for line in 1..@height
106
+ result << self.line(line)+"\n"
107
+ end
108
+ result
109
+ end
110
+
111
+ end # class Matrix