RosettaCodeData/Task/Honeycombs/Ruby/honeycombs.rb

136 lines
3.8 KiB
Ruby

Shoes.app(title: "Honeycombs", height: 700, width: 700) do
C = Math::cos(Math::PI/3)
S = Math::sin(Math::PI/3)
Radius = 60.0
letters = [
%w[L A R N D 1 2],
%w[G U I Y T 3 4],
%w[P C F E B 5 6],
%w[V S O M K 7 8],
%w[Q X J Z H 9 0],
]
def highlight(hexagon)
hexagon.style(fill: magenta)
end
def unhighlight(hexagon)
hexagon.style(fill: yellow)
end
def choose(hexagon)
hexagon.choose
highlight hexagon
chosen = @hexagons.find_all {|h| h.chosen?}.map {|h| h.letter}
if chosen.size == @hexagons.size
@chosen.text = 'Every hexagon has been chosen.'
else
@chosen.text = "Chosen: #{chosen.sort.join(',')}\n" +
"Last Chosen: #{hexagon.letter}"
end
end
width = 20 + (Radius*(7*letters[0].size - 3)/4.0).ceil
height = 60 + (Radius*(1 + 2*S*letters.size)).ceil
@hexagons = []
letter_to_hex = {}
# create the GUI
stack(height: height, width: width) do
@chosen = para("Chosen:\nLast chosen:")
# draw the hexagrams
letters.each_index do |row|
letters[0].each_index do |column|
x = 60 + column * Radius * 0.75 + (1-S) * Radius
y = 80 + row * S * Radius + (column.odd? ? S * Radius * 0.5 : 0)
h = shape(x-Radius, y-S*Radius) do
strokewidth 3
move_to(x-C*Radius, y-S*Radius)
line_to(x+C*Radius, y-S*Radius)
line_to(x+Radius, y)
line_to(x+C*Radius, y+S*Radius)
line_to(x-C*Radius, y+S*Radius)
line_to(x-Radius, y)
line_to(x-C*Radius, y-S*Radius)
end
# add some attributes and methods to the shape
class << h
attr_accessor :x, :y, :state, :letter
def chosen?
not @state.nil?
end
def choose
@state = :chosen
end
def contains?(px, py)
if @x-Radius < px and px <= @x-C*Radius
ratio = (px - @x + Radius)/(Radius*(1-C))
@y - ratio*S*Radius < py and py <= @y + ratio*S*Radius
elsif @x-C*Radius < px and px <= @x+C*Radius
@y - S*Radius < py and py < @y + S*Radius
elsif @x+C*Radius < px and px <= @x+Radius
ratio = (@x + Radius - px)/(Radius*(1-C))
@y - ratio*S*Radius < py and py <= @y + ratio*S*Radius
else
false
end
end
def inspect
%q(<%s,"%s",%s,%d@%d>) % [self.class, letter, chosen?, x, y]
end
end
h.x = x + x - Radius
h.y = y + y - S*Radius
h.letter = letters[row][column]
unhighlight h
@hexagons << h
letter_to_hex[h.letter.downcase] = h
letter_to_hex[h.letter.upcase] = h
# add the letter to the hexagon
para(h.letter).style(size:56, stroke:red) \
.move(h.x - C*Radius, h.y - S*Radius)
end
end
# highlight the hexagon under the mouse
hex_over = nil
motion do |x, y|
hex = @hexagons.find {|h| h.contains?(x,y)}
unless hex.nil? or hex.chosen?
highlight hex
end
unless hex_over == hex or hex_over.nil? or hex_over.chosen?
unhighlight hex_over
end
hex_over = hex
end
# handle mouse clicks
click do |button, x, y|
info("button #{button} clicked at (#{x}, #{y})")
hexagon = @hexagons.find {|h| h.contains?(x,y)}
if hexagon
info("clicked hexagon #{hexagon}")
choose hexagon
end
end
# handle keystrokes
keypress do |key|
if key == "\x11" # control-Q
exit
elsif key == "?"
info @hexagons.collect {|h| h.inspect}.join("\n")
elsif letter_to_hex.has_key?(key)
info("pressed key #{key} -> #{letter_to_hex[key]}")
choose letter_to_hex[key]
end
end
end
end