【AOJ】花札シャッフル問題(Hanafuda Shuffle)
(ICPCというプログラミングコンテストではJavaかC++かCを使わないといけないので)サークルの方ではJavaでやっているんですが、普段はRubyで書いていきたいと思います。
問題
カードの山を混ぜて切る方法はいろいろとある. 日本のカード遊びである「花札」における花札混ぜ切りは,札を切る方法の一つ である.
n枚のカードの山がある.図1に示すように,山の一番上からp枚 目の札から連続したc枚の札を抜き取り,それをそのまま山の上に置く. この操作(カット操作という)を繰り返し行う.
花札混ぜ切りをシミュレートし,最終的に山の一番上にくる札を答える プログラムを書きなさい.
書いたコード
class Deck def initialize(n) @cards = 1.upto(n).to_a end def cut(r) r.times do p,c = gets.split.map(&:to_i) bundle = @cards[-p-c+1..-p] @cards.slice!(-p-c+1..-p) @cards.concat(bundle) end @cards end end loop do input = gets.chomp break if input == "0 0" n,r = input.split.map(&:to_i) deck = Deck.new(n) puts deck.cut(r).last end
山札のクラスを作ってインスタンス変数に配列を入れて、それをごにょごにょする感じで書きました。こういうのを定期的にやってないとメソッド名とかいつまでたっても覚えないですね。
気持ち悪い部分見つけたらツッコミください。
追記
修正しないと気持ち悪いので追記していきます。
gets.split.map(&:to_i)
p_c = gets.chomp.split(" ") p = p_c[0].to_i p = p_c[1].to_i
と書いてしまった部分。気持ち悪さは感じてたけど時間制限あるから「これでいいや」的なノリでサブミットしてしまいました。
まず、splitの使い方。引数を省略すれば空白文字で区切ってくれる。つまり、.split(" ")
は.split
でオーケー。で、引数無しのsplitメソッドは先頭・末尾の空白文字も取り除いてくれるのでchomp
を併用する必要がない。
さらに、split
して返ってくる配列を一度保存してからその1つ1つにアクセスしてる。これはきもい。p_cという変数名もきもい。Rubyではa,b = [1,2]
みたいな代入ができるのでそれを使った方がいい。
すると、こうなる。
p,c = gets.split.map(&:to_i)
こちらの記事を参考にさせていただきました。
@cards.concat(fetch_cards(p,c))
これ、2行もいらないのでは。
cards_bundle = fetch_cards(p,c)
@cards.concat(cards_bundle)
ということで1行に。
@cards.concat(fetch_cards(p,c))
fetch_cardsメソッドはいらないのでは
def fetch_cards(p,c) bundle = @cards[-p-c+1..-p] @cards.slice!(-p-c+1..-p) bundle end def cut(r) r.times do p,c = gets.split.map(&:to_i) @cards.concat(fetch_cards(p,c)) end @cards end
cut
メソッドとfetch_cards
メソッドを分けて書いていたのを、id:sekaiyaさんにご指摘頂きました。fetch_cards
単体で使う場面は無いので、この処理はcut
メソッドに書いてしまった方がすっきりして良いですね。
def cut(r) r.times do p,c = gets.split.map(&:to_i) bundle = @cards[-p-c+1..-p] @cards.slice!(-p-c+1..-p) @cards.concat(bundle) end @cards end