rcrossword 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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