#!/usr/bin/env ruby # -*- coding: utf-8 -*- #trrでなかなか成長しないのでいっそのこと、、っていうか。うーん? #まあとにかく。自作ならやる気出るだろう。という、実に謎い思考回路。 #ところがどっこい、結局trrを参考にしているという矛盾。^^;むう。。 #このプログラムはタイピングです。 #自分にとって楽しく、または便利なタイピングが作りたいと思い、こうなりました。 #これを作ろうと思ったのは、私のような、タイピングを速くなりたいけど、何が課題かわからない人に #役に立つものを作りたかったからです。 #きっかけは、自分がタイピングサイトを探していたときに、こんな機能があったらいいなと感じたことです。 #作ろうとした機能、考えた機能は、(つまり「あったらいいな感じた機能」) #*自分のペースで練習ができる、ジャンル選択、回数選択 #*打つのにかかった時間、各キーでのミス回数、最高得点中何点で何%取れているのかの結果表示 #*CSVからランダムに出題、選択式のお題 #*楽しく打てる内容(早口言葉、メソッド名など) #*アルファベットやローマ字をランダムに羅列して出題したり(予測したら負けモード)、 # ミスした文をやり直す(パーフェクト出すまで帰れませんモード)「正確さトレーニング」機能 #*とにかく文章を打ちまくる「素早さトレーニング」機能(ミスしても次に行く) #*自分の打った文がお題になる「自習」機能 #です。100行までということで、かなり不完全で不自然な仕上がりですが、かろうじて #どうしても作りたかった機能は実装できました。 #今回実現できたのは、 #*ジャンル選択、回数選択 #*楽しく打てる内容 #*ミス回数、どのキーでミスしたのかわかる # 現状 #この時点では、点数も出ないし、結果が不十分な印象です。 #また、表示がずれたり、入力で想定外の値が入れられるとエラーや期待していない値が #渡されたり、改善点が大量にあります。まだまだ完璧とは言えないです。 #今のアピールポイントは、csvを規則に従って書けば、問題がカスタマイズできることです。 #規則はソースコードとcsvを見れば割とすぐに理解できると思います。具体的には、 #まず、typing-texts.csvを開きます。 #アルファベット、記号でないものが含まれるジャンルの場合、ヘッダーに()をつけます。 #カッコの内容を変更した、アルファベット版も用意します。 #ヘッダーのカッコ以外の部分は元とおなじにしてください。内容ができたら、 #typing-texts-utu.csvにヘッダーの()部分を消したアルファベット版のデータを貼り付けてください。 #typing-texts.csvは画面に表示する、見かけ上打つ文字です。 #typing-texts-utu.csvは、実際にキーボードから打っている文字です。 #うまく書き込むと、新たなジャンルとして遊べるようになります。 # 他におもいついたアイデア #一つは言葉の力で励ましたり勇気を出したりできるようなプログラムです。具体的には、 #診断形式で、今その人に響く言葉を導こうとするものです。 #他には、音で時間がわかる時計や、密集した字を行ごとに分けた表示で見やすくするなどです。 require 'curses'; include Curses require 'csv' sentence = CSV.read("typing-texts.csv" , :headers => true)#タイピング本文 sentence_utu= CSV.read("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("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") win.addstr("ジャンルを決めてください(複数選択可能、qで入力終了\nもう一度選ぶと選択解除)\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("\nなにか打つと開始!!\n") win.getAns; refresh; win.setpos(0,0) 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 keikajikan = (Time.now.to_i) - 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 ensure close_screen end