昨日の答えです.
1. シェルで以下のコマンドを実行したら,何が表示されますか?
やってみますと,
$ ruby -e 'n=13;n.times{|i| puts " "*(i-n/2).abs + "*"*(n-2*(i-n/2).abs)};' * *** ***** ******* ********* *********** ************* *********** ********* ******* ***** *** *
「13」を変えてみましょう.
$ ruby -e 'n=7;n.times{|i| puts " "*(i-n/2).abs + "*"*(n-2*(i-n/2).abs)};' * *** ***** ******* ***** *** * $ ruby -e '3.upto(9){|n|n.times{|i| puts " "*(i-n/2).abs + "*"*(n-2*(i-n/2).abs)}}' * *** * ** **** ** * *** ***** *** * ** **** ****** **** ** * *** ***** ******* ***** *** * ** **** ****** ******** ****** **** ** * *** ***** ******* ********* ******* ***** *** *
おおむね,'*'を並べてダイヤモンド型にしていることがわかります.
しかし空行があったりなかったりします.よく見ると,n=4,6,8のときの先頭のようです.
それでワンライナーを見直すと,nが偶数でiが0のとき*1は,(i-n/2).absはn/2,(n-2*(i-n/2).abs)は0となってしまい,空行に見える行が出るというわけですね.
2. このプログラムを改良してください.
方針としては,
でやってみましょう.偶数のとき,ダイヤモンド型にどうしてもならないのですが*2,まあこれはこの図形を出すということにします.
それで,コードです.
#!/usr/bin/env ruby # diamond.rb class Diamond def initialize(n_ = 0) @n = n_.to_i @n = 13 if @n <= 0 end def start @n.times do |i| spc = (i - @n / 2).abs ast = @n - 2 * spc next if ast == 0 puts " " * spc + "*" * ast end end end if __FILE__ == $0 Diamond.new(ARGV.shift).start end
そういえば,ワンライナーでは見えていませんでしたが,' 'の個数を求めるときにも,'*'の個数を求めるときにも,「(i-n/2).abs」という式が共通して現れているのですね.2回書くのは当然ながら保守性を損ないますので,この式の値をいったん変数に入れて,参照するようにしました.
initializeメソッドの引数n_について,初期値に0を入れていますが,nilでもかまいません.ここを13とするのは…2度,デフォルトの値を書くのは,いいものではありませんね.