AOJ(問題集)7
AIZU ONLINE JUDGE: Programming Challenge
0061 Rank Checker
data = [] until (st = $<.gets.chomp) == "0,0" data << st.split(",").map(&:to_i) end data.sort! {|a, b| b[1] <=> a[1]} x = data.first.last h = {} l = 1 data.each do |d| l += 1 unless x == d.last x = d.last h[d.first] = l end puts $<.readlines.map(&:to_i).map {|i| h[i]}
実装が汚い…。
0062 What is the Bottommost?
def doit(ary) return ary.first if ary.size == 1 doit( ary.each_cons(2).map {|i, j| (i + j) % 10} ) end $<.readlines.map {|a| a.chomp.chars.map(&:to_i)}.each do |given| puts doit(given) end
0063 Palindrome
co = 0 $<.readlines.map(&:chomp).each do |st| co += 1 if st == st.reverse end puts co
0064 Secret Number
n = 0 $<.readlines.map(&:chomp).each do |st| n += st.scan(/\d+/).map(&:to_i).sum end puts n
0065 Trading
x, y = $<.readlines.map(&:chomp).chunk {|st| st.empty?}.reject {|a| a.first} .map(&:last).map{|a| a.map {|b| b.split(",").first.to_i}}.to_a h = Hash.new(0) (x + y).each {|i| h[i] += 1} (x - (x - y)).uniq.sort.each {|i| puts "#{i} #{h[i]}"}
0066 Tic Tac Toe
table = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]] check = ->(field, type) { table.each {|pat| return true if pat.map {|i| field[i] == type}.all?} false } $<.readlines.map(&:chomp).map(&:chars).each do |field| result = if check.(field, "o") "o" elsif check.(field, "x") "x" else "d" end puts result end
最初与えられた盤面でゲームが完結していないのかと思った…。
0067 The Number of Island
L = 12 def delete(field, x, y) field[y][x] = "0" [[1, 0], [0, -1], [-1, 0], [0, 1]].each do |dx, dy| x1 = x + dx y1 = y + dy if !(x1 < 0 or x1 >= L or y1 < 0 or y1 >= L) and field[y1][x1] == "1" delete(field, x1, y1) end end end $<.readlines.map(&:chomp).chunk {|st| st.empty?} .reject {|a| a.first}.map {|a| a.last}.each do |field| co = 0 L.times do |y| L.times do |x| if field[y][x] == "1" co += 1 delete(field, x, y) end end end puts co end
0068 Enclose Pins with a Rubber Band
include Math until (n = $<.gets.to_i).zero? points = Array.new(n) { Complex(*$<.gets.split(",").map(&:to_f)) } ym = points.map(&:imaginary).max start_po = po0 = points.find {|po| po.imaginary == ym} prev_arg = PI result = loop do points = (points - [start_po] + [po0]).uniq selected = points.map {|po| [po - start_po, po]} .reject {|pos| pos.first == 0} .sort_by {|pos| a = pos.first.angle + PI - prev_arg; a >= 0 ? a : a + 2 * PI} .first.last points.select! {|po| po != start_po} break points.size - 1 if selected == po0 # po0の分だけ1引く prev_arg = (selected - start_po).angle + PI start_po = selected end puts result end
ムズカしかったので一発でいってうれしいが、しかし複雑すぎる。もっといい解法がないかな。
Ruby で解けている人は多くない。
問題はこれ。考え方としては
1. 点を複素数としてオブジェクト化する。
2. 確実に外にある点(po0
)をひとつ選ぶ。
3. 残りの点のすべてへの方向を計算し、いちばん少ない角度で左回りになる点を選ぶ。
4. 選んだ点で同様に (3) を繰り返し、一周したところでおしまい。
5. 残った点の数が求めるもの。
つまり、反時計回りで一周して、周にない点の数を求めるということ。
0069 Drawing Lots II
あみだくじ。与えられたあみだくじで特定の場所を選んで当たりに到達するか調べる。もしそれでダメなら、一本だけ横線を加えてもよい。という問題(参照)。
def hit(n, m, goal, d, dans) h = 0 until h == d yoko = dans[h] if m != n - 1 and yoko[m] == 1 m += 1 elsif m.nonzero? and yoko[m - 1] == 1 m -= 1 end h += 1 end goal == m end until (n = $<.gets.to_i).zero? m = $<.gets.to_i - 1 goal = $<.gets.to_i - 1 d = $<.gets.to_i dans = Array.new(d) { $<.gets.chomp.chars.map(&:to_i) } if hit(n, m, goal, d, dans) puts 0 else try = ->{ d.times do |h| ([0] + dans[h] + [0]).each_cons(3).with_index do |a, x| if a.sum.zero? dans[h][x] = 1 return "#{h + 1} #{x + 1}" if hit(n, m, goal, d, dans) dans[h][x] = 0 end end end 1 } puts try.() end end
これも一発でいった。しかし、段々ムズカしくなってきた…。ふう。
これも Ruby で解いた人は少ない。
0070 Tag Discussion Solution Statistics Submit
def solve(ary, n, s) co = 0 ary.each do |i| s1 = s - i * n if n == 1 if s1.zero? co += 1 end elsif s1 > 0 co += solve(ary - [i], n - 1, s1) end end co end $<.readlines.map {|a| a.split.map(&:to_i)}.each do |n, s| puts solve([*0..9], n, s) end
たぶんこれでいけるのだけれど、時間制限に引っかかる。問題はこれ。よく考えないとな。
デバッグ用。
io.readlines.map {|a| a.split.map(&:to_i)}.each do |n, s| solve = ->(ary, n, s1, st = "") { co = 0 ary.each do |i| s2 = s1 - i * n st1 = st + "#{i}*#{n} + " if n == 1 if s2.zero? co += 1 puts st1[0..-4] + " = #{s}" end elsif s2 > 0 co += solve.(ary - [i], n - 1, s2, st1) end end co } puts solve.([*0..9], n, s) end
これはたとえば n = 5, s = 24 でこうなる。
0*5 + 1*4 + 2*3 + 3*2 + 8*1 = 24 0*5 + 1*4 + 2*3 + 4*2 + 6*1 = 24 0*5 + 1*4 + 2*3 + 5*2 + 4*1 = 24 0*5 + 1*4 + 3*3 + 2*2 + 7*1 = 24 0*5 + 1*4 + 4*3 + 3*2 + 2*1 = 24 0*5 + 2*4 + 1*3 + 3*2 + 7*1 = 24 0*5 + 2*4 + 1*3 + 4*2 + 5*1 = 24 0*5 + 2*4 + 1*3 + 5*2 + 3*1 = 24 0*5 + 2*4 + 3*3 + 1*2 + 5*1 = 24 0*5 + 3*4 + 1*3 + 2*2 + 5*1 = 24 0*5 + 3*4 + 2*3 + 1*2 + 4*1 = 24 1*5 + 0*4 + 2*3 + 3*2 + 7*1 = 24 1*5 + 0*4 + 2*3 + 4*2 + 5*1 = 24 1*5 + 0*4 + 2*3 + 5*2 + 3*1 = 24 1*5 + 0*4 + 3*3 + 2*2 + 6*1 = 24 1*5 + 0*4 + 3*3 + 4*2 + 2*1 = 24 1*5 + 0*4 + 4*3 + 2*2 + 3*1 = 24 1*5 + 2*4 + 0*3 + 3*2 + 5*1 = 24 1*5 + 2*4 + 0*3 + 4*2 + 3*1 = 24 2*5 + 0*4 + 1*3 + 3*2 + 5*1 = 24 2*5 + 0*4 + 1*3 + 4*2 + 3*1 = 24 2*5 + 1*4 + 0*3 + 3*2 + 4*1 = 24 22
フーム。
関係性を調べてみる。
table = [] s = 0 while s < 25 st = "" table << (1..10).map {|n| "%3d" % solve([*0..9], n, s)}.join(" ") s += 1 end table.reverse_each {|l| puts l}
結果。
0 1 16 43 22 0 0 0 0 0 0 3 27 51 13 0 0 0 0 0 0 3 21 35 7 0 0 0 0 0 0 3 18 36 5 0 0 0 0 0 0 4 20 26 1 0 0 0 0 0 0 5 23 29 0 0 0 0 0 0 0 3 13 19 0 0 0 0 0 0 0 5 20 23 0 0 0 0 0 0 0 4 14 15 0 0 0 0 0 0 0 4 13 14 0 0 0 0 0 0 0 4 12 11 0 0 0 0 0 0 0 5 14 9 0 0 0 0 0 0 0 3 7 4 0 0 0 0 0 0 0 5 11 4 0 0 0 0 0 0 0 4 8 1 0 0 0 0 0 0 1 4 5 0 0 0 0 0 0 0 1 4 4 0 0 0 0 0 0 0 1 4 5 0 0 0 0 0 0 0 1 2 2 0 0 0 0 0 0 0 1 3 3 0 0 0 0 0 0 0 1 2 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
うーん。
かなり考えたのだが、これでも時間オーバー。メモ化。
@memo = {} def solve(ary, n, s) hash = ary.map {|i| [11, 13, 17, 19, 23, 29, 31, 37, 41, 43][i]}.inject(&:*) hash *= n return @memo[[hash, s]] if @memo[[hash, s]] co = 0 ary.each do |i| s1 = s - i * n if n == 1 if s1.zero? co += 1 end elsif s1 > 0 co += solve(ary - [i], n - 1, s1) end end @memo[[hash, s]] = co end $<.readlines.map {|a| a.split.map(&:to_i)}.each do |n, s| puts solve([*0..9], n, s) end
このアプローチでは無理かな。
他の人の回答(参照)。
$sumhash = {} def check_sum(n, s, used = 0) key = "#{n},#{s},#{used}" return $sumhash[key] if ! $sumhash[key].nil? if n == 0 return s == 0 ? 1 : 0 end count = 0 10.times do |i| b = 1 << i ni = n * i if (used & b).zero? and s >= ni used |= b count += check_sum(n - 1, s - ni, used) used ^= b end end return $sumhash[key] = count end while (line = $<.gets) n, s = line.chomp.split(" ").map{|s| s.to_i} puts check_sum(n, s) end
なんと、じつに素直なアプローチ。で、あとはメモ化かあ。全然自分の知っている方法だけで解けるではないか。うーん、まだまだだなあ…。
ただ、ビット演算で or で立てたフラグを消すのが xor というのは気づかなかった。これは勉強になった。
AOJ(問題集)6
AIZU ONLINE JUDGE: Programming Challenge
0051 Differential II
$<.readlines.drop(1).map {|a| a.chomp.chars.map(&:to_i).sort}.each do |ary| puts ary.reverse.join.to_i - ary.join.to_i end
0052 Factorial II
until (n = $<.gets.to_i).zero? five = n / 5 f = ->(x) { return five if n < x five += n / x f.(x * 5) } puts f.(25) end
これはちょっと考えました。
0053 Sum of Prime Numbers
require 'prime' nums = [] h = {} until (i = $<.gets.to_i).zero? nums << i h[i] = 0 end max_num = nums.max sum = 0 Prime.each.with_index do |prime, i| break if i + 1 > max_num sum += prime h[i + 1] = sum if h[i + 1] end nums.each {|j| puts h[j]}
与えられた値が重複しているのだな。結構いい成績だった。
0054 Sum of Nth decimal places
$<.readlines.map {|a| a.split.map(&:to_i)}.each do |a, b, n| f = ->(x, i = 1, sum = 0) { return sum if i > n or x.zero? f.(x * 10 % b, i + 1, sum + x * 10 / b) } puts f.(a % b) end
0055 Sequence
$<.readlines.map(&:to_f).each do |x| sum = 0 solve = ->(n, i = 1) { sum += n return sum if i == 10 (i + 1).even? ? solve.(n * 2.0, i + 1) : solve.(n / 3.0, i + 1) } puts solve.(x) end
0056 Goldbach's Conjecture
require 'prime' h = {} primes = Prime.each(50000).to_a primes.each {|pr| h[pr] = true} until (n = $<.gets.to_i).zero? co = 0 if n.odd? co = 1 if h[n - 2] else primes.each do |pr| break if pr > n / 2 co += 1 if h[n - pr] end end puts co end
何か変なミスをしていた。何とタイムは挑戦者中最速。
0057 The Number of Area
$<.readlines.map(&:to_i).each do |n| puts 2 + (n - 1) * (n + 2) / 2 end
0058 Orthogonal
$<.readlines.map {|l| l.split.map(&:to_r)}.each do |xa, ya, xb, yb, xc, yc, xd, yd| x1, y1 = xb - xa, yb - ya x2, y2 = xd - xc, yd - yc puts x1 * x2 + y1 * y2 == 0 ? "YES" : "NO" end
0059 Intersection of Rectangles
while (st = $<.gets) xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2 = st.split.map(&:to_f) if !(xa1 > xb2 or xa2 < xb1 or ya1 > yb2 or ya2 < yb1) puts "YES" else puts "NO" end end
こんなに簡単なものが条件を見落としていた…。
0060 Card Game
$<.readlines.map {|a| a.split.map(&:to_i)}.each do |my1, my2, opp1| deck = [*1..10] - [my1, my2, opp1] limit = 20 - (my1 + my2) p = 0 deck.each do |opp2| n = (deck - [opp2]).take_while {|i| i <= limit}.size p += 1/7r * Rational(n, 6) end puts p >= 1/2r ? "YES" : "NO" end
AOJ(問題集)5
AIZU ONLINE JUDGE: Programming Challenge
0041 Expression
def solve(ary) if ary.size <= 1 return ary[0] if eval(ary[0]) == 10 else idxs = [*0...ary.size] idxs.combination(2) do |i, j| a, b = ary[i], ary[j] nxt = (idxs - [i, j]).map{|x| ary[x]} ["(#{a} + #{b})", "(#{a} - #{b})", "(#{b} - #{a})", "#{a} * #{b}"].each do |st| result = solve(nxt + [st]) return result if result end end end nil end until (given = $<.gets.chomp.split) == ["0", "0", "0", "0"] ans = solve(given) puts ans ? ans : 0 end
自信作(笑)。
0042 A Thief
i = 1 until (furoshiki = $<.gets.to_i).zero? table = {0 => 0} Array.new($<.gets.to_i) {$<.gets.split(",").map(&:to_i)}.each do |v, w| h = Hash.new(0) table.each {|key, value| h[key + w] = table[key] + v if key + w <= furoshiki} table.merge!(h) {|k, v1, v2| [v1, v2].max} end m = table.values.max result = table.select {|k, v| v == m}.sort {|a, b| a[0] <=> b[0]}.first puts "Case #{i}:", result[1], result[0] i += 1 end
典型的な動的計画法。
0043 Puzzle
def check(table) result = 0 if table.sum <= 2 result = 1 if table.find {|x| x == 2} else (1..7).each do |i| tmp = table.dup if tmp[i].nonzero? and tmp[i + 1].nonzero? and tmp[i + 2].nonzero? 3.times {|x| tmp[i + x] -= 1} result += check(tmp) return 1 if result.nonzero? end (1..9).each do |j| tmp1 = table.dup if tmp1[j] >= 3 tmp1[j] -= 3 result += check(tmp1) return 1 if result.nonzero? end end end end result end $<.readlines.map(&:chomp).map {|n| n.chars.map(&:to_i)}.each do |data| table = Array.new(10, 0) data.each {|i| table[i] += 1} result = (1..9).map do |i| added = table.dup added[i] += 1 next if added[i] > 4 check(added).nonzero? ? i : nil end.compact puts result.empty? ? 0 : result.join(" ") end
3.09秒かかった。
他の人の回答を見ていて気づいたが、check() メソッド内のループはネストさせる必要がない。書き直すと
def check(table) result = 0 if table.sum <= 2 table.find {|x| x == 2} else (1..7).each do |i| tmp = table.dup if tmp[i].nonzero? and tmp[i + 1].nonzero? and tmp[i + 2].nonzero? 3.times {|x| tmp[i + x] -= 1} return true if check(tmp) end end (1..9).each do |j| tmp1 = table.dup if tmp1[j] >= 3 tmp1[j] -= 3 return true if check(tmp1) end end false end end $<.readlines.map(&:chomp).map {|n| n.chars.map(&:to_i)}.each do |data| table = Array.new(10, 0) data.each {|i| table[i] += 1} result = (1..9).map do |i| added = table.dup added[i] += 1 next if added[i] > 4 check(added) ? i : nil end.compact puts result.empty? ? 0 : result.join(" ") end
これで 0.10秒。充分速い。
0044 Prime Number II
require 'prime' $<.readlines.map(&:to_i).each do |n| a = (n - 1).step(0, -1) {|i| break i if Prime.prime?(i)} b = (n + 1).step {|i| break i if Prime.prime?(i)} puts "#{a} #{b}" end
標準添付ライブラリを使うというインチキ。
0045 Sum and Average
all_price = amount = i = 0 $<.readlines.map {|x| x.split(",").map(&:to_i)}.each do |price, n| all_price += price * n amount += n i += 1 end puts all_price puts (amount / i.to_f).round
0046 Differential
max, min = 0, Float::INFINITY $<.readlines.map(&:to_f).each do |h| max = h if h > max min = h if h < min end printf "%.1f\n", max - min
0047 Cup Game
place = "A" $<.readlines.map {|x| x.chomp.split(",")}.each do |a, b| if place == a place = b elsif place == b place = a end end puts place
0048 Class
table = [["light fly", 0, 48.0], ["fly", 48.0, 51.0], ["bantam", 51.0, 54.0], ["feather", 54.0, 57.0], ["light", 57.0, 60.0], ["light welter", 60.0, 64.0], ["welter", 64.0, 69.0], ["light middle", 69.0, 75.0], ["middle", 75.0, 81.0], ["light heavy", 81.0, 91.0], ["heavy", 91.0, Float::INFINITY]] $<.readlines.map(&:to_f).each do |w| table.each {|name, bottom, top| puts name if bottom < w and w <= top} end
0049 Blood Groups
table = {"A"=>0, "B"=>1, "AB"=>2, "O"=>3} nums = Array.new(4, 0) $<.readlines.map {|a| a.chomp.split(",").last}.each do |type| nums[table[type]] += 1 end puts nums
Windows フリーゲーム「Almagest」を Linux で遊ぶ
ゲーム HP。
Almagest -Overture-
以下よりダウンロードする。
「Almagest -Overture-」ターン制SFシミュレーションゲーム - 窓の杜
lzh ファイルは Linux ではそのままでは解答できないので、ここでは lhasa を入れてみる。
$ sudo apt install lhasa
これで解凍できる。ver 3.04 の差分フォルダもダウンロードした場合は、手作業で差分ファイルを差し替える(参照)。
動かすためには Wine が必要です。実行はふつうに
$ wine Almagest-1.exe
でよい。特にインストールとかはされない。
Linux Mint 19, wine-3.0 で動作確認。
※参考
Almagest -Overture- - Wikipedia
Almagestとは (アルマゲストとは) [単語記事] - ニコニコ大百科
Almagest Wiki - Front Page
はがきデザインキット2019 を Ubuntu 18.10 にインストール
以前に郵便局の「はがきデザインキット」を Ubuntu にインストールする記事(参照)を書いたのですが、その手順が古くなったので再挑戦です。
まずは Wine が使えるか調べます。「Wine」とは Linux で Windows のソフトを動かすためのアプリです。
$ wine --version Command 'wine' not found, but can be installed with: sudo apt install wine sudo apt install wine-development
というわけで入っていないので、表示されたとおりにやります。
$ sudo apt update $ sudo apt install wine-stable
あとで必要なのでやっておきます。(※後記:たぶん samba と winbind のインストールは必要ない気がします。飛ばして下さい。)
$ sudo apt install samba $ sudo apt install winbind
Wine がインストールされているか確認します。
$ wine --version wine-3.18 (Ubuntu 3.18-2)
このままだと文字化けします。なので
$ sudo apt install winetricks $ winetricks allfonts
を実行します(参照)。終了後、
$ winecfg
で文字化けがなければ OK です。これで Wine のインストールが完了しました。
つぎに Abode Air をインストールします。ここから「手順1」は「Windows」、「手順2」は「Adobe AIR 32.0 for Win64」を選択し、「今すぐダウンロード」をクリックします。念のため
$ sudo apt install mono-complete
をしておいてから、ダウンロードした exe ファイルを
$ wine AdobeAIRInstaller.exe
で実行。インストーラーがうまく働いていないように見えますが、フリーズ後に [Ctrl] + [C] をして(うまくいかなければプロセスを終了させる)上記コマンドを再実行すると、インストール済の表示が出れば OK です。 (追記:インストーラーのプロセスはすべて必ず終了させて下さい。)
最後にここから「はがきデザインキット」をダウンロード。zip ファイルを解凍して design_kit.air を右クリック、[他のアプリケーションで開く]→[Adobe AIR Application Installer] を選択して実行すると、インストールされる筈です。お疲れ様でした!
追記(2020年度版へのアップグレード)
2019年度版から2020年度版へアップグレードする場合、ソフトで用意された方法ではうまくアップグレードできないかも知れません。その場合は2020年度版をダウンロードし、上の手順で design_kit.air を再インストールしてみて下さい。これでふつうにバージョンアップできると思います。
AOJ(問題集)4
AIZU ONLINE JUDGE: Programming Challenge
0031 Weight
def measure(object, weight, result = []) return result.join(" ") if weight.zero? result.unshift(weight) if (object / weight).nonzero? measure(object % weight, weight / 2, result) end $<.readlines.map(&:to_i).each {|ob| puts measure(ob, 512)}
0032 Plastic Board
rectangle = lozenge = 0 $<.readlines.map {|l| l.split(",").map(&:to_i)}.each do |a, b, c| rectangle += 1 if a * a + b * b == c * c lozenge += 1 if a == b end puts rectangle, lozenge
0033 Ball
def try(balls, b ,c) return 1 if balls.empty? nxt = balls.first bl = balls.drop(1) if nxt > b and nxt > c try(bl, nxt, c) + try(bl, b, nxt) elsif nxt > b try(bl, nxt, c) elsif nxt > c try(bl, b, nxt) else 0 end end $<.gets.to_i.times do balls = $<.gets.split.map(&:to_i) puts try(balls.drop(1), balls.first, 0).nonzero? ? "YES" : "NO" end
読み込みに readlines
を使ったらエラーが出る。gets
を使ったコードに替えたら正解になった。非本質的なところで延々と悩まされた。
0034 Railway Lines
$<.readlines.map {|l| l.split(",").map(&:to_i)}.each do |given| ls = given.first(10) v1, v2 = given.last(2) s = Rational(v1 * ls.sum, v1 + v2) l = 0 ls.each_with_index do |ln, i| next if s > (l += ln) puts i + 1 break end end
0035 Is it Convex?
$<.readlines.map {|l| l.split(",").map(&:to_r)}.each do |given| f = (given + given.first(4)).each_slice(2).each_cons(3).map do |a, b, c| (c[0] - a[0]) * (b[1] - a[1]) - (c[1] - a[1]) * (b[0] - a[0]) > 0 end puts((f.all? or f.none?) ? "YES" : "NO") end
0036 A Figure on Surface
L = 8 table = [["11", "11"], ["1", "1", "1", "1"], ["1111"], ["01", "11", "10"], ["110", "011"], ["10", "11", "01"], ["011", "110"]] table.map! {|pt| [pt.size, l = pt.first.length, pt.join("0" * (L - l))]} $<.readlines.chunk {|l| !!l.match(/^\d/) || nil} .map {|a| a.last.map(&:chomp).join}.each do |field| table.each_with_index do |ary, k| y, n, pt = ary (L + 1 - y).times do |i| (L + 1 - n).times do |j| puts "ABCDEFG"[k] if field[i * L + j, pt.length] == pt end end end end
0037 Path on a Grid
given = $<.readlines.map {|l| l.chomp.chars.map(&:to_i)} yoko = 0.step(8, 2).map {|i| given[i]} tate = 1.step(8, 2).map {|i| given[i]}.transpose dirs = "LRUD" go = nil route = "" f = false get_yoko = ->(x, y, dir) { if dir == 0 if tate[x][y] == 1 go.(x, y, 3) elsif x > 0 and yoko[y][x - 1] == 1 go.(x, y, 0) elsif y > 0 and tate[x][y - 1] == 1 go.(x, y, 2) else go.(x, y, 1) end else if y > 0 and tate[x][y - 1] == 1 go.(x, y, 2) elsif x <= 3 and yoko[y][x] == 1 go.(x, y, 1) elsif tate[x][y] == 1 go.(x, y, 3) else go.(x, y, 0) end end } get_tate = ->(x, y, dir) { if dir == 2 if x > 0 and yoko[y][x - 1] == 1 go.(x, y, 0) elsif y > 0 and tate[x][y - 1] == 1 go.(x, y, 2) elsif yoko[y][x] == 1 go.(x, y, 1) else go.(x, y, 3) end else if x <= 3 and yoko[y][x] == 1 go.(x, y, 1) elsif y <= 3 and tate[x][y] == 1 go.(x, y, 3) elsif x > 0 and yoko[y][x - 1] == 1 go.(x, y, 0) else go.(x, y, 2) end end } go = ->(x, y, dir) { return if x.zero? and y.zero? and f f = true route += dirs[dir] if dir <= 1 get_yoko.(x + dir * 2 - 1, y, dir) else get_tate.(x, y + dir * 2 - 5, dir) end } go.(0, 0, 1) puts route
何だか全然よくないコード。もっと考えたい。
0038 Poker Hand
def same_numbers(ary, result = []) return result.sort if ary.empty? a = ary.first co = ary.count(a) result << co if co > 1 same_numbers(ary - [a], result) end $<.readlines.map {|l| l.split(",").map(&:to_i)}.each do |hand| puts case same_numbers(hand) when [4] then "four card" when [2, 3] then "full house" when [3] then "three card" when [2, 2] then "two pair" when [2] then "one pair" else hand.sort! if hand.sum == (hand.first + 2) * 5 or hand == [1, 10, 11, 12, 13] "straight" else "null" end end end
0039 Roman Figure
table = {I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000, nil => 0} count = ->(roman, number = 0) { return number if roman.empty? a, b = table[roman.first], table[roman[1]] number += if a >= b r = roman.drop(1) a else r = roman.drop(2) b - a end count.(r, number) } $<.readlines.map(&:chomp).each {|roman| puts count.(roman.chars.map(&:to_sym))}
0040 Affine Cipher
def decode(word, a, b) g = (0..25).map {|i| [[*"a".."z"][(a * i + b) % 26], i]}.to_h word.chars.map {|st| (g[st] + 97).chr}.join end e = Enumerator.new do |y| generate = ->(n) { a, b = n, 0 n.times do y << [a, b] a -= 1 b += 1 end generate.(n + 1) } generate.(1) end $<.readlines.drop(1).map {|a| a.split}.each do |sentence| loop do a, b = e.next dsr = (1..a).select {|i| (a % i).zero?} next if dsr.include?(2) or dsr.include?(13) or dsr.include?(26) f = sentence.select {|w| w.length == 4}.map do |word| st = decode(word, a, b) st == "that" or st == "this" end.any? next unless f puts sentence.map {|word| decode(word, a, b)}.join(" ") break end end
アフィン暗号の解読にはここを参考にした。
うーん、あんまりひどいタイムなので、他の人のコードを参考にした。すごい。
cl = [*"a".."z"] table_a = (1..26).select {|i| 26.gcd(i) == 1} b = nil $<.readlines.drop(1).each do |str| a = table_a.find do |i| b = (0..26).find do |j| nominees = str.split.select {|w| w.length == 4} ["that", "this"].map do |x| nominees.include?(x.chars.map {|c| cl[(i * cl.index(c) + j) % 26]}.join) end.any? end end table = (0..25).map {|i| (a * i + b) % 26} puts str.chomp.chars.map {|c| (c == " ") ? c : cl[table.index(cl.index(c))]}.join end
暗黙の Proc化(Ruby)
[1] pry(main)> (1..4).map {|i| i + 3} => [4, 5, 6, 7]
これと
[2] pry(main)> (1..4).map(&->(i) {i + 3}) => [4, 5, 6, 7]
は同じ。引数での & は Proc をブロックに変換するから。(正確にはさらにそれを暗黙に .call()
している。)
では、
[3] pry(main)> (1..4).map(&3) TypeError: wrong argument type Integer (expected Proc)
はもちろんエラーになるよね。でも、この &3
のとき、3 は Proc でないので、暗黙に 3 を to_proc
しようとしている。それを示してみよう。
Integer クラスにこうモンキーパッチしてみる。
[4] pry(main)> class Integer [4] pry(main)* def to_proc [4] pry(main)* ->(i){i + self} [4] pry(main)* end [4] pry(main)* end => :to_proc
Integer を Proc化するのである。すると、
[5] pry(main)> (1..4).map(&3) => [4, 5, 6, 7]
おお、先ほどと同じだ。つまり、ここでは暗黙に 3 を to_proc
しているのである。うーん、すごいですなあ。
つまり、オブジェクトに to_proc
を定義しておくと、このような遊び(?)ができるわけです。可読性がなにですが。
AOJ(問題集)3
AIZU ONLINE JUDGE: Programming Challenge
0021 Parallelism
$<.readlines.drop(1).map {|a| a.split.map(&:to_r)}.each do |x1, y1, x2, y2, x3, y3, x4, y4| puts((x2 - x1) * (y4 - y3) == (x4 - x3) * (y2 - y1) ? "YES" : "NO") end
単純な問題なのに、自分の解き方ではどうしてもダメだったので、他の人のを参考に。to_f
じゃなくて to_r
がミソなのかなあ。
0022 Maximum Sum Sequence
while (n = $<.gets.to_i).nonzero? given = (1..n).map {$<.gets.to_i} max = -Float::INFINITY n.times do |i| sum = 0 (i...n).each do |j| sum += given[j] max = sum if sum > max end end puts max end
0023 Circles Intersection
$<.readlines.drop(1).map {|a| a.split.map(&:to_f)}.each do |xa, ya, ra, xb, yb, rb| l = Math.sqrt((xb - xa) ** 2 + (yb - ya) ** 2) r = ra - rb puts case when l < r then 2 when l < -r then -2 when l > ra + rb then 0 else 1 end end
0024 Physical Experiments
$<.readlines.map(&:to_r).each do |v| puts((1 + 1/98r * v ** 2).ceil) end
0025 Hit and Blow
$<.readlines.map {|a| a.split.map(&:to_i)}.each_slice(2) do |a, b| a1, b1 = [], [] hit = 0 a.each_index do |i| if a[i] == b[i] hit += 1 else a1 << a[i] b1 << b[i] end end blow = a1.size - (a1 - b1).size puts "#{hit} #{blow}" end
0026 Dropping Ink
L = 10 table = [a = [[0, 0], [0, -1], [1, 0], [0, 1], [-1, 0]], b = a + [[1, -1], [1, 1], [-1, 1], [-1, -1]], b + [[0, -2], [2, 0], [0, 2], [-2, 0]]] field = Array.new(L) {Array.new(L, 0)} set = ->(x, y) { return if x < 0 or x >= L or y < 0 or y >= L field[y][x] += 1 } $<.readlines.map {|l| l.split(",").map(&:to_i)}.each do |x, y, s| table[s - 1].each {|dx, dy| set.(x + dx, y + dy)} end f = field.flatten puts f.count(0) puts f.max
0027 What day is today?
require 'date' table = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday) loop do month, day = $<.gets.split.map(&:to_i) break if month.zero? puts table[Date.new(2004, month, day).wday] end
0028 Mode Value
field = Array.new(101, 0) $<.readlines.map(&:to_i).each {|n| field[n] += 1} m = field.max field.each_with_index {|n, i| puts i if m == n}
0029 English Sentence
counts = Hash.new(0) max = [0, nil] $<.gets.split.map(&:downcase).each do |word| counts[word] += 1 l = word.length max = [l, word] if l > max.first end h = counts.invert puts "#{h[h.keys.max]} #{max.last}"
0030 Sum of Integers
loop do n, s = $<.gets.split.map(&:to_i) break if n.zero? and s.zero? puts [*0..9].combination(n).map {|numbers| numbers.sum == s}.count(true) end