10進数を2進数と16進数に変換する

"%b" % num
"%x" % num

ってな具合に、フォーマットを指定すればすごい簡単なのだけど、
それじゃつまらないのでそれ以外の方法でやってみた。
2進数はまあこれで大丈夫。
でも16進数はうまくいってない・・・。
hex << 'F' で hex の末尾に 'F' が追加されるはずなのに、
なぜか '15' が追加されている。。
なんで・・・。

class Fixnum
  def to_b
    num = self
    bin = ""

    while num > 0
      bin << (num % 2).to_s
      num /= 2
    end
    
    bin.reverse
  end

  def to_x
    num = self
    hex = ""

    while num > 0
      temp = (num % 16).to_s
      
      case temp
      when 10
        hex << 'A'
      when 11
        hex << 'B'
      when 12
        hex << 'C'
      when 13
        hex << 'D'
      when 14
        hex << 'E'
      when 15
        hex << 'F'
      else
        hex << temp.to_s
      end
          
      num /= 16
    end
    
    hex.reverse
  end
end


while line = gets
  line.chomp!
  next unless /\d+/ =~ line
  num = line.to_i
  puts num.to_b
  puts num.to_x
  puts
end

追記

このエントリを書いてから、
貼り付けたソースを見てみたらすぐに何が原因か分かった。
ぐあーなんておれは馬鹿なんだーーっ!

class Fixnum
  def to_b
    num = self
    bin = ""

    while num > 0
      bin << (num % 2).to_s
      num /= 2
    end
    
    bin.reverse
  end

  def to_x
    num = self
    hex = ""

    while num > 0
      temp = (num % 16) #.to_s ← ここで .to_s してるのが問題だった!!
      
      case temp
      when 10
        hex << 'A'
      when 11
        hex << 'B'
      when 12
        hex << 'C'
      when 13
        hex << 'D'
      when 14
        hex << 'E'
      when 15
        hex << 'F'
      else
        hex << temp.to_s
      end
          
      num /= 16
    end
    
    hex.reverse
  end
end


while line = gets
  line.chomp!
  next unless /\d+/ =~ line
  num = line.to_i
  puts num.to_b
  puts num.to_x
  puts
end

追記の追記

コメントから、進数の変換にはInteger#to_sが使えることを知った。
以下はマニュアルからコピペしたもの。
色々とやり方はあるもんだなぁー。TIMTOWTDI

p 10.to_s(2)    # => "1010"
p 10.to_s(8)    # => "12"
p 10.to_s(16)   # => "a"
p 35.to_s(36)   # => "z"

ヒットアンドブローのスクリプトができた

でもひどいコードかも。。
ヒットアンドブローは、コンピュータの用意した数字の並びを当てるゲーム。
コンピュータは、こちらが考えた数字の並びと自分のものを比較して、
次の2つのヒントをくれる。

  • HIT: 数字も場所も合っているものの数
  • BLOW: 数字は合っているが場所は合っていないものの数

例えば、コンピュータの用意した数字の並びが4278で、
プレイヤーが考えた数字が4321だったときは、HIT:1 BLOW:1となる。
全部をHITにできれば勝ち。
また、今回は同じ数字を使ってもいいようにしてみた。
(そのせいで手こずった・・・。)

=begin
ヒットアンドブロー

<概要>
コンピュータの用意した数字の並びと同じ数字の並びをつくれば勝ち
HIT: 数字も場所も合っている
BLOW: 数字は合っているが場所は合っていない

<usage>
  > ruby hit-and-blow.rb [size]
  [size]でいくつの数字の並びなのかを指定できる(デフォルトは4)
=end


# 複数の数字の管理をする
class Numbers
  def initialize(size = 4)
    @size = size.to_i
    @numbers = Array.new # コンピュータの用意する数字の並び

    @size.times{
      @numbers << rand(10)
    }
  end
  
  # カードの表示
  def disp
    puts "com> #{@numbers}"
  end

  # コンピュータの用意した数字の並びとプレイヤーの数字の並びを比較する
  def compare(ply)
    # コンピュータとプレイヤーの用意した各数字の間にリンクを考える
    # 対応する数字同士はリンクする
    links = Array.new
    @size.times{
      link = Hash.new
      link['to'] = nil
      link['type'] = nil

      links << link
    }
    
    @size.times{|c|
      @size.times{|p|
        # toがpで、typeがhitのLinkが存在する場合はply[p]をパス
        next if links.detect{|l| l['to'] == p and l['type'] == 'hit'}
        
        if @numbers[c] == ply[p].to_i
          links[c]['to'] = p

          if c == p
            if l = links.detect{|l| l['to'] == p and l['type'] == 'blow'}
              l['to'] = l['type'] = nil
            end
                            
            links[c]['type'] = 'hit'
            break # 'hit'が分かったら、そのcom[c]の処理は終了
          else
            links[c]['type'] = 'blow'
          end
        end
      }
    }

    hit = blow = 0
    links.each{|l|
      hit += 1 if l['type'] == 'hit'
      blow += 1 if l['type'] == 'blow'
    }

    puts "  HIT:#{hit} BLOW:#{blow}"
    
    if hit == @size
      puts "Congratution!!"
      exit
    end
  end
end


size = ARGV.shift || 4
com = Numbers.new(size)
puts "#{size}つのランダムな数字の並びを当ててください。"

loop{ 
  print "ply> "
  line = gets
  line.chomp!
  exit if /^e/ =~ line
  com.disp if /^d/ =~ line
  com = Numbers.new if /^r/ =~ line
  unless /^\d{#{size}}$/ =~ line
    puts "#{size}つの数字を指定してください。"
    next
  end
  
  ply = line.split(//) # プレイヤーの用意する数字の並び
                       # 比較のために配列にする必要がある
  com.compare(ply)
}


今回、僕は自分で思っているよりもプログラムが書けないことに気づいた。
もっと色々自分で考えて書いてみないとダメだと思った。
だからもっと色々自分で考えて書いてみようと思う。

今月のカレンダーを出力

わりとキレイに書けたような気がする。
たのしいRubyの練習問題にも似たようなのあったなぁ。

require "date"

def calendar
  today = Date.today
  fday = Date.new(today.year, today.month, 1)
  lday = Date.new(today.year, today.month, -1)
  # Date#wday は週の何日目かを表す。日曜が0。月曜を0にしたいので-1する。
  wday = fday.wday - 1
  # 日曜日の場合は-1なので6に変更する。
  wday = 6 if wday == -1

  puts today.strftime("%Y %B").center(20)
  puts "--------------------"
  puts "Mo Tu We Th Fr Sa Su"
  print "   " * (wday)
  fday.day.upto(lday.day){|d|
    print "%2d " % d
    wday += 1
    if wday == 7
      puts
      wday = 0
    end
  }
  
end

calendar


実行結果はこんな感じ。

     2007 June
--------------------
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

RSSをHTMLに変換

指定されたRSSのitemのtitleをcheckbox付きのHTLで出力する。
HTMLが整形されてないのが気になるけど、
とりあえずこれはこれでほぼ完成。
連携するCGIの方は、まだ何もできていないので完成したとは言えない。

require 'rss'
require 'kconv'

def print_items(rss)
  html = ""

  html << %Q(<form method="GET" action="hoge.cgi">\n)
  item_num = 0
  rss.items.each{|item|
    html << %Q(<input type="checkbox" name="item" value="#{item_num += 1}">)
    html << %Q(#{item.title}<br />\n)
  }
  html << %Q(<input type="submit"><br />\n)
  html << %Q(</form>\n)

  html

  ## 標準出力用
  #  rss.items.each{|item|
  #    puts "#{item.title}: #{item.description}".tosjis
  #  }
end

def output_file(filename, rss)
  html = ""

  html << "<html><body>\n"
  html << "<ul>\n"
  html << print_items(rss)
  html << "</ul>\n"
  html << "</body></html>"
  
  html = html.tosjis

  open(filename, 'w'){|f|
    f.print(html)
  }

  print html
end

rss_src = ARGV[0] || 'http://b.hatena.ne.jp/hotentry?mode=rss'
# 第二引数にtrueを与えると、バリデーション付きでパースする。
rss = RSS::Parser.parse(rss_src, true)
filename = __FILE__.sub(/\.rb$/, '.html')

print_items(rss)

output_file(filename, rss)


Sign up | Tumblrを使って何かしようとしてるのは内緒。
読み方はたんぶらー?たんぶるる?
僕はたんぶらーと読みたい。
screenshot