CodeZine(コードジン)

特集ページ一覧

RubyのCursesを使ってコンソールを制御する

作って覚えるRuby再入門 第1回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/01/08 12:00

ダウンロード ソースコード (3.8 KB)

目次

コンソールライブラリで遊んでみる

 最後に応用例として、Cursesを使ったゲームを作ってみたいと思います。どんなゲームを作るかというと、大昔からある「ハングマン」というゲームです。ハングマンというのは、出題者(今回はコンピュータ)が英単語を一つ問題として決めておき、解答者(人間)は問題で使われている(と思う)文字を一文字ずつ入力していきます。一定回数内の入力で正解の英単語が当てられれば解答者の勝ちです。正解できなければ出題者の勝ちになります。

 今回作るソースは全部で3本です。

  • hanging.rb メインプログラムです。
  • mondaiwind.rb 問題を出力するウィンドウを表現します。
  • mondai.rb 問題の英単語を表現します。

 なおこのプログラムを動作させるには"Hpricot"というライブラリが必要ですのでRubyGemsでインストールしてください。このライブラリについては後述します。

インストール方法
gem install hpricot

 まずメインプログラム(hanging.rb)です。

 大まかな流れとしては、問題作成→表示→入力待ち→正解or解答回数終了となります。メインプログラムは流れを作っているだけで細かな部分は他のクラスに任せています。

 Curses::getchはユーザーの入力を受け付けるメソッドですが、結果は文字コード(Integerオブジェクト)で返されます。このままでは扱いにくいのでchrメソッドで文字列に変換しています。

hanging.rb
require "mondai"
require "mondaiwind"
require "curses"
include Curses

init_screen
cbreak #バッファリングモードオフ
begin
  puts "making mondai....."
  # 問題文の生成
  m = Mondai.new
  mondai = m.make

  # 問題文の表示
  mon_win = MondaiWind.new(stdscr)
  mon_win.display(mondai)
  
  # 解答入力待ち
  max_input = mondai.length * 2
  # 問題の長さの2倍まで入力を試せる
  max_input.times do 
    if m.all_collect?
      # 全文字正解した場合「SEIKAI!」と表示して終了
      mon_win.seikai
      break
    end
    input_str = getch.chr
    addstr(input_str)
    if index = m.check(input_str)
      # 入力した文字が正解ならその文字を正解の位置に表示
      mon_win.turn_up(input_str,index)
    end
  end
  getch
ensure
  close_screen
  # 最後に解答を表示
  puts "answer=>#{mondai}"
end

 次は、問題出力用のウィンドウクラス(mondaiwind.rb)です。

 これまで説明した事を少し応用して組み立てています。

mondaiwind.rb
require "curses"

class MondaiWind
  def initialize(main_wind) # 初期化(newする時に呼ばれる)
    max_y = main_wind.maxy
    max_x = main_wind.maxx
    # メインウィンドウの高さを少し小さくしたサブウィンドウを作成
    @window = main_wind.subwin(max_y-3,max_x,0,0)
    # サブウィンドウの境界線を描く
    @window.box(?|,?-,?*)
    # 解答入力欄を作成
    main_wind.setpos(@window.maxy,0)
    main_wind.addstr("input=>")
  end

  def display(mondai_str) # 問題文の表示
    @mondai_str = mondai_str
    @mondai_y = @window.maxy/2
    @mondai_x = (@window.maxx/2)-(mondai_str.length/2)
    # サブウィンドウのちょうど真ん中に問題文を表示
    @window.setpos(@mondai_y,@mondai_x)
    # 問題文を表示(最初は全部"_"を出しておく)
    @window.addstr("_" * @mondai_str.length)
    @window.refresh
  end
  
  def turn_up(moji_str,index) # 正解となった文字を表示
    # カーソルを、正解した文字の位置に移動
    @window.setpos(@mondai_y,@mondai_x+index)
    # '_'の代わりに正解した文字を表示
    @window.addstr(moji_str)
    @window.refresh
  end

  def seikai # 全文字正解になったときに呼ばれる
    @window.setpos(@mondai_y + 1,@mondai_x)
    @window.addstr("SEIKAI!!")
    @window.refresh
  end
end

 最後に問題文クラス(mondai.rb)です。

 ここは少し複雑なので多めにコメントを入れておきました。

 HpricotというのはRubyでHTMLを解析するためのライブラリです。簡単に使える上に非常に高速なのでお勧めです。解析するだけでなくプログラム上で書き換えたものを再びHTMLとして出力する機能も備えています。

mondai.rb
require 'rubygems'
require 'hpricot'
require 'open-uri'

class Mondai
  def make
    # 問題となる英単語を文字列として取得
    mondaibun = get_from_remote
    # その文字列を一文字ずつ分割して配列にする
    @mondai = mondaibun.split(//)
    # 正解数を初期化
    @collect_num = 0
    # 問題文(文字列)を返却
    return mondaibun
  end

  def check(input_c)
    # 入力された文字が問題文の配列の中にあるか探査
    pos = @mondai.index(input_c)
    if pos
      # 該当した場合はその箇所を空文字にする(再度ヒットしないように)
      @mondai[pos] = ""
      @collect_num +=1 # 正解数を増やす
    end
    # 入力された文字の配列中の位置を返却
    # 該当しなかった場合はnilを返却
    return pos
  end

  def all_collect?
    # 正解数が問題文の長さと同じかそれ以上なら全文字正解
    return (@collect_num >= @mondai.length)
  end

  private # これ以降のメソッドは外からは見えないよ宣言

  def get_from_remote
    # del.icio.usのタグ一覧からページを取得
    doc = Hpricot(open("http://del.icio.us/tag/"))
    # ページ内からタグに相当する部分のみを切り出す(結果は配列)
    arr = doc.search("div.alphacloud a")
    # 沢山あるタグの中から一つランダムで選び返却する
    return arr[rand(arr.size-1)].inner_html
  end
end

まとめ

 今回は、Rubyの練習課題としてコンソールアプリを作り始めました。

 Cursesライブラリの準備の仕方や使い方、そしてその応用例を説明しました。

 次回はもう少し大きなコンソールアプリを作ってみたいと思います。

参考資料



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:作って覚えるRuby再入門

著者プロフィール

  • 越智 理夫(オチ マサオ)

    株式会社カサレアル プロフェッショナルサービスセンター所属。エンジニア向けトレーニングコースの開発および講師を行う。専門はJava,Ruby,OOAD,DOA,テスト駆動開発など。最近二歳の娘にこき使われている。

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5