- 履歴一覧
- 履歴 を表示
- プログラミング言語/Ruby/初心者用課題解答例 は削除されています。
#contents
*初心者用課題 Ruby版 [#z0839d58]
問題の詳細については
[[初心者用課題]]を参照。
*素数判定 [#u543d3a3]
ま さ に 外 道(I)
require 'mathn.rb'
class PrimePredicater
def initialize
@prime = Prime.new
@cache = []
end
def prime?(x)
extend_cache x if @cache.empty? || x > @cache.last
@cache.include? x
end
private
def extend_cache(lim)
@prime.each do |x|
break if x > lim
@cache.push x
end
end
end
#使用例
ppred = PrimePredicater.new
[1, 10, 2, 5, 7].each do |x|
p ppred.prime?(x)
end
*素数を求める [#e48df6ac]
ま さ に 外 道(II)
require 'mathn.rb'
def primes(lim)
prms = []
prime = Prime.new
prime.each do |x|
break if x > lim
prms.push x
end
prms
end
puts primes(100).join(" ")
*うるう年測定 [#r3e10171]
require 'readline'
module LeapYearPredicater
LEAP_YEAR_JUDGE_TABLE = [
[
[true, false],
[true, true]
],
[
[],
[]
]
]
def leap_year?(y)
f, h, fh = [4, 100, 400].collect{|x| (y % x).zero? ? 0 : 1 }
LEAP_YEAR_JUDGE_TABLE[f][h][fh] or false
end
module_function :leap_year?
end
def recept_input
while buffer = Readline.readline("Year? > ", true)
yield buffer
end
end
recept_input do |line|
y = line.to_i
if y >= 0
puts "#{y}: #{LeapYearPredicater.leap_year?(y)}"
else
puts "#{y}: invalid year."
end
end
*ハノイの塔 [#r9efcc5f]
#Usage: ruby hanoi.rb [n number of disc]
=begin
= Hanoiクラス
「ハノイの塔」の問題を解くクラス。
== クラスメソッド
--- Hanoi.new(num, :from => "From", :to => "To", :work => "Work")
Hanoiクラスを生成する。numは積まれている円盤の枚数。
fromなどのキーワード引数(もどき)はnumの後に書く必要がある。
問題に使用する円盤を差す棒の名前。
== インスタンスメソッド
--- height
--- from
--- to
--- work
それぞれ、new時に与えた問題の設定を参照する。heightは初めにfromに
積まれている円盤の数。
--- each{|n, from, to| ... }
再帰的に問題を解いている様子を一回ずつ監視する。
nは動かす円盤の番号、それをfromからtoへと動かしている。
円盤nとはn番目に小さい円盤のこと。
=end
class Hanoi
def initialize(n, h)
@height = n
@from = h[:from] || "From"
@to = h[:to] || "To"
@work = h[:work] || "Work"
end
attr_reader :height, :from, :to, :work
def each(&block)
do_hanoi @height, @from, @to, @work, &block
end
private
def do_hanoi(n, from, to, work, &block)
if n == 1
yield n, from, to
else
do_hanoi n - 1, from, work, to, &block
yield n, from, to
do_hanoi n - 1, work, to, from, &block
end
end
end
##使用例
num = (ARGV[0] || 3).to_i
num >= 0 or raise "#{num}: Invalid Number"
hanoi = Hanoi.new(num, :from => "A", :to => "B", :work => "C")
hanoi.each do |n, from, to|
puts "#{n}: #{from} -> #{to}"
end
*転置行列 [#o1ceec0c]
require 'matrix'
def parse_matrix(src)
matrix = []
src.each do |line|
line.chomp!
next if line.empty?
matrix.push line.split(/\s+/).map{|x| x.to_i }
end
Matrix.rows(matrix)
end
m = parse_matrix(ARGF.read)
puts m.transpose.to_a.map{|v| v.join(" ") }
*数当てゲーム [#b1a863ae]
#Usage: ruby guess_number.rb [n Difficulty]
srand
require 'readline'
def try_answer(prompt)
while buf = Readline.readline(prompt, true)
yield buf
end
end
difficulty = (ARGV[0] || 1).to_i
difficulty >= 1 or raise "#{difficulty}: Invalid difficulty direction"
answer = rand(10 * difficulty + 1)
judge_table = ["Collect!", "Bigger.", "Smaller."]
try_answer("guess? > ") do |line|
try = line.to_i
result = try <=> answer
puts "#{try} is #{judge_table[result]}"
break if result.zero?
end
*数当てゲーム その2(Hit&Blow) [#od23e209]
ルールの補足に合わせて改訂。
def help
warn <<-HELP
hit_and_blow.rb: play Hit & Blow game.
usage: ruby hit_and_blow.rb [-option] [DIFFICULTY]
h, --help show this help
v, --version show version
HELP
exit 0
end
def version
warn "hit_and_blow 0.0.1"
exit 0
end
require 'readline'
srand
#n桁以下の数を乱数生成
def generate_answer(col)
bottom = 10 ** (col - 1)
rand(10 ** col - bottom) + bottom
end
#答えの数の妥当性チェック(全桁の数がユニークか)
def valid_answer?(n)
n.to_s.split(//).uniq! ? false : true
end
def generate_valid_answer(col)
answer = nil
loop do
answer = generate_answer(col)
valid_answer?(answer) and break
end
answer
end
#数を桁ごとに分ける(col指定で0補完)
def num_split_cols(n, col=nil)
width = col || n.to_s.length
sprintf("%0#{width}d", n).split(//).map{|n| n.to_i }
end
def input_number(prompt)
while line = Readline.readline(prompt, true)
n = line.to_i
if n < 0
warn "do not input negative number."
else
yield n
end
end
end
ARGV.delete_if do |x|
case x
when "-h", "--help"
help
when "-v", "--version"
version
end
end
n = (ARGV[0] || 4).to_i
n > 0 or raise "#{n}: Invalid difficulty specification."
answer = generate_valid_answer(n)
answer_set = num_split_cols(answer, n)
p answer if $DEBUG
result = []
def result.clear(width)
fill(0, 0, width)
end
def result.count(n)
join.count(n.to_s)
end
result.clear(n)
input_number("try! >") do |reply|
reply_set = num_split_cols(reply, n)
#check `Hit'
reply_set.each_with_index do |r, i|
result[i] += 1 if r == answer_set[i]
end
#check `Blow'
reply_set.each_with_index do |r, i|
result[i] += 1 if answer_set.include?(r)
end
hit, blow = result.count(2), result.count(1)
print "#{hit} Hit & #{blow} Blow\n"
break if hit == n
result.clear(n)
end
*FizzBuzz [#xb9545ca]
def fizz_buzz(n)
ret = "#{["Fizz"][n % 3]}#{["Buzz"][n % 5]}"
ret.empty? ? n.to_s : ret
end
puts (1..100).collect{|n| fizz_buzz n }
*カレンダー出力 [#v8444f3a]
#使い方: コマンドラインにテキトーに日付を入れで動かす
require 'optparse'
require 'time'
require 'forwardable'
require 'stringio'
class Month
extend Forwardable
[:Sunday, :Monday, :Thuesday, :Wednesday,
:Thursday, :Friday, :Saturday].each_with_index do |const, n|
const_set const, n
end
private
def initialize(datum)
@datum = datum
@days = [nil]
load_days datum, @days
end
def load_days(datum, days)
1.upto(31) do |day|
date = Time.local(datum.year, datum.month, day)
break unless date.month == datum.month
days.push date
end
end
public
def_delegators "@datum", :year, :zone
def name(abbrev=false)
@datum.strftime(abbrev ? "%b" : "%B")
end
def_delegators "@days", :[], :first, :last
def each
@days.each{|d| yield d }
end
end
class CalenderRender
def initialize(mon)
@mon = mon
end
def run(port=$stdout)
weeks = calender_matrix(@mon)
show_calender header_render(@mon) + calender_render(weeks)
end
private
def show_calender(src, port=$stdout)
port.print src
end
def calender_matrix(mon)
weeks = []
week = Array.new(7)
1.upto(mon.last.day) do |n|
week[mon[n].wday] = mon[n].day
if mon[n].wday == Month::Saturday
weeks.push week
week = Array.new(7)
end
end
weeks.push week
weeks
end
end
class CUICalenderRender < CalenderRender
private
def calender_matrix(mon)
weeks = super
weeks.unshift %w[Sun Mon Tue Wed Thu Fri Sat]
weeks
end
def header_render(mon)
col = 3 * 7 + (7 - 1)
cap = "#{mon.name}, #{mon.year}"
padding = (col - cap.length) / 2
head = sprintf("%#{padding}s%s%#{padding}s", "", cap, "")
sprintf("%#{col}s\n", head)
end
def calender_render(weeks)
weeks.collect{|week|
if week.all?{|day| day.nil? }
""
else
week.collect{|day| sprintf("%3s", day.to_s)}.join(" ")
end
}.join("\n")
end
end
class HTMLCalenderRender < CalenderRender
def header_render(mon)
h = "#{mon.name}, #{mon.year}"
<<-HTML
<!-- generated by calender.rb -->
<?xml version="1.0" ?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>#{h}</title>
</head>
<body>
<table>
<tr>
<th colspan="7">#{h}</th>
</tr>
HTML
end
def calender_render(weeks)
buf = StringIO.new
weeks.each do |week|
buf.puts "\t<tr>"
week.each do |day|
buf.puts "\t\t<td>#{day}</td>" if day
end
buf.puts "\t</tr>"
end
buf.puts "</table>\n</body>\n</html>"
buf.string
end
end
class GUICalenderRender < CalenderRender
#作成中
end
render_class = CUICalenderRender
render_class_table = {
"cui" => CUICalenderRender,
"gui" => GUICalenderRender,
"html" => HTMLCalenderRender
}
op = OptionParser.new
op.on("-m MODE", "--show-mode=MODE",
"specify calender type(cui|gui|html)"){|v|
render_class = render_class_table[v.downcase] || CUICalenderRender
}
op.on("-h", "--help", "show this help"){
warn op.help
exit 0
}
op.on("-v", "--version", "show version"){
warn "calender.rb 0.0.1"
exit 0
}
op.parse!(ARGV)
if ARGV.size > 1
ARGV.replace [ARGV.join("/")]
end
datum = ARGV[0] ? Time.parse(ARGV[0]).getlocal : Time.now
mon = Month.new(datum)
render = render_class.new(mon)
render.run
*配列いじり [#d5c23dc0]
def exclude_without_first!(array)
fst = array.first.dup
array.fill(0)
array[0] = fst
array
end
*Caesar暗号解読 [#h97ae94f]
総当り法による力任せ解読。
### Usage: ruby caesar.rb HINT [CODE_FILE]
module CaesarCode
class CharTable
def initialize(char_set)
@char_set = char_set
@shifted = char_set.dup
@shift_count = 0
def @shifted.rotate
temp = self.shift
self.push temp
self
end
@table = {}
init_table
end
attr_reader :shift_count
def [](key)
@table[key]
end
def shift
@shifted.rotate
init_table
@shift_count += 1
self
end
private
def init_table
@table.clear
@char_set.zip(@shifted).each do |x|
@table[x[0]] = x[1]
end
end
end
end
def convert(base, table)
base.split(//).collect{|x| table[x] or x }.join("")
end
raise ArgumentError, "hint word not given" if ARGV.empty?
hint = ARGV.shift
char_set = "abcdefghijklmnopqrstuvwxyz .,-".split(//)
table = CaesarCode::CharTable.new(char_set)
src = ARGF.read
org = src[0]
until src.include?(hint)
src = convert(src, table.shift)
raise "can't decode" if org == src[0]
end
print src
print "鍵(シフト数)は #{table.shift_count} です\n"
*ファイル読み込んで標準出力に出す [#ib80ae4e]
begin
puts IO.readlines("kadai.txt").map{|line| "[#{line.chomp}]" }
rescue => ex
warn ex.message
end
*Base64 [#q2bfc331]
require 'stringio'
def version
warn "base64.rb 0.0.1"
exit 0
end
def help
warn <<-HELP
base64.rb: Base64 encoder/decoder
usage: ruby base64.rb MODE [filenames ...]
MODE:
encode : ordinary file to Base64 format
decode : Base64 format to original file
none : print not convert one
HELP
exit 0
end
proc_tbl = {
:encode => proc{|org| [org].pack("m") },
:decode => proc{|org| org.unpack("m").first },
:none => proc{|org| org }
}
opt_mode = []
ARGV.delete_if do |x|
case x
when "encode", "decode", "none"
opt_mode.push x.intern
when "-h", "--help"
help
when "-v", "--version"
version
end
end
opt_mode.empty? and opt_mode.push :none
opt_mode.size == 1 or raise "Too many mode specification"
mode = opt_mode.first
$stdin.binmode
$stdout.binmode
def argf_imitate(argv, mode)
if argv.empty?
yield $stdin
else
argv.each do |path|
File.open(path, mode){|f| yield f }
end
end
end
argf_imitate(ARGV, 'rb') do |f|
buffer = StringIO.new(proc_tbl[mode].call(f.read))
until buffer.eof?
$stdout.print buffer.read(64)
end
end
----
*初心者用課題(汎用アルゴリズム編) Ruby版 [#re07127c]
問題の詳細については
[[練習問題(アルゴリズム編)]]を参照。
*スタック [#g581d449]
require 'readline'
require 'forwardable'
module RPCalc
class Stack
extend Forwardable
def initialize
@body = []
end
def self.load(collection)
stack = self.new
collection.each{|x| stack.push x }
stack
end
def_delegators :@body, :push, :pop, :size, :empty?
def_delegator :@body, :last, :top
def pretty_print
". " + @body.reverse.map{|x| x.to_s }.join(" ") + " ]"
end
end
module Lexer
def lex(str)
str.strip.split(/\s+/)
end
end
module Parser
def parse(tokens)
semantic_values = []
tokens.each do |token|
case token
when /\A[_a-zA-Z]\w*\Z/
semantic_values.push [token.intern, :IDENT]
when /\A\d+\.\d+\Z/, /\A\d+\Z/
semantic_values.push [token.to_f, :NUMBER]
when /\A(\+|-|\*|\/)\Z/
semantic_values.push [token.intern, :COPERATOR]
else
semantic_values.push [token.intern, :ETC]
end
end
semantic_values
end
end
module Evaluater
def evaluate(svals, stack)
svals.each do |value, type|
case type
when :COPERATOR
unless o2 = stack.pop
warn "Stack Empty."
break
end
unless o1 = stack.pop
warn "Stack Empty."
stack.push o2
break
end
stack.push o1.__send__(value, o2)
when :NUMBER
stack.push value
when :IDENT
exit if value == :exit
when :ETC
; #ignore
else
raise Exception, "unknown semantic value: #{type}"
end
end
stack.top
end
end
class Calculator
include Lexer, Parser, Evaluater
def initialize
@stack = Stack.new
end
def shell(prompt, echo=true)
while line = Readline.readline(prompt, true)
yield line
puts @stack.pretty_print if echo
end
end
def calculate(expr)
tokens = lex(expr)
svals = parse(tokens)
evaluate(svals, @stack)
end
end
end
calc = RPCalc::Calculator.new
calc.shell("> ") do |line|
puts calc.calculate(line)
end
print "\n"