Newer
Older
Ruby / typing.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

#trrでなかなか成長しないのでいっそのこと、、っていうか。うーん?
#まあとにかく。自作ならやる気出るだろう。という、実に謎い思考回路。
#ところがどっこい、結局trrを参考にしているという矛盾。^^;むう。。


#このプログラムはタイピングです。
#自分にとって楽しく、または便利なタイピングが作りたいと思い、こうなりました。
#これを作ろうと思ったのは、タイピングを速くなりたいけど、何が課題かわからない人に
#役に立つものを作りたかったからです。
#作ろうとした機能、考えた機能は、
#*打つのにかかった時間、各キーでのミス回数、最高得点中何点で何%取れているのかの結果表示
#*CSVからランダムに出題、選択式のお題
#*楽しく打てる内容(早口言葉、メソッド名など)
#*アルファベットやローマ字をランダムに羅列して出題したり(予測したら負けモード)、
# ミスした文をやり直す(パーフェクト出すまで帰れませんモード)「正確さトレーニング」機能
#*とにかく文章を打ちまくる「素早さトレーニング」機能(ミスしても次に行く)
#*自分の打った文がお題になる「自習」機能
#です。100行までということでかなり不完全な仕上がりですが

require 'curses'
include Curses
require 'csv'
sentence    = CSV.read("happyou/typing-texts.csv" , :headers => true)#タイピング本文
sentence_utu= CSV.read("happyou/typing-texts-utu.csv",:headers => true)
menu_sentakusi ={1=>"play",2=>"option",3=>"practice"}
play_sentakusi =sentence.headers
type_list =[] #打つ内容を呼び出すための文字列を格納する
kaisu = 0   # 問題数を指定
miss_now = nil      # 各文字でミスったか否か
miss_all = []      # 全部で何回、どの字でミスったか
class Window
  @@numbers = CSV.read("happyou/futaketa-alpha.csv",:headers => true)
def putSentakusi(nani,zip = @@numbers.headers)
  for na,s in nani.zip(zip)
    self.addstr(sprintf("%s => %s\n",s,na))
  end
  self.refresh
end
def getAns()
  self.addstr("入力:")
  self.refresh
  while true
    a = getch 
    if a == "q"
      return "q"
    elsif @@numbers[a]
      return @@numbers[a].join.to_i
   end
  end
end
def addstr_sousyoku(nani,str)
  nani.each{|n|self.attron(n)}
               self.addstr(str)
  nani.each{|n|self.attroff(n)}        
end
end

init_screen
noecho
cbreak
begin
  win = Window.new(32,60,10,10)
  win.addstr("タイピングです。\nメニュー\n番号を入れてください\n")
  win.putSentakusi(menu_sentakusi.values)
  choice =  win.getAns
  win.setpos(0,0)
  case menu_sentakusi[choice]
  when "play"
    win.addstr("ジャンルを決めてください(複数選択可能、qで入力終了\n")
    win.addstr("もう一度選ぶと選択解除)\n")#refreshはquestionに
    cursor_position =[win.cury,win.curx]
    while true
      win.setpos(*cursor_position) ##* s e t "p  o" s *##setopsって書くとそのエラーすっごく見つけづらい
      win.putSentakusi(play_sentakusi)
      choice = win.getAns
      break if choice == "q"
      play_choice = play_sentakusi[choice-1]
      already_chosen = (type_list.include?(play_choice))
      if play_choice
        type_list << play_choice #打つ内容に紐付いた文字を格納
        type_list.delete(play_choice)if already_chosen 
      end
      win.addstr(sprintf("\n選択済み:%s\n",type_list.join(",")) )
      win.refresh
    end
    odai_display_list = type_list.collect{|type|sentence[type]}.flatten.compact
    odai_utu_list = type_list.collect{|type|sentaku = type.sub(/\(.*?\)/,"").to_s;sentence_utu[sentaku]}.flatten.compact
    odai_length = odai_display_list.length  # 問題数を拾っている
    win.clear
    win.addstr(sprintf("何問やりますか(最大%d問)\n",odai_length))
    until kaisu != "q" && kaisu >= 1 && kaisu <= odai_length 
      kaisu = win.getAns
      win.setpos(1,0)
    end                  
    win.addstr(kaisu.to_s)
    win.addstr("\nなにか打つと開始!!\n")
    win.getAns
    refresh
    number = 0  #お題の番号 #文字の様子 -> 入力前太字。入力後普通、ミス下線
    start_time = Time.now.to_i
    kaisu.times do
      number  = rand(0..(odai_length-1) )                   #この回のループで出すお題の番号
      odai = {display: odai_display_list[number],utu: odai_utu_list[number]}#この回のループで出すお題のハッシュ
      ch_count = 0 
      win.addstr_sousyoku([A_BOLD],odai[:display]+"\n")
      cursor_position =[win.cury,win.curx]
      win.addstr_sousyoku([A_DIM,A_BOLD],odai[:utu])
      while odai[:utu].length > ch_count
        win.setpos(cursor_position[0],(cursor_position[1])+ch_count);win.refresh
        input = getch 
        if input == odai[:utu][ch_count]
          win.addch(odai[:utu][ch_count])unless miss_now
          win.addstr_sousyoku([A_UNDERLINE],odai[:utu][ch_count])if miss_now
          ch_count += 1 ;miss_now = false ; win.refresh
        else
          miss_all << odai[:utu][ch_count] ; miss_now = true
        end
      end
      win.clear ; odai_length -= 1
      odai_display_list.delete_at(number)#2回出題を防ぐ
      odai_utu_list.delete_at(number)##for最終行##
    end
    finish_time = Time.now.to_i
    keikajikan = finish_time - start_time
    miss = miss_all.tally
    win.addstr_sousyoku([A_BOLD],"結果\n")
    win.addstr(sprintf("かかった時間: %d秒(1問あたり: %d秒),ミス: %d回\nミスの詳細\n",keikajikan,keikajikan/kaisu,miss_all.length))
    win.putSentakusi(miss.values,miss.keys)
    refresh
  else
    win.addstr("未実装か存在しない選択肢です。\n")
    win.refresh
  end
ensure
  close_screen
end