Class: BoxesService

Inherits:
Object
  • Object
show all
Defined in:
app/services/boxes_service.rb

Class Method Summary collapse

Class Method Details

.find_paths(remaining_letters, last_word = nil, curr_path = [], depth = 0) ⇒ nil

Find a sequence of words that contain all remaining letters according to Letter Boxed rules

Parameters:

  • remaining_letters (Array<String>)

    letters left to be used

  • last (String)

    word in the current sequence (if any)

  • curr_path (Array<String>) (defaults to: [])

    currrent sequence of words

  • depth (Integer) (defaults to: 0)

    current depth

Returns:

  • (nil)


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'app/services/boxes_service.rb', line 62

def self.find_paths(remaining_letters, last_word = nil, curr_path = [], depth = 0)
    if remaining_letters.empty? and not @valid_paths.include? curr_path
        @valid_paths << curr_path
    end

    if @valid_paths.length >= @num_of_paths
        false
    else
        if depth < @max_depth
            if last_word.nil?
                words = @possible_words.values.flatten.select { |w| not curr_path.include? w }
            else
                words = @possible_words[last_word.last].select { |w| not curr_path.include? w }
            end
            words.sort_by { |w| (remaining_letters-w.chars.uniq).length }
                            .each do |word|
                still_searching = find_paths(remaining_letters - word.chars.uniq, word, curr_path+[ word ], depth + 1)
                return if not still_searching
            end
        end
        true
    end
end

.get_lettersArray<String>

Generates 12 random letters for Letter Boxed with at least 3 vocals

Returns:

  • (Array<String>)

    12 letters



88
89
90
91
92
93
94
95
96
97
# File 'app/services/boxes_service.rb', line 88

def self.get_letters
    alphabet = ("a".."z").to_a
    letters = alphabet.shuffle[0, 12]

    while ([ "a", "e", "i", "o", "u" ]-letters).length > 2
        letters = alphabet.shuffle[0, 12]
    end

    letters
end

.iterative_path_search(letters, n_paths = 3) ⇒ Array<Array<String>>

Find a number of word sequences less where each sequence is less than 6 words long and contains all letters

Parameters:

  • letters (Array<String>)

    that can be used

  • n_paths (Integer) (defaults to: 3)

    the number of paths that should be found

Returns:

  • (Array<Array<String>>)

    the paths found



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'app/services/boxes_service.rb', line 28

def self.iterative_path_search(letters, n_paths = 3)
    @valid_paths = []
    @max_depth = 2
    @possible_words = {}
    @num_of_paths = n_paths
    patterns = [ letters[0..2], letters[3..5], letters[6..8], letters[9..11] ]
    letters.each_with_index do |l, i|
        possible_letters = letters.map(&:clone)
        possible_letters.slice!(3*(i/3), 3)
        possible_letters.insert(0, l)
        words = WordsService.words(possible_letters.join, true)
        patterns.each do |p|
            words = words.select { |w| not w.match(/[#{p}][#{p}]+/) }
        end

        return @valid_paths if words.empty?

        @possible_words[l] = words
    end
    while @max_depth < 6 and @valid_paths.length < @num_of_paths
        find_paths(letters, letters)
        @max_depth += 1
    end

    @valid_paths
end

.set_day_box(date = Date.today) ⇒ Object

Sets the puzzle for a given day



13
14
15
16
17
18
19
20
21
# File 'app/services/boxes_service.rb', line 13

def self.set_day_box(date = Date.today)
    while LetterBox.find_by(play_date: date).nil?
        letters = get_letters()

        if iterative_path_search(letters).length >= 3
            LetterBox.create(letters: letters.join, play_date: date)
        end
    end
end

.set_week_boxesObject

Sets the puzzles for the next week



3
4
5
6
7
8
9
10
# File 'app/services/boxes_service.rb', line 3

def self.set_week_boxes
    tomorrow = Date.tomorrow
    boxes = LetterBox.where(play_date: tomorrow...tomorrow + 7).order(:play_date)
    play_date = boxes.any? ? boxes.maximum(:play_date) : tomorrow
    (play_date..tomorrow + 6).each do |date|
        self.set_day_box(date)
    end
end