word_search 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +29 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +1166 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +5 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +61 -0
  11. data/Rakefile +14 -0
  12. data/bin/console +8 -0
  13. data/bin/coverage +1 -0
  14. data/bin/setup +6 -0
  15. data/lib/word_search/generator/base.rb +28 -0
  16. data/lib/word_search/generator.rb +60 -0
  17. data/lib/word_search/plane/base.rb +52 -0
  18. data/lib/word_search/plane.rb +22 -0
  19. data/lib/word_search/position_word/base.rb +98 -0
  20. data/lib/word_search/solver.rb +15 -0
  21. data/lib/word_search/three_dimensional/direction.rb +37 -0
  22. data/lib/word_search/three_dimensional/generator.rb +35 -0
  23. data/lib/word_search/three_dimensional/plane.rb +89 -0
  24. data/lib/word_search/three_dimensional/point.rb +15 -0
  25. data/lib/word_search/three_dimensional/position_word.rb +29 -0
  26. data/lib/word_search/two_dimensional/direction.rb +17 -0
  27. data/lib/word_search/two_dimensional/generator.rb +35 -0
  28. data/lib/word_search/two_dimensional/plane.rb +57 -0
  29. data/lib/word_search/two_dimensional/point.rb +14 -0
  30. data/lib/word_search/two_dimensional/position_word.rb +28 -0
  31. data/lib/word_search/version.rb +3 -0
  32. data/lib/word_search/word_bank.rb +45 -0
  33. data/lib/word_search.rb +30 -0
  34. data/vendor/cache/activemodel-5.0.0.1.gem +0 -0
  35. data/vendor/cache/activesupport-5.0.0.1.gem +0 -0
  36. data/vendor/cache/ast-2.2.0.gem +0 -0
  37. data/vendor/cache/codeclimate-test-reporter-0.6.0.gem +0 -0
  38. data/vendor/cache/coderay-1.1.1.gem +0 -0
  39. data/vendor/cache/concurrent-ruby-1.0.2.gem +0 -0
  40. data/vendor/cache/diff-lcs-1.2.5.gem +0 -0
  41. data/vendor/cache/docile-1.1.5.gem +0 -0
  42. data/vendor/cache/i18n-0.7.0.gem +0 -0
  43. data/vendor/cache/json-2.0.2.gem +0 -0
  44. data/vendor/cache/method_source-0.8.2.gem +0 -0
  45. data/vendor/cache/minitest-5.9.0.gem +0 -0
  46. data/vendor/cache/parser-2.3.1.2.gem +0 -0
  47. data/vendor/cache/powerpack-0.1.1.gem +0 -0
  48. data/vendor/cache/pry-0.10.4.gem +0 -0
  49. data/vendor/cache/rainbow-2.1.0.gem +0 -0
  50. data/vendor/cache/rake-10.5.0.gem +0 -0
  51. data/vendor/cache/rspec-3.5.0.gem +0 -0
  52. data/vendor/cache/rspec-core-3.5.2.gem +0 -0
  53. data/vendor/cache/rspec-expectations-3.5.0.gem +0 -0
  54. data/vendor/cache/rspec-mocks-3.5.0.gem +0 -0
  55. data/vendor/cache/rspec-support-3.5.0.gem +0 -0
  56. data/vendor/cache/rubocop-0.42.0.gem +0 -0
  57. data/vendor/cache/ruby-enum-0.5.0.gem +0 -0
  58. data/vendor/cache/ruby-progressbar-1.8.1.gem +0 -0
  59. data/vendor/cache/simplecov-0.12.0.gem +0 -0
  60. data/vendor/cache/simplecov-html-0.10.0.gem +0 -0
  61. data/vendor/cache/slop-3.6.0.gem +0 -0
  62. data/vendor/cache/thread_safe-0.3.5.gem +0 -0
  63. data/vendor/cache/tzinfo-1.2.2.gem +0 -0
  64. data/vendor/cache/unicode-display_width-1.0.5.gem +0 -0
  65. data/word_search.gemspec +35 -0
  66. metadata +248 -0
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ script:
5
+ - rake
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 npezza93
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # ![Word Search](https://raw.githubusercontent.com/google/material-design-icons/master/action/drawable-xxxhdpi/ic_search_black_18dp.png)Word Search Generator and Solver
2
+
3
+ [![Build Status](https://travis-ci.org/npezza93/word_search.svg?branch=master)](https://travis-ci.org/npezza93/word_search)
4
+ [![Code Climate](https://codeclimate.com/github/npezza93/word_search/badges/gpa.svg)](https://codeclimate.com/github/npezza93/word_search)
5
+ [![Test Coverage](https://codeclimate.com/github/npezza93/word_search/badges/coverage.svg)](https://codeclimate.com/github/npezza93/word_search/coverage)
6
+
7
+ ## Install
8
+ Add WordSearch to your `Gemfile` and `bundle install`:
9
+
10
+ `gem 'word_search'`
11
+
12
+ Alternatively, you can install the gem from [rubygems.org](https://rubygems.org/):
13
+
14
+ `gem install word_search`
15
+
16
+ ## Usage
17
+
18
+ To create a plane with just random letters in each position:
19
+
20
+ ```ruby
21
+ ❯ plane = WordSearch::Plane.new(5, 5)
22
+ ❯ plane.add_letters
23
+ # To traverse the cartesian plane:
24
+ ❯ plane[0][3]
25
+ => #<WordSearch::TwoDimensional::Point:0x007facf1d8d7e0 @letter="u", @x=0, @y=3>
26
+ ❯ plane.pto_s
27
+ nvqgy
28
+ uhsit
29
+ zqloh
30
+ muudd
31
+ himyj
32
+
33
+ # To print to a file(without a filename defaults to 'crossword')
34
+ ❯ plane.print(file_name)
35
+
36
+ # When printing a 3D crossword there are two spaces between z slices. The top slice is z = 0.
37
+ ❯ plane = WordSearch::Plane.new(3, 3, 2)
38
+ ❯ plane.add_letters
39
+ ❯ plane.pto_s
40
+ bxv
41
+ lud
42
+ agp
43
+
44
+ esj
45
+ era
46
+ utg
47
+ ```
48
+
49
+ To create plane filled with words supplied by a word bank:
50
+ ```ruby
51
+ ❯ generator = WordSearch::Generator.new('words.csv', 5, 5) # or add a z param to get a 3D word search
52
+ ❯ generator.perform
53
+ ❯ generator.word_bank
54
+ => ["word", "hello", "bye"]
55
+ ❯ generator.pto_s
56
+ ghsii
57
+ eelwt
58
+ ylcon
59
+ blarz
60
+ yoydt
61
+ ```
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ task :console do
6
+ require 'pry'
7
+ require 'word_searcher'
8
+ ARGV.clear
9
+ Pry.start
10
+ end
11
+
12
+ RuboCop::RakeTask.new
13
+ RSpec::Core::RakeTask.new(:spec)
14
+ task default: [:spec, :rubocop]
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'word_search'
5
+ require 'pry'
6
+ require 'benchmark'
7
+
8
+ Pry.start
data/bin/coverage ADDED
@@ -0,0 +1 @@
1
+ open coverage/index.html
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,28 @@
1
+ module WordSearch
2
+ class Generator
3
+ class Base
4
+ include ActiveModel::Validations
5
+
6
+ attr_accessor :plane, :word_bank, :used_coordinates
7
+ delegate :to_s, :pto_s, :print, to: :plane
8
+
9
+ def initialize(plane, word_bank)
10
+ @plane = plane
11
+ @word_bank = word_bank
12
+ @used_coordinates = []
13
+ end
14
+
15
+ def perform
16
+ word_bank.each do |word|
17
+ place_word(word)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def random(number)
24
+ SecureRandom.random_number number
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,60 @@
1
+ module WordSearch
2
+ class Generator < SimpleDelegator
3
+ include ActiveModel::Validations
4
+
5
+ validate :can_words_fit?
6
+ validate :valid_plane?
7
+ validate :valid_word_bank?
8
+
9
+ def initialize(file, x, y, z = nil)
10
+ plane = Plane.new(x, y, z)
11
+ obj =
12
+ if z.present?
13
+ ThreeDimensional::Generator.new(plane, WordBank.new(file))
14
+ else
15
+ TwoDimensional::Generator.new(plane, WordBank.new(file))
16
+ end
17
+
18
+ super obj
19
+ end
20
+
21
+ def perform
22
+ super
23
+
24
+ if valid?
25
+ plane.add_letters
26
+ plane
27
+ else
28
+ false
29
+ end
30
+ end
31
+
32
+ def object
33
+ __getobj__
34
+ end
35
+
36
+ private
37
+
38
+ def can_words_fit?
39
+ errors.add(:base, words_too_long) if plane.max < word_bank.longest_length
40
+ end
41
+
42
+ def words_too_long
43
+ "#{word_bank.longest_words.join(' and ')} "\
44
+ "#{'is'.pluralize(word_bank.longest_words.count)} "\
45
+ 'too long for the word search'
46
+ end
47
+
48
+ def valid_plane?
49
+ plane.errors.full_messages.each do |msg|
50
+ errors.add(:base, msg)
51
+ end unless plane.valid?
52
+ end
53
+
54
+ def valid_word_bank?
55
+ word_bank.errors.full_messages.each do |msg|
56
+ errors.add(:base, msg)
57
+ end unless word_bank.valid?
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,52 @@
1
+ module WordSearch
2
+ class Plane
3
+ class Base < Hash
4
+ include ActiveModel::Validations
5
+
6
+ attr_accessor :x, :y
7
+
8
+ validates :x, :y, numericality: { greater_than_or_equal_to: 2 }
9
+
10
+ def print(file_name = nil)
11
+ file = File.open(file_name || 'crossword', 'w')
12
+ file.write(to_s)
13
+ file
14
+ end
15
+
16
+ def random_letter
17
+ ('a'..'z').to_a[SecureRandom.random_number(26)]
18
+ end
19
+
20
+ def two_dimensional?
21
+ true
22
+ end
23
+
24
+ def three_dimensional?
25
+ false
26
+ end
27
+
28
+ def add_letters
29
+ x.times do |x_point|
30
+ y.times do |y_point|
31
+ yield(x_point, y_point)
32
+ end
33
+ end
34
+ end
35
+
36
+ def pto_s
37
+ puts to_s
38
+ end
39
+
40
+ private
41
+
42
+ def initialize_plane
43
+ x.times do |x_point|
44
+ self[x_point] = {}
45
+ y.times do |y_point|
46
+ yield(x_point, y_point)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ module WordSearch
2
+ class Plane < SimpleDelegator
3
+ def initialize(x, y, z = nil)
4
+ obj =
5
+ if z.present? && z > 1
6
+ ThreeDimensional::Plane.new(x, y, z)
7
+ else
8
+ TwoDimensional::Plane.new(x, y)
9
+ end
10
+
11
+ super obj
12
+ end
13
+
14
+ def to_s
15
+ if invalid?
16
+ errors.full_messages.join("\n")
17
+ else
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,98 @@
1
+ module WordSearch
2
+ class PositionWord
3
+ class Base
4
+ attr_accessor :plane, :word, :direction, :coordinate
5
+
6
+ def initialize(plane, word, direction, coordinate)
7
+ @plane = plane
8
+ @word = word
9
+ @direction = direction
10
+ @coordinate = coordinate
11
+ end
12
+
13
+ def perform
14
+ return false unless valid?
15
+
16
+ word.split('').each do |letter|
17
+ place_letter(letter)
18
+ update_coordinates
19
+ end
20
+ end
21
+
22
+ def valid?
23
+ valid_coordinates? && valid_letters?
24
+ end
25
+
26
+ private
27
+
28
+ def last_x
29
+ return @last_x if defined? @last_x
30
+
31
+ @last_x = coordinate.x
32
+ (word.length - 1).times do
33
+ @last_x += direction.x
34
+ end
35
+
36
+ @last_x
37
+ end
38
+
39
+ def last_y
40
+ return @last_y if defined? @last_y
41
+
42
+ @last_y = coordinate.y
43
+ (word.length - 1).times do
44
+ @last_y += direction.y
45
+ end
46
+
47
+ @last_y
48
+ end
49
+
50
+ def last_z
51
+ return @last_z if defined? @last_z
52
+
53
+ @last_z = coordinate.z
54
+ (word.length - 1).times do
55
+ @last_z += direction.z
56
+ end
57
+
58
+ @last_z
59
+ end
60
+
61
+ def valid_coordinates?
62
+ positive_last_coordinates? && last_coordinates_in_plane?
63
+ end
64
+
65
+ def valid_letters?
66
+ bad_overlap, intersection_points = false, 0
67
+
68
+ letters.count.times do |position|
69
+ next if letter_at(position).blank?
70
+
71
+ if letters[position] == letter_at(position)
72
+ intersection_points += 1
73
+ else
74
+ bad_overlap = true
75
+ end
76
+ end
77
+
78
+ !bad_overlap && intersection_points < 2
79
+ end
80
+
81
+ def letters
82
+ @letters ||= word.split('')
83
+ end
84
+
85
+ def x_at(position)
86
+ coordinate.x + position * direction.x
87
+ end
88
+
89
+ def y_at(position)
90
+ coordinate.y + position * direction.y
91
+ end
92
+
93
+ def z_at(position)
94
+ coordinate.z + position * direction.z
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,15 @@
1
+ module WordSearch
2
+ class Solver
3
+ attr_accessor :script, :word_bank, :plane
4
+
5
+ def initialize(script, word_list_file, plane_file)
6
+ @script = script
7
+ @word_bank = WordBank.new(word_list_file)
8
+ @plane = TwoDimensional::Plane.make_from_file(plane_file)
9
+ end
10
+
11
+ def execute
12
+ load(script, true)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ module WordSearch
2
+ module ThreeDimensional
3
+ class Direction
4
+ include Ruby::Enum
5
+
6
+ # Standard cardinal directions
7
+ define :N, [0, 1, 0]
8
+ define :NE, [1, 1, 0]
9
+ define :E, [1, 0, 0]
10
+ define :SE, [1, -1, 0]
11
+ define :S, [0, -1, 0]
12
+ define :SW, [-1, -1, 0]
13
+ define :W, [-1, 0, 0]
14
+ define :NW, [-1, 1, 0]
15
+
16
+ # cardinal directions with a positive z index (forward)
17
+ define :NF, [0, 1, 1]
18
+ define :NEF, [1, 1, 1]
19
+ define :EF, [1, 0, 1]
20
+ define :SEF, [1, -1, 1]
21
+ define :SF, [0, -1, 1]
22
+ define :SWF, [-1, -1, 1]
23
+ define :WF, [-1, 0, 1]
24
+ define :NWF, [-1, 1, 1]
25
+
26
+ # cardinal directions with a negative z index (back)
27
+ define :NB, [0, 1, -1]
28
+ define :NEB, [1, 1, -1]
29
+ define :EB, [1, 0, -1]
30
+ define :SEB, [1, -1, -1]
31
+ define :SB, [0, -1, -1]
32
+ define :SWB, [-1, -1, -1]
33
+ define :WB, [-1, 0, -1]
34
+ define :NWB, [-1, 1, -1]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,35 @@
1
+ module WordSearch
2
+ module ThreeDimensional
3
+ class Generator < Generator::Base
4
+ def directions
5
+ Direction.values.shuffle.map do |direction|
6
+ Point.new(direction.first, direction.second, direction.third)
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def place_word(word)
13
+ placed = false
14
+ until placed || used_coordinates.uniq.count == plane.total_points
15
+ placed = position_word(word).present?
16
+ end
17
+
18
+ word_bank.errors.add(word, 'cannot be placed') if placed.blank?
19
+ placed
20
+ end
21
+
22
+ def position_word(word)
23
+ used_coordinates << (coordinate = random_point)
24
+
25
+ directions.find do |direction|
26
+ PositionWord.new(plane, word, direction, coordinate).perform
27
+ end
28
+ end
29
+
30
+ def random_point
31
+ Point.new(random(plane.x), random(plane.y), random(plane.z))
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,89 @@
1
+ module WordSearch
2
+ module ThreeDimensional
3
+ class Plane < Plane::Base
4
+ attr_accessor :z
5
+ validates :z, numericality: { greater_than_or_equal_to: 1 }
6
+
7
+ def initialize(x, y, z)
8
+ @x, @y, @z = x, y, z
9
+
10
+ initialize_plane do |x_point, y_point|
11
+ self[x_point][y_point] = {}
12
+ z.times do |z_point|
13
+ self[x_point][y_point][z_point] =
14
+ Point.new(x_point, y_point, z_point)
15
+ end
16
+ end
17
+ end
18
+
19
+ def to_s
20
+ (0..(z - 1)).map do |z_slice|
21
+ values.map do |row|
22
+ row.values.map { |ys| ys[z_slice] }.map(&:to_s)
23
+ end.transpose.reverse.map(&:join).join("\n")
24
+ end.join("\n\n")
25
+ end
26
+
27
+ def two_dimensional?
28
+ false
29
+ end
30
+
31
+ def three_dimensional?
32
+ true
33
+ end
34
+
35
+ def total_points
36
+ x * y * z
37
+ end
38
+
39
+ def max
40
+ [x, y, z].max
41
+ end
42
+
43
+ def add_letters
44
+ super do |x_point, y_point|
45
+ z.times do |z_point|
46
+ self[x_point][y_point][z_point].letter ||= random_letter
47
+ end
48
+ end
49
+ end
50
+
51
+ class << self
52
+ def make_from_file(file)
53
+ string = File.read(file).split("\n\n").map(&:split)
54
+
55
+ return false unless valid_file?(string)
56
+
57
+ make_word_search(string)
58
+ end
59
+
60
+ private
61
+
62
+ def valid_file?(string)
63
+ string.collect(&:length).uniq.count == 1 &&
64
+ string.flat_map { |row| row.map(&:length) }.uniq.count == 1
65
+ end
66
+
67
+ def make_word_search(string)
68
+ plane = empty_3d_plane_from_string(string)
69
+
70
+ string.each_with_index do |slice, z|
71
+ slice.reverse.each_with_index do |row, y|
72
+ row.split('').each_with_index do |letter, x|
73
+ plane[x][y][z] = Point.new(x, y, z, letter)
74
+ end
75
+ end
76
+ end
77
+
78
+ plane
79
+ end
80
+
81
+ def empty_3d_plane_from_string(string)
82
+ x = string.flat_map { |row| row.map(&:length) }.uniq.first
83
+ y = string.collect(&:length).uniq.first
84
+ new(x, y, string.count)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,15 @@
1
+ module WordSearch
2
+ module ThreeDimensional
3
+ class Point
4
+ attr_accessor :x, :y, :z, :letter
5
+ alias to_s letter
6
+
7
+ def initialize(x, y, z, letter = nil)
8
+ @x = x
9
+ @y = y
10
+ @z = z
11
+ @letter = letter if letter
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ module WordSearch
2
+ module ThreeDimensional
3
+ class PositionWord < PositionWord::Base
4
+ private
5
+
6
+ def place_letter(letter)
7
+ plane[coordinate.x][coordinate.y][coordinate.z].letter = letter
8
+ end
9
+
10
+ def update_coordinates
11
+ coordinate.x += direction.x
12
+ coordinate.y += direction.y
13
+ coordinate.z += direction.z
14
+ end
15
+
16
+ def positive_last_coordinates?
17
+ last_x >= 0 && last_y >= 0 && last_z >= 0
18
+ end
19
+
20
+ def last_coordinates_in_plane?
21
+ last_x < plane.x && last_y < plane.y && last_z < plane.z
22
+ end
23
+
24
+ def letter_at(position)
25
+ plane.dig(x_at(position), y_at(position), z_at(position)).letter
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ module WordSearch
2
+ module TwoDimensional
3
+ class Direction
4
+ include Ruby::Enum
5
+
6
+ # Standard cardinal directions
7
+ define :N, [0, 1]
8
+ define :NE, [1, 1]
9
+ define :E, [1, 0]
10
+ define :SE, [1, -1]
11
+ define :S, [0, -1]
12
+ define :SW, [-1, -1]
13
+ define :W, [-1, 0]
14
+ define :NW, [-1, 1]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module WordSearch
2
+ module TwoDimensional
3
+ class Generator < Generator::Base
4
+ def directions
5
+ Direction.values.shuffle.map do |direction|
6
+ Point.new(direction.first, direction.second)
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def place_word(word)
13
+ placed = false
14
+ until placed || used_coordinates.uniq.count == plane.total_points
15
+ placed = position_word(word).present?
16
+ end
17
+
18
+ word_bank.errors.add(word, 'cannot be placed') if placed.blank?
19
+ placed
20
+ end
21
+
22
+ def position_word(word)
23
+ used_coordinates << (coordinate = random_point)
24
+
25
+ directions.find do |direction|
26
+ PositionWord.new(plane, word, direction, coordinate).perform
27
+ end
28
+ end
29
+
30
+ def random_point
31
+ Point.new(random(plane.x), random(plane.y))
32
+ end
33
+ end
34
+ end
35
+ end