Skip to content

Instantly share code, notes, and snippets.

@silverhammermba
Last active May 23, 2022 17:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save silverhammermba/8805653 to your computer and use it in GitHub Desktop.
Save silverhammermba/8805653 to your computer and use it in GitHub Desktop.
Generates word searches with only a single word to find, but every letter in the grid is in the word.
#!/usr/bin/env ruby
# terrible word search generator
# inspired by http://cnlohr.blogspot.com/2014/02/to-make-terrible-wordsearches.html
if ARGV.length != 3
STDERR.puts "usage: #$0 WIDTH HEIGHT WORD"
exit 1
end
$word = ARGV[2].upcase
# grid must be large enough to fit it
$width = [ARGV[0].to_i, $word.length].max
$height = [ARGV[1].to_i, $word.length].max
letters = $word.chars.uniq
# make sure $grid has one occurrence of $word, try to fix otherwise
def check_grid
# did we get lucky?
solutions = find_occurrences
return solutions.first if solutions.size == 1
row = rand($height - $word.length + 1)
col = rand($width - $word.length + 1)
dirr = 1
dirc = 1
# possibly reverse
if rand < 0.5
row = $height - row - 1
dirr = -1
end
if rand < 0.5
col = $width - col - 1
dirc = -1
end
case rand 3
when 0 # horizontal
row = rand($height)
dirr = 0
when 1 # vertical
col = rand($width)
dirc = 0
when 2 # diagonal
# nothing to do
end
$word.length.times do |i|
$grid[row + i * dirr][col + i * dirc] = $word[i]
end
# make sure we didn't add too many
solutions = find_occurrences
return solutions.first if solutions.size == 1
nil
end
def find_occurrences
occurrences = []
# horizontal
$grid.each_with_index do |row, r|
(0..($width - $word.length)).each do |c|
horz = row[c...(c + $word.length)].join
occurrences << [r, c, ?h] if $word == horz or $word == horz.reverse
end
end
# vertical
(0..($height - $word.length)).each do |r|
(0...$width).each do |c|
vert = (r...(r + $word.length)).map { |i| $grid[i][c] }.join
occurrences << [r, c, ?v] if $word == vert or $word == vert.reverse
end
end
# diagonal
(0..($height - $word.length)).each do |r|
(0..($width - $word.length)).each do |c|
diag = (0...($word.length)).map { |i| $grid[r + i][c + i] }.join
occurrences << [r, c, 'dd'] if $word == diag or $word == diag.reverse
diag = (0...($word.length)).map { |i| $grid[r + $word.length - i - 1][c + i] }.join
occurrences << [r + $word.length - 1, c, 'du'] if $word == diag or $word == diag.reverse
end
end
occurrences
end
solution = nil
$grid = Array.new($height) { Array.new($width) { letters.sample } }
until solution = check_grid
$grid = Array.new($height) { Array.new($width) { letters.sample } }
end
$grid.each { |row| puts row.join(' '); puts }
puts solution.join(?,)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment