LoginSignup
3

More than 5 years have passed since last update.

クリスマスツリーのアスキーアートを生成するRubyスクリプトを書いた

Last updated at Posted at 2016-12-24

一人暮らしのワンルームアパートでYouTubeを見ながら、コンビニ弁当をつつくという、日本でもっとも文化的なクリスマスイブの過ごし方をしているのですが、残念ながら足りないものがありました。クリスマスツリーです。一人暮らしの独身男性が住むワンルームアパートにクリスマスツリーがあるほうが珍しいとは思いますが、しかしクリスマスツリーがないと、わたしのハイソサエティなクリスマスイブライフのクオリティが下がってしまうのも事実。そこでここはプログラマらしく、クリスマスツリーをアスキーアートとして出力するスクリプトを書いてみることにしました。

簡単な要件としては以下の通りです:

  • クリスマスツリーは葉と幹そして飾りの3部分からなる
    • 葉の形状は二等辺三角形。
    • 幹は長方形で、高さは葉の半分。幅は葉の3分の1程度とする。
    • 飾りは葉の部分に装飾される。量としては葉の6分の1程度にすると見栄えがよさそう。 -なお 飾りはランダムに生成する。
  • 「アスキーアート」ということで、アスキー文字のみで作成する。
    • 葉は*、幹は#、飾りはそれ以外のアスキー文字記号をいくつか選ぶ。

というわけで実際に作成してみました。


# クリスマスツリーを生成する。
# @param leaf_height 葉の高さ
# @return クリスマスツリー[String]
def create_tree(leaf_height)
  # 葉部分の高さが小さい場合は例外を投げる。
  raise ArgumentError.new("しょぼくなるのでだめです") if leaf_height < 5

  # 葉部分の最大の長さ、幹部分の高さと幅をそれぞれ求めておく。
  leaf_width = leaf_height * 2 - 1
  stem_width = (leaf_width / 3).odd? ? leaf_width / 3 : leaf_width / 3 - 1
  stem_height = leaf_height / 2

  # ツリー全体を二次元配列により表現する。
  tree = Array.new(leaf_height + stem_height){Array.new(leaf_width, "\s")}

  # 葉の座標を配列に格納する: 
  leaf_coordinates = (0...leaf_height).flat_map do |i|
    start = leaf_height - i - 1
    length = (i + 1) * 2 - 1
    (start...(start + length)).map{|j| [i, j]}
  end

  # 飾りの座標を格納する: 葉部分にランダムで飾り付ける。飾りの割合は葉全体の1/6程度にする。
  decoration_coordinates = leaf_coordinates.sample(leaf_coordinates.size / 6)

  # 幹の座標を配列に格納する: 幹の高さは葉の1/2、幅は葉の1/3程度とする。
  blank_length = (leaf_width - stem_width) / 2
  stem_coordinates = [*0...stem_height].product([*0...stem_width])
                                       .map{|i, j| [i + leaf_height, j + blank_length]}

  # 葉、飾り、幹のそれぞれを二次元配列treeにマッピングする。
  leaf_coordinates.each{|x, y| tree[x][y] = "*"}
  decoration_coordinates.each{|x, y| tree[x][y] = %w(? $ @ &).sample}
  stem_coordinates.each{|x, y| tree[x][y] = "#"}

  # 二次元配列を人の目にわかりやすい文字列に変換する。
  tree.map(&:join).join("\n")
end

puts create_tree(10)

#          *
#         ***
#        *****
#       *****?*
#      **&******
#     ******@****
#    *$***********
#   *******$**@****
#  ****@*****@******
# &**?*@****$**@&$**@
#        #####
#        #####
#        #####
#        #####
#        #####

puts create_tree(15)

#               *
#              ***
#             *****
#            *******
#           *@**?***$
#          *?***$*****
#         *****$****&*@
#        &*$***&**$*****
#       **?****?*********
#      ********&*&****@***
#     **$*****$*&**********
#    ************?*&@****?**
#   ********$****?????*?***&*
#  ********?****&*******@*****
# ***@******************?******
#           #########
#           #########
#           #########
#           #########
#           #########
#           #########
#           #########

begin 
  puts create_tree(3)
rescue => e
  puts e.message #=> しょぼくなるのでだめです
end

なかなか見栄えの良いクリスマスツリーができたのではないでしょうか。ちょっと張り切りすぎて、コメントをたくさん書きすぎたのは反省ですね。

それはさておき、クリスマスツリーができたということで、クリスマスイブ生活のクオリティも一層上がったように思います。なおクリスマス当日(日曜日)は休日出勤。サービス残業ならぬサービス出勤で、手当なんぞは夢のまた夢。クリスマスイブ以上に楽しいクリスマスがやってきそうですね。がってむ(´・ω・`)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3