gamefic 0.2.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gamefic/action.rb +87 -56
  3. data/lib/gamefic/ansi.rb +55 -0
  4. data/lib/gamefic/character.rb +130 -76
  5. data/lib/gamefic/command.rb +19 -0
  6. data/lib/gamefic/core_ext/array.rb +51 -40
  7. data/lib/gamefic/core_ext/string.rb +4 -0
  8. data/lib/gamefic/describable.rb +108 -46
  9. data/lib/gamefic/direction.rb +46 -0
  10. data/lib/gamefic/director/delegate.rb +91 -0
  11. data/lib/gamefic/director/order.rb +10 -0
  12. data/lib/gamefic/director/parser.rb +119 -0
  13. data/lib/gamefic/director.rb +16 -197
  14. data/lib/gamefic/engine/cgi.rb +221 -0
  15. data/lib/gamefic/engine/tty.rb +237 -0
  16. data/lib/gamefic/engine.rb +88 -67
  17. data/lib/gamefic/entity.rb +96 -69
  18. data/lib/gamefic/grammar/conjugator.rb +20 -0
  19. data/lib/gamefic/grammar/gender.rb +11 -0
  20. data/lib/gamefic/grammar/person.rb +10 -0
  21. data/lib/gamefic/grammar/plural.rb +13 -0
  22. data/lib/gamefic/grammar/pronouns.rb +60 -0
  23. data/lib/gamefic/grammar/tense.rb +6 -0
  24. data/lib/gamefic/grammar/verb_set.rb +43 -0
  25. data/lib/gamefic/grammar/verbs.rb +25 -0
  26. data/lib/gamefic/grammar/word_adapter.rb +36 -0
  27. data/lib/gamefic/grammar.rb +13 -0
  28. data/lib/gamefic/html.rb +53 -0
  29. data/lib/gamefic/keywords.rb +51 -33
  30. data/lib/gamefic/node.rb +65 -58
  31. data/lib/gamefic/plot/article_mount.rb +22 -0
  32. data/lib/gamefic/plot/command_mount.rb +88 -0
  33. data/lib/gamefic/plot/entity_mount.rb +45 -0
  34. data/lib/gamefic/plot/query_mount.rb +9 -0
  35. data/lib/gamefic/plot/scene_mount.rb +181 -0
  36. data/lib/gamefic/plot/you_mount.rb +22 -0
  37. data/lib/gamefic/plot.rb +296 -247
  38. data/lib/gamefic/query/ambiguous_children.rb +5 -0
  39. data/lib/gamefic/query/base.rb +265 -0
  40. data/lib/gamefic/query/children.rb +10 -0
  41. data/lib/gamefic/query/expression.rb +47 -0
  42. data/lib/gamefic/query/family.rb +10 -0
  43. data/lib/gamefic/query/many_children.rb +7 -0
  44. data/lib/gamefic/query/matches.rb +11 -0
  45. data/lib/gamefic/query/parent.rb +10 -0
  46. data/lib/gamefic/query/plural_children.rb +14 -0
  47. data/lib/gamefic/query/self.rb +10 -0
  48. data/lib/gamefic/query/siblings.rb +10 -0
  49. data/lib/gamefic/query/text.rb +43 -0
  50. data/lib/gamefic/query.rb +19 -203
  51. data/lib/gamefic/rule.rb +18 -0
  52. data/lib/gamefic/scene/active.rb +25 -0
  53. data/lib/gamefic/scene/concluded.rb +22 -0
  54. data/lib/gamefic/scene/multiplechoice.rb +74 -0
  55. data/lib/gamefic/scene/paused.rb +26 -0
  56. data/lib/gamefic/scene/yesorno.rb +43 -0
  57. data/lib/gamefic/scene.rb +125 -0
  58. data/lib/gamefic/script/base.rb +33 -0
  59. data/lib/gamefic/script/file.rb +14 -0
  60. data/lib/gamefic/script/text.rb +14 -0
  61. data/lib/gamefic/script.rb +9 -0
  62. data/lib/gamefic/serialized.rb +24 -0
  63. data/lib/gamefic/shell.rb +9 -247
  64. data/lib/gamefic/snapshots.rb +134 -0
  65. data/lib/gamefic/source/base.rb +12 -0
  66. data/lib/gamefic/source/file.rb +23 -0
  67. data/lib/gamefic/source/text.rb +16 -0
  68. data/lib/gamefic/source.rb +9 -0
  69. data/lib/gamefic/stage.rb +75 -0
  70. data/lib/gamefic/syntax.rb +106 -124
  71. data/lib/gamefic/tester.rb +20 -0
  72. data/lib/gamefic/version.rb +3 -0
  73. data/lib/gamefic.rb +18 -12
  74. metadata +102 -70
  75. data/lib/gamefic/base.rb +0 -10
  76. data/lib/gamefic/before.rb +0 -12
  77. data/lib/gamefic/import/basics/actions/close.rb +0 -16
  78. data/lib/gamefic/import/basics/actions/commands.rb +0 -3
  79. data/lib/gamefic/import/basics/actions/drop-in.rb +0 -17
  80. data/lib/gamefic/import/basics/actions/drop-on.rb +0 -16
  81. data/lib/gamefic/import/basics/actions/drop.rb +0 -30
  82. data/lib/gamefic/import/basics/actions/enter.rb +0 -16
  83. data/lib/gamefic/import/basics/actions/go.rb +0 -35
  84. data/lib/gamefic/import/basics/actions/inventory.rb +0 -8
  85. data/lib/gamefic/import/basics/actions/leave.rb +0 -29
  86. data/lib/gamefic/import/basics/actions/look-in-at.rb +0 -27
  87. data/lib/gamefic/import/basics/actions/look-under.rb +0 -3
  88. data/lib/gamefic/import/basics/actions/look.rb +0 -71
  89. data/lib/gamefic/import/basics/actions/nil.rb +0 -25
  90. data/lib/gamefic/import/basics/actions/open.rb +0 -23
  91. data/lib/gamefic/import/basics/actions/quit.rb +0 -3
  92. data/lib/gamefic/import/basics/actions/take.rb +0 -107
  93. data/lib/gamefic/import/basics/entities/container.rb +0 -8
  94. data/lib/gamefic/import/basics/entities/entity.rb +0 -11
  95. data/lib/gamefic/import/basics/entities/fixture.rb +0 -5
  96. data/lib/gamefic/import/basics/entities/item.rb +0 -5
  97. data/lib/gamefic/import/basics/entities/portal.rb +0 -40
  98. data/lib/gamefic/import/basics/entities/room.rb +0 -30
  99. data/lib/gamefic/import/basics/entities/scenery.rb +0 -5
  100. data/lib/gamefic/import/basics/entities/supporter.rb +0 -6
  101. data/lib/gamefic/import/basics/entities/thing.rb +0 -16
  102. data/lib/gamefic/import/basics/queries/reachable.rb +0 -38
  103. data/lib/gamefic/import/basics/queries/room.rb +0 -8
  104. data/lib/gamefic/import/basics/queries/visible.rb +0 -32
  105. data/lib/gamefic/import/basics/rules/has-enough-light.rb +0 -14
  106. data/lib/gamefic/import/basics.old/actions/container.rb +0 -112
  107. data/lib/gamefic/import/basics.old/actions/inventory.rb +0 -50
  108. data/lib/gamefic/import/basics.old/actions/look.rb +0 -53
  109. data/lib/gamefic/import/basics.old/actions/meta.rb +0 -6
  110. data/lib/gamefic/import/basics.old/actions/traversal.rb +0 -35
  111. data/lib/gamefic/import/basics.old/actions.rb +0 -1
  112. data/lib/gamefic/import/basics.old/entities/container.rb +0 -3
  113. data/lib/gamefic/import/basics.old/entities/fixture.rb +0 -3
  114. data/lib/gamefic/import/basics.old/entities/item.rb +0 -3
  115. data/lib/gamefic/import/basics.old/entities/portal.rb +0 -43
  116. data/lib/gamefic/import/basics.old/entities/room.rb +0 -27
  117. data/lib/gamefic/import/basics.old/entities/scenery.rb +0 -3
  118. data/lib/gamefic/import/basics.old/entities/supporter.rb +0 -3
  119. data/lib/gamefic/import/basics.old/entities.rb +0 -1
  120. data/lib/gamefic/import/basics.old/room_modes.rb +0 -48
  121. data/lib/gamefic/import/basics.rb +0 -6
  122. data/lib/gamefic/import/room_modes.rb +0 -48
  123. data/lib/gamefic/import/standard.rb +0 -1
  124. data/lib/gamefic/meta.rb +0 -12
  125. data/lib/gamefic/optionset.rb +0 -114
  126. data/lib/gamefic/requirement.rb +0 -14
  127. data/lib/gamefic/story.rb +0 -14
  128. data/lib/gamefic/thing.rb +0 -7
@@ -1,76 +1,103 @@
1
- require "digest/md5"
2
1
  require "gamefic/node"
3
2
  require "gamefic/describable"
4
- require "gamefic/plot"
3
+ require "gamefic/serialized"
5
4
 
6
5
  module Gamefic
7
6
 
8
- class Entity
9
- include Branch
10
- include Describable
11
- include OptionSettings
12
- attr_writer :option_array
13
- attr_reader :session, :plot
14
- def initialize(plot, args = {})
15
- if (plot.kind_of?(Plot) == false)
16
- raise "First argument must be a Plot"
17
- end
18
- pre_initialize
19
- #self.state = State
20
- #@story = Subplot.current
21
- @plot = plot
22
- @option_mapper = @plot
23
- @plot.send :add_entity, self
24
- #@story.add_entity self
25
- args.each { |key, value|
26
- send "#{key}=", value
27
- }
28
- @update_procs = Array.new
29
- @session = Hash.new
30
- post_initialize
31
- end
32
- #def self.present(args = {})
33
- # story = Plot.Loading
34
- # if story == nil
35
- # raise "No plot loading"
36
- # end
37
- # return self.new(story, args)
38
- #end
39
- def uid
40
- if @uid == nil
41
- @uid = Digest::MD5.hexdigest(self.object_id.to_s)[0,8]
42
- end
43
- @uid
44
- end
45
- def pre_initialize
46
- # raise NotImplementedError, "#{self.class} must implement post_initialize"
47
- end
48
- def post_initialize
49
- # raise NotImplementedError, "#{self.class} must implement post_initialize"
50
- end
51
- def tell(message, refresh = false)
52
- #TODO: Should this even be here? In all likelihood, only Characters receive tells, right?
53
- #TODO: On second thought, it might be interesting to see logs from an npc point of view.
54
- end
55
- def update
56
- @update_procs.each { |p|
57
- p.call self
58
- }
59
- end
60
- def on_update(&block)
61
- @update_procs.push block
62
- end
63
- def parent=(node)
64
- if node != nil and node.kind_of?(Entity) == false and node.kind_of?(Zone) == false
65
- raise "Entity's parent must be an Entity or a Zone"
66
- end
67
- super
68
- end
69
- def destroy
70
- self.parent = nil
71
- # TODO: Need to call this private method here?
72
- @plot.send(:rem_entity, self)
73
- end
74
- end
7
+ class Entity
8
+ include Node
9
+ include Describable
10
+ include Serialized
11
+ extend Serialized::ClassMethods
12
+ include Grammar::WordAdapter
13
+
14
+ attr_reader :session, :plot
15
+ serialize :name, :parent, :description
16
+
17
+ def initialize(plot, args = {})
18
+ if (plot.kind_of?(Plot) == false)
19
+ raise "First argument must be a Plot"
20
+ end
21
+ pre_initialize
22
+ @plot = plot
23
+ @plot.send :add_entity, self
24
+ args.each { |key, value|
25
+ send "#{key}=", value
26
+ }
27
+ @update_procs = Array.new
28
+ @session = Hash.new
29
+ yield self if block_given?
30
+ post_initialize
31
+ end
32
+ def uid
33
+ if @uid == nil
34
+ @uid = self.object_id.to_s
35
+ end
36
+ @uid
37
+ end
38
+ def pre_initialize
39
+ # raise NotImplementedError, "#{self.class} must implement post_initialize"
40
+ end
41
+ def post_initialize
42
+ # raise NotImplementedError, "#{self.class} must implement post_initialize"
43
+ end
44
+ def tell(message)
45
+ #TODO: Should this even be here? In all likelihood, only Characters receive tells, right?
46
+ #TODO: On second thought, it might be interesting to see logs from an npc point of view.
47
+ end
48
+ def stream(message)
49
+ # Unlike tell, this method sends raw data without formatting.
50
+ end
51
+
52
+ # Execute the entity's on_update blocks.
53
+ # This method is typically called by the Engine that manages game execution.
54
+ #
55
+ def update
56
+ @update_procs.each { |p|
57
+ p.call self
58
+ }
59
+ end
60
+
61
+ # Add a block to be executed when the game updates a turn.
62
+ #
63
+ # @yieldparam [Entity]
64
+ def on_update(&block)
65
+ @update_procs.push block
66
+ end
67
+
68
+ # Set the Entity's parent.
69
+ #
70
+ # @param node [Entity] The new parent.
71
+ def parent=(node)
72
+ if node != nil and node.kind_of?(Entity) == false
73
+ raise "Entity's parent must be an Entity"
74
+ end
75
+ super
76
+ end
77
+
78
+ # Remove this Entity from its current Plot.
79
+ #
80
+ def destroy
81
+ self.parent = nil
82
+ # TODO: Need to call this private method here?
83
+ @plot.send(:rem_entity, self)
84
+ end
85
+
86
+ # Get an extended property.
87
+ #
88
+ # @param key [Symbol] The property's name.
89
+ def [](key)
90
+ session[key]
91
+ end
92
+
93
+ # Set an extended property.
94
+ #
95
+ # @param key [Symbol] The property's name.
96
+ # @param value The value to set.
97
+ def []=(key, value)
98
+ session[key] = value
99
+ end
100
+
101
+ end
75
102
 
76
103
  end
@@ -0,0 +1,20 @@
1
+ require 'gamefic'
2
+ require 'gamefic/grammar'
3
+
4
+ module Gamefic::Grammar
5
+ module Conjugator
6
+ module ClassMethods
7
+ @@conjugated_verbs = {}
8
+ def conjugate infinitive, tense, *forms
9
+ @@conjugated_verbs[infinitive] ||= {}
10
+ @@conjugated_verbs[infinitive][tense] = VerbSet.new(infinitive, *forms)
11
+ end
12
+ def conjugated_verbs
13
+ @@conjugated_verbs
14
+ end
15
+ end
16
+ #def self.included(base)
17
+ # base.extend ClassMethods
18
+ #end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ require 'gamefic/grammar'
2
+
3
+ module Gamefic::Grammar
4
+ module Gender
5
+ attr_writer :gender
6
+ def gender
7
+ # Supported values are "male", "female", "other", and "neutral"
8
+ @gender ||= "neutral"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require 'gamefic/grammar'
2
+
3
+ module Gamefic::Grammar
4
+ module Person
5
+ attr_writer :person
6
+ def person
7
+ @person ||= 3
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ require 'gamefic/grammar'
2
+
3
+ module Gamefic::Grammar
4
+ module Plural
5
+ attr_writer :plural
6
+ def plural?
7
+ if @plural.nil?
8
+ @plural = false
9
+ end
10
+ @plural
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,60 @@
1
+ require 'gamefic'
2
+ require 'gamefic/grammar'
3
+
4
+ module Gamefic::Grammar
5
+ class Pronouns
6
+ def initialize object
7
+ @object = object
8
+ end
9
+ def subj
10
+ Pronouns.get_pronoun_set(@object)[0]
11
+ end
12
+ def obj
13
+ Pronouns.get_pronoun_set(@object)[1]
14
+ end
15
+ def poss
16
+ Pronouns.get_pronoun_set(@object)[2]
17
+ end
18
+ def Subj
19
+ subj.cap_first
20
+ end
21
+ def Obj
22
+ obj.cap_first
23
+ end
24
+ def Poss
25
+ obj.cap_first
26
+ end
27
+ def self.get_pronoun_set(obj)
28
+ set = Pronouns.sets["#{obj.person}"]
29
+ if set.nil?
30
+ set = Pronouns.sets["#{obj.person}:#{obj.plural? ? 'plural' : 'singular'}"]
31
+ end
32
+ if set.nil?
33
+ set = Pronouns.sets["#{obj.person}:#{obj.plural? ? 'plural' : 'singular'}:#{obj.gender}"]
34
+ end
35
+ if set.nil?
36
+ raise "Pronoun set could not be determined"
37
+ end
38
+ set
39
+ end
40
+ # TODO Consider implementing method_missing to determine correct pronoun
41
+ # from example, e.g., "he" would change to "she" for female entities
42
+ def self.sets
43
+ if @sets.nil?
44
+ @sets = {}
45
+ @sets["1:singular"] = ["I", "me", "my"]
46
+ @sets["2"] = ["you", "you", "your"]
47
+ @sets["3:singular:male"] = ["he", "him", "his"]
48
+ @sets["3:singular:female"] = ["she", "her", "her"]
49
+ # "other" refers to a person or living being that is neither
50
+ # male or female or for whom gender is unspecified. It's
51
+ # typically used to avoid referring to a person as "it."
52
+ @sets["3:singular:other"] = ["they", "them", "their"]
53
+ @sets["3:singular:neutral"] = ["it", "it", "its"]
54
+ @sets["1:plural"] = ["we", "us", "our"]
55
+ @sets["3:plural"] = ["they", "them", "their"]
56
+ end
57
+ @sets
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,6 @@
1
+ require 'gamefic/grammar'
2
+
3
+ module Gamefic::Grammar::Tense
4
+ PRESENT = :present
5
+ PAST = :past
6
+ end
@@ -0,0 +1,43 @@
1
+ require 'gamefic/grammar'
2
+
3
+ module Gamefic::Grammar
4
+ class VerbSet
5
+ def initialize infinitive, *forms
6
+ # TODO what to do with the tense?
7
+ @infinitive = infinitive.to_s
8
+ @forms = {}
9
+ form = forms[0]
10
+ @forms["1:singular"] = form.nil? ? @infinitive.to_s : form.to_s
11
+ form = forms[1]
12
+ @forms["2:singular"] = form.nil? ? @infinitive.to_s : form.to_s
13
+ form = forms[2]
14
+ @forms["3:singular"] = form.nil? ? generate_third_singular : form.to_s
15
+ form = forms[3]
16
+ @forms["1:plural"] = form.nil? ? @infinitive.to_s : form.to_s
17
+ form = forms[4]
18
+ @forms["2:plural"] = form.nil? ? @forms["1:plural"] : form.to_s
19
+ form = forms[5]
20
+ @forms["3:plural"] = form.nil? ? @forms["1:plural"] : form.to_s
21
+ end
22
+ def conjugate pronoun
23
+ form = @forms["#{pronoun.person}"]
24
+ if form.nil?
25
+ form = @forms["#{pronoun.person}:#{pronoun.plural? ? 'plural' : 'singular'}"]
26
+ end
27
+ if form.nil?
28
+ raise "Unable to conjugate #{@infinitive}"
29
+ end
30
+ form
31
+ end
32
+ private
33
+ def generate_third_singular
34
+ if @infinitive.end_with?('o')
35
+ @infinitive + "es"
36
+ elsif @infinitive.end_with?('ry')
37
+ @infinitive[0..-2] + "ies"
38
+ else
39
+ @infinitive + "s"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ require 'gamefic'
2
+ require 'gamefic/grammar'
3
+
4
+ module Gamefic::Grammar
5
+ class Verbs
6
+ extend Gamefic::Grammar::Conjugator::ClassMethods
7
+ def initialize obj
8
+ @pronoun = obj
9
+ self.class.conjugated_verbs.each_pair { |infinitive, verbset|
10
+ define_singleton_method infinitive do
11
+ verbset[:present].conjugate @pronoun
12
+ end
13
+ }
14
+ end
15
+ def method_missing infinitive, *args, &block
16
+ Gamefic::Grammar::VerbSet.new(infinitive, nil, *args).conjugate(@pronoun)
17
+ end
18
+ def [] infinitive
19
+ words = infinitive.split_words
20
+ Gamefic::Grammar::VerbSet.new(words[0], nil).conjugate(@pronoun) + (words.length > 1 ? ' ' + words[1..-1].join(' ') : '')
21
+ end
22
+ conjugate :be, :present, :am, :are, :is, :are
23
+ conjugate :have, :present, :have, :have, :has, :have
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require 'gamefic/grammar'
2
+ require 'gamefic/grammar/gender'
3
+
4
+ module Gamefic::Grammar
5
+ module WordAdapter
6
+ include Gender
7
+ include Person
8
+ include Plural
9
+ # @return [Gamefic::Grammar::Pronouns]
10
+ def pronoun
11
+ @pronoun ||= Grammar::Pronouns.new(self)
12
+ end
13
+ # @return [Gamefic::Grammar::Verbs]
14
+ def verb
15
+ @verb ||= Grammar::Verbs.new(self)
16
+ end
17
+ def contract words
18
+ @contractions ||= {
19
+ "I am" => "I'm",
20
+ "you are" => "you're",
21
+ "he is" => "he's",
22
+ "she is" => "she's",
23
+ "it is" => "it's",
24
+ "we are" => "we're",
25
+ "they are" => "they're",
26
+ "am not" => "am not",
27
+ "are not" => "aren't",
28
+ "is not" => "isn't",
29
+ "do not" => "don't",
30
+ "does not" => "doesn't"
31
+ }
32
+ src = pronoun.subj + " " + verb.send(words)
33
+ @contractions[src] || src
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Gamefic
2
+ module Grammar
3
+ autoload :Tense, 'gamefic/grammar/tense'
4
+ autoload :Pronouns, 'gamefic/grammar/pronouns'
5
+ autoload :Conjugator, 'gamefic/grammar/conjugator'
6
+ autoload :Verbs, 'gamefic/grammar/verbs'
7
+ autoload :VerbSet, 'gamefic/grammar/verb_set'
8
+ autoload :Person, 'gamefic/grammar/person'
9
+ autoload :Plural, 'gamefic/grammar/plural'
10
+ autoload :Gender, 'gamefic/grammar/gender'
11
+ autoload :WordAdapter, 'gamefic/grammar/word_adapter'
12
+ end
13
+ end
@@ -0,0 +1,53 @@
1
+ require 'rexml/document'
2
+
3
+ module Gamefic
4
+
5
+ module Html
6
+ def self.fix_ampersands(text)
7
+ codes = []
8
+ ENTITIES.keys.each { |e|
9
+ codes.push e[1..-1]
10
+ }
11
+ piped = codes.join('|')
12
+ re = Regexp.new("&(?!(#{piped}))")
13
+ text.gsub(re, '&\1')
14
+ end
15
+ def self.encode(text)
16
+ Gamefic::Html::ENTITIES.each { |k, v|
17
+ while text.include?(k)
18
+ text[v] = k
19
+ end
20
+ }
21
+ text
22
+ end
23
+ def self.decode(text)
24
+ Gamefic::Html::ENTITIES.each { |k, v|
25
+ while text.include?(k)
26
+ text[k] = v
27
+ end
28
+ }
29
+ text
30
+ end
31
+ def self.parse(code)
32
+ code = fix_ampersands(code).strip
33
+ last = nil
34
+ begin
35
+ doc = REXML::Document.new code
36
+ rescue REXML::ParseException => e
37
+ if e.source.buffer != last
38
+ if e.source.buffer[0,1] == '<'
39
+ code = code[0,(code.length - e.source.buffer.length)] + '&lt;' + e.source.buffer[1..-1]
40
+ last = e.source.buffer
41
+ retry
42
+ end
43
+ end
44
+ raise e
45
+ end
46
+ end
47
+ end
48
+
49
+ module Html
50
+ ENTITIES = { "&quot;" => "\"", "&amp;" => "&", "&lt;" => "<", "&gt;" => ">", "&nbsp;" => " ", "&iexcl;" => "¡", "&cent;" => "¢", "&pound;" => "£", "&curren;" => "¤", "&yen;" => "¥", "&brvbar;" => "¦", "&sect;" => "§", "&uml;" => "¨", "&copy;" => "©", "&ordf;" => "ª", "&laquo;" => "«", "&not;" => "¬", "&shy;" => "­", "&reg;" => "®", "&macr;" => "¯", "&deg;" => "°", "&plusmn;" => "±", "&sup2;" => "²", "&sup3;" => "³", "&acute;" => "´", "&micro;" => "µ", "&para;" => "¶", "&middot;" => "·", "&cedil;" => "¸", "&sup1;" => "¹", "&ordm;" => "º", "&raquo;" => "»", "&frac14;" => "¼", "&frac12;" => "½", "&frac34;" => "¾", "&iquest;" => "¿", "&Agrave;" => "À", "&Aacute;" => "Á", "&Acirc;" => "Â", "&Atilde;" => "Ã", "&Auml;" => "Ä", "&Aring;" => "Å", "&AElig;" => "Æ", "&Ccedil;" => "Ç", "&Egrave;" => "È", "&Eacute;" => "É", "&Ecirc;" => "Ê", "&Euml;" => "Ë", "&Igrave;" => "Ì", "&Iacute;" => "Í", "&Icirc;" => "Î", "&Iuml;" => "Ï", "&ETH;" => "Ð", "&Ntilde;" => "Ñ", "&Ograve;" => "Ò", "&Oacute;" => "Ó", "&Ocirc;" => "Ô", "&Otilde;" => "Õ", "&Ouml;" => "Ö", "&times;" => "×", "&Oslash;" => "Ø", "&Ugrave;" => "Ù", "&Uacute;" => "Ú", "&Ucirc;" => "Û", "&Uuml;" => "Ü", "&Yacute;" => "Ý", "&THORN;" => "Þ", "&szlig;" => "ß", "&agrave;" => "à", "&aacute;" => "á", "&acirc;" => "â", "&atilde;" => "ã", "&auml;" => "ä", "&aring;" => "å", "&aelig;" => "æ", "&ccedil;" => "ç", "&egrave;" => "è", "&eacute;" => "é", "&ecirc;" => "ê", "&euml;" => "ë", "&igrave;" => "ì", "&iacute;" => "í", "&icirc;" => "î", "&iuml;" => "ï", "&eth;" => "ð", "&ntilde;" => "ñ", "&ograve;" => "ò", "&oacute;" => "ó", "&ocirc;" => "ô", "&otilde;" => "õ", "&ouml;" => "ö", "&divide;" => "÷", "&oslash;" => "ø", "&ugrave;" => "ù", "&uacute;" => "ú", "&ucirc;" => "û", "&uuml;" => "ü", "&yacute;" => "ý", "&thorn;" => "þ", "&yuml;" => "ÿ", "&OElig;" => "Œ", "&oelig;" => "œ", "&Scaron;" => "Š", "&scaron;" => "š", "&Yuml;" => "Ÿ", "&fnof;" => "ƒ", "&circ;" => "ˆ", "&tilde;" => "˜", "&Alpha;" => "Α", "&Beta;" => "Β", "&Gamma;" => "Γ", "&Delta;" => "Δ", "&Epsilon;" => "Ε", "&Zeta;" => "Ζ", "&Eta;" => "Η", "&Theta;" => "Θ", "&Iota;" => "Ι", "&Kappa;" => "Κ", "&Lambda;" => "Λ", "&Mu;" => "Μ", "&Nu;" => "Ν", "&Xi;" => "Ξ", "&Omicron;" => "Ο", "&Pi;" => "Π", "&Rho;" => "Ρ", "&Sigma;" => "Σ", "&Tau;" => "Τ", "&Upsilon;" => "Υ", "&Phi;" => "Φ", "&Chi;" => "Χ", "&Psi;" => "Ψ", "&Omega;" => "Ω", "&alpha;" => "α", "&beta;" => "β", "&gamma;" => "γ", "&delta;" => "δ", "&epsilon;" => "ε", "&zeta;" => "ζ", "&eta;" => "η", "&theta;" => "θ", "&iota;" => "ι", "&kappa;" => "κ", "&lambda;" => "λ", "&mu;" => "μ", "&nu;" => "ν", "&xi;" => "ξ", "&omicron;" => "ο", "&pi;" => "π", "&rho;" => "ρ", "&sigmaf;" => "ς", "&sigma;" => "σ", "&tau;" => "τ", "&upsilon;" => "υ", "&phi;" => "φ", "&chi;" => "χ", "&psi;" => "ψ", "&omega;" => "ω", "&thetasym;" => "ϑ", "&upsih;" => "ϒ", "&piv;" => "ϖ", "&ensp;" => " ", "&emsp;" => " ", "&thinsp;" => " ", "&zwnj;" => "‌", "&zwj;" => "‍", "&lrm;" => "‎", "&rlm;" => "‏", "&ndash;" => "–", "&mdash;" => "—", "&lsquo;" => "‘", "&rsquo;" => "’", "&sbquo;" => "‚", "&ldquo;" => "“", "&rdquo;" => "”", "&bdquo;" => "„", "&dagger;" => "†", "&Dagger;" => "‡", "&bull;" => "•", "&hellip;" => "…", "&permil;" => "‰", "&prime;" => "′", "&Prime;" => "″", "&lsaquo;" => "‹", "&rsaquo;" => "›", "&oline;" => "‾", "&frasl;" => "⁄", "&euro;" => "€", "&image;" => "ℑ", "&weierp;" => "℘", "&real;" => "ℜ", "&trade;" => "™", "&alefsym;" => "ℵ", "&larr;" => "←", "&uarr;" => "↑", "&rarr;" => "→", "&darr;" => "↓", "&harr;" => "↔", "&crarr;" => "↵", "&lArr;" => "⇐", "&uArr;" => "⇑", "&rArr;" => "⇒", "&dArr;" => "⇓", "&hArr;" => "⇔", "&forall;" => "∀", "&part;" => "∂", "&exist;" => "∃", "&empty;" => "∅", "&nabla;" => "∇", "&isin;" => "∈", "&notin;" => "∉", "&ni;" => "∋", "&prod;" => "∏", "&sum;" => "∑", "&minus;" => "−", "&lowast;" => "∗", "&radic;" => "√", "&prop;" => "∝", "&infin;" => "∞", "&ang;" => "∠", "&and;" => "∧", "&or;" => "∨", "&cap;" => "∩", "&cup;" => "∪", "&int;" => "∫", "&there4;" => "∴", "&sim;" => "∼", "&cong;" => "≅", "&asymp;" => "≈", "&ne;" => "≠", "&equiv;" => "≡", "&le;" => "≤", "&ge;" => "≥", "&sub;" => "⊂", "&sup;" => "⊃", "&nsub;" => "⊄", "&sube;" => "⊆", "&supe;" => "⊇", "&oplus;" => "⊕", "&otimes;" => "⊗", "&perp;" => "⊥", "&sdot;" => "⋅", "&lceil;" => "⌈", "&rceil;" => "⌉", "&lfloor;" => "⌊", "&rfloor;" => "⌋", "&lang;" => "〈", "&rang;" => "〉", "&loz;" => "◊", "&spades;" => "♠", "&clubs;" => "♣", "&hearts;" => "♥", "&diams;" => "♦" }
51
+ end
52
+
53
+ end
@@ -2,41 +2,59 @@
2
2
 
3
3
  module Gamefic
4
4
 
5
- class Keywords < Array
6
- def initialize(statement = '')
7
- if statement.kind_of?(Keywords)
8
- self.concat statement
9
- else
5
+ class Keywords < Array
6
+ def initialize(statement = '')
7
+ if statement.kind_of?(Keywords)
8
+ self.concat statement
9
+ else
10
10
  if statement.kind_of?(Array)
11
11
  statement = statement.join(' ')
12
12
  end
13
- self.concat statement.to_s.gsub(/[^a-z0-9]/i, ' ').strip.downcase.split(' ')
14
- end
15
- self.delete_if { |w|
16
- w.length < 2 or w == 'an' or w == 'the'
17
- }
18
- self.uniq!
19
- end
20
- def found_in(other)
21
- matches = 0.0
22
- self.each { |my_word|
23
- if (other.include?(my_word))
24
- matches = matches + 1.0
25
- else
26
- other.each { |other_word|
27
- if my_word.length < other_word.length
28
- if other_word[0, my_word.length] == my_word
29
- matches = matches + (my_word.length.to_f / other_word.length.to_f)
30
- end
31
- end
32
- }
33
- end
34
- }
35
- return matches
36
- end
37
- def to_s
38
- self.join(' ')
39
- end
40
- end
13
+ self.concat statement.to_s.gsub(/[^a-z0-9]/i, ' ').strip.downcase.split(' ')
14
+ end
15
+ # TODO: This routine is stubbed to allow any combination of letters and
16
+ # numbers as a keyword. Since we're doing this, there's a distinct
17
+ # possibility that the Keywords class can be deprecated.
18
+ #self.delete_if { |w|
19
+ # w.length < 2 or w == 'an' or w == 'the'
20
+ #}
21
+ #self.uniq!
22
+ self
23
+ end
24
+ def found_in(other, fuzzy = false)
25
+ matches = 0.0
26
+ self.each { |my_word|
27
+ if other.include?(my_word)
28
+ matches = matches + 1.0
29
+ else
30
+ other.each { |other_word|
31
+ if my_word.length < other_word.length
32
+ if other_word[0, my_word.length] == my_word and my_word.length > 2
33
+ matches = matches + (my_word.length.to_f / other_word.length.to_f)
34
+ end
35
+ elsif fuzzy
36
+ fuzzy_word = my_word
37
+ if fuzzy_word.end_with?('ies')
38
+ fuzzy_word = fuzzy_word[0..-4]
39
+ elsif fuzzy_word.end_with?('ae')
40
+ fuzzy_word = fuzzy_word[0..-3]
41
+ elsif fuzzy_word.end_with?('s') or fuzzy_word.end_with?('i')
42
+ fuzzy_word = fuzzy_word[0..-2]
43
+ end
44
+ if other_word[0, fuzzy_word.length] == fuzzy_word and fuzzy_word.length > 2
45
+ matches = matches + (fuzzy_word.length.to_f / other_word.length.to_f)
46
+ elsif fuzzy_word[0, other_word.length] == other_word and other_word.length > 2
47
+ matches = matches + (fuzzy_word.length.to_f / other_word.length.to_f)
48
+ end
49
+ end
50
+ }
51
+ end
52
+ }
53
+ return matches
54
+ end
55
+ def to_s
56
+ self.join(' ')
57
+ end
58
+ end
41
59
 
42
60
  end