Skip to content

Commit

Permalink
Merge pull request #2 from briandowns/add-ruby
Browse files Browse the repository at this point in the history
Add Ruby
  • Loading branch information
briandowns authored Jun 13, 2019
2 parents 8ba8c00 + 7f46437 commit 5a92abc
Show file tree
Hide file tree
Showing 5 changed files with 364 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ $ super-hacker -b 16
- Java
- Javascript
- Rockstar
- Ruby

## Installation

Expand Down
83 changes: 83 additions & 0 deletions templates/ruby/btree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package ruby

// https://github.com/seifertd/Ruby-BTree

const Btree = `
Copyright (c) 2010,2011 Douglas A. Seifert
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# :main: README.md
module Btree
# :stopdoc:
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
# :startdoc:
# Returns the version string for the library.
#
def self.version
@version ||= File.read(path('version.txt')).strip
end
# Returns the library path for the module. If any arguments are given,
# they will be joined to the end of the libray path using
# <tt>File.join</tt>.
#
def self.libpath( *args, &block )
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
if block
begin
$LOAD_PATH.unshift LIBPATH
rv = block.call
ensure
$LOAD_PATH.shift
end
end
return rv
end
# Returns the lpath for the module. If any arguments are given,
# they will be joined to the end of the path using
# <tt>File.join</tt>.
#
def self.path( *args, &block )
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
if block
begin
$LOAD_PATH.unshift PATH
rv = block.call
ensure
$LOAD_PATH.shift
end
end
return rv
end
# Utility method used to require all files ending in .rb that lie in the
# directory below this file that has the same name as the filename passed
# in. Optionally, a specific _directory_ name can be passed in such that
# the _filename_ does not have to be equivalent to the directory.
#
def self.require_all_libs_relative_to( fname, dir = nil )
dir ||= ::File.basename(fname, '.*')
search_me = ::File.expand_path(
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
Dir.glob(search_me).sort.each {|rb| require rb}
end
def self.create(degree)
raise "Degree of Btree must be >= 2" if degree < 2
return Btree::Tree.new(degree)
end
end # module Btree
Btree.require_all_libs_relative_to(__FILE__)
`
55 changes: 55 additions & 0 deletions templates/ruby/eightbitadder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ruby

// http://sandbox.mc.edu/~bennet/ruby/code/ctest3_rb.html

const EightBitAdder = `
#
# This is a one-bit adder.
#
require "csim"
require "cgrp"
require "oba"
NumberOut.shush
# Blueprint for a the one-bit adder
bp = OBA.new
# Two input senders, and the output device.
na = SwitchBank.new
nb = SwitchBank.new
disp = NumberOut.new(" Sum")
# We're going to build an 8-bit adder
prev = nil
8.times do
# Create the one-bit adder and join the data inputs and outputs.
addr = bp.another
na.join(addr)
nb.join(addr)
addr.join(disp)
# Chain the carry, if this isn't he first one.
if prev then
prev.join(addr)
end
prev = addr
end
# Overflow light.
prev.join(LED.new(" Oflow"))
NumberOut.shush(false)
30.times do
a = rand(256)
b = rand(256)
print a, " + ", b, ":\n"
Gate.activate
na.value = a
nb.value = b
Gate.deactivate
end
`
215 changes: 215 additions & 0 deletions templates/ruby/reflextest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package ruby

// http://sandbox.mc.edu/~bennet/ruby/code/blink_rb.html

const ReflexTest = `
#!/usr/bin/ruby
# Import the library.
require 'tk'
# Parameters.
Width = 5 # Width of button grid.
Height = 5 # Height of button grid.
MinWait = 200 # Smallest button change wait (ms)
MaxWait = 1400 # Largest button change wait (ms)
InitWait = 800 # Initial button change wait (ms)
LossRate = 2000 # Frequency to take away points.
# Set defaults. Some we keep in constants to use later.
BG = '#ccffcc'
TkOption.add('*background', BG)
TkOption.add('*activeBackground', '#ddffdd')
FG = '#006600'
TkOption.add('*foreground', FG)
TkOption.add('*activeForeground', FG)
TkOption.add('*troughColor', '#99dd99')
# Root window.
root = TkRoot.new('background' => BG) { title 'Click Fast' }
# Button from the panel
class PanelButton < TkButton
private
# Exchange colors on the button.
def cswap
for p in [['background', 'foreground'],
['activebackground', 'activeforeground']]
c = cget(p[0])
configure(p[0] => cget(p[1]))
configure(p[1] => c)
end
end
public
# Initialize the button within the widget sup, at position pos (zero-based)
# with the number num. When pressed, send the score (+ or -) to cmd.
# Scorekeeper is an object which implements an up and down methods to
# receive score changes.
def initialize(sup, pos, num, scorekeeper)
super(sup, 'text' => num.to_s, 'command' => proc { self.pushed },
'activeforeground' => '#990000', 'activebackground' => '#ffdddd')
grid('row' => pos / Width + 1, 'column' => pos % Width, 'sticky' => 'news')
@active = false
@scorekeeper = scorekeeper
end
attr_reader :active
# Activate or deactivate the button.
def activate
if not @active
cswap
@active = true
end
end
def deactivate
if @active
cswap
@active = false
end
end
# When pushed, send our number, or negative our number, to the scorekeeping
# command.
def pushed
n = self.cget('text').to_i
if @active
@scorekeeper.up(n)
else
@scorekeeper.down(n)
end
end
end
# This class calls reduces the score at the indicated time rate.
class ScoreTimer
# This object will call scorekeeper.down(step) each rate ms.
def initialize(scorekeeper, rate = 500, step = 1)
@scorekeeper = scorekeeper
@rate = rate
@step = step
Tk.after(rate, proc { self.change })
end
# Reduce the score periodically
def change
@scorekeeper.down(@step)
Tk.after(@rate, proc { self.change })
end
end
# This is a box displaying a count-up timer in minutes and seconds to tenths
# m:ss.d
class TimeCounter < TkLabel
# Initialize. Displays zero and starts the ticking event.
def initialize(root)
super(root, "text" => '0:00.0', 'anchor' => 'e')
@count = 0
Tk.after(100, proc { self.change })
end
# One clock tick (tenths of a second). Increment the counter, then build
# the new display value.
def change
@count += 1
self.configure('text' =>
sprintf("%d:%02d.%d",
@count / 600, (@count / 10) % 60, @count % 10))
Tk.after(100, proc { self.change })
end
end
# This is the main application GUI.
class App
private
# Set the score value.
def setscore(val)
color = if val < 0 then 'red' else FG end
@slab.configure('text' => val.to_s, 'foreground' => color)
end
public
# The wait attribute is the amount of time (ms) between button changes.
attr_writer :wait
# Initialize it and have the applicate drawn in the root window.
def initialize(root)
# This is the label containing the score. Initially zero.
@slab = TkLabel.new(root) {
text "0"
anchor 'e'
grid('row' => 0, 'column' => 0, 'columnspan' => Width / 2,
'sticky' => 'w')
}
# This is the timer window at upper right.
TimeCounter.new(root).
grid('row' => 0, 'column' => Width/2, 'columnspan' => (Width+1)/2,
'sticky' => 'e')
# Create the buttons. First, make an array of numbers from 1 to the
# number of buttons, then create the buttons, each labelled with a
# number chosen at random from the list, so thare are no repeats.
nums = (1..Height*Width).to_a;
@buts= [ ]
for n in (0...Height*Width)
pos = rand(nums.length)
@buts.push(PanelButton.new(root, n, nums[pos], self))
nums.delete_at(pos)
end
# This creates the slider to adjust the speed of the game. The proc is
# called whenever the slider changes, and is sent the new setting.
scale = TkScale.new('command' => proc { |v| self.wait = v.to_i } ) {
orient "horizontal" # Which way the slider goes.
from MinWait # Value of smallest setting
to MaxWait # Value of largest setting
showvalue false # Don't show the numeric value of the setting.
grid('row' => Height + 1, 'column' => 1, 'columnspan' => Width - 2,
'sticky' => 'news')
}
scale.set(InitWait)
# Labels by the slider.
TkLabel.new {
text "Fast"
anchor "w"
grid("row" => Height + 1, 'column' => 0, 'sticky' => 'w')
}
TkLabel.new {
text "Slow"
anchor "e"
grid("row" => Height + 1, 'column' => Width-1, 'sticky' => 'e')
}
@wait = InitWait
# Decrement the score every LossRate period.
@timer = ScoreTimer.new(self, LossRate)
self.change
end
# Actions to increase or decrease the score.
def up(delta)
setscore(@slab.cget('text').to_i + delta)
end
def down(delta)
setscore(@slab.cget('text').to_i - delta)
end
# Change (or set, if none is yet set) the active button. It deactivates
# the button in @buts[0], It then chooses some other button at random,
# activates that and swaps it into position 0.
def change
@buts[0].deactivate
pos = rand(@buts.length - 1) + 1
@buts[0], @buts[pos] = @buts[pos], @buts[0]
@buts[0].activate
Tk.after(@wait, proc { self.change })
end
end
a = App.new(root)
Tk.mainloop
`
10 changes: 10 additions & 0 deletions templates/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/briandowns/super-hacker/templates/javascript"
"github.com/briandowns/super-hacker/templates/python"
"github.com/briandowns/super-hacker/templates/rockstar"
"github.com/briandowns/super-hacker/templates/ruby"
"github.com/briandowns/super-hacker/templates/scala"
)

Expand Down Expand Up @@ -81,6 +82,13 @@ var rockstarTemplates = []string{
rockstar.NinetyNineBottles,
}

// rubyTemplates holds all active Rockstar templates.
var rubyTemplates = []string{
ruby.Btree,
ruby.EightBitAdder,
ruby.ReflexTest,
}

// Random selects a template from the template slice
// at random and returns it to the caller.
func Random(lang string) (string, error) {
Expand All @@ -101,6 +109,8 @@ func Random(lang string) (string, error) {
return javascriptTemplates[rand.Intn(len(javascriptTemplates))], nil
case "rockstar":
return rockstarTemplates[rand.Intn(len(rockstarTemplates))], nil
case "ruby":
return rubyTemplates[rand.Intn(len(rubyTemplates))], nil
default:
return "", errors.New("unsupported language")
}
Expand Down

0 comments on commit 5a92abc

Please sign in to comment.