/* ##### #### # # #### # # # # # # # # # # # # # # # # # ###### # # # # # # # # # # # # # # # # # # #### #### #### # # ##### # # ##### ###### # # # # # # # # # # ##### # # ##### # # # # # # # # ###### ##### ##### ## # # # ###### ##### # # # # # # ## # # # # # # # # # # # # # ##### # # # ##### ###### # # # # # ##### # # # # # # # ## # # # # # # # # # # # ###### # # Date : Sat Oct 23 06:05:22 JST 1999 SpecialThanks : Yamashita Junji, Hirooku Tohru Written by : Abiru Eiichi Version : 2.0 <これ以前のバージョンからの変更点> ・ソースが汚かったので書き直しました。 ・ゲーム終了後、任意のキー入力で繰り返し練習できるようにした。 ・ファイル入出力などで例外が発生したときにその旨を  アプレット上に表示するように変更。 */ import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.awt.event.KeyEvent.*; import java.util.*; import java.io.*; import java.net.*; public class TTT extends Applet implements KeyListener{ int lineCount; //問題文ファイルの行数を保持 int currentNum; //現在、何文字目を入力しているかを保持 int missCount; //タッチミスの回数を保持 boolean firstType , lastType , gameOver; //初回と最後の入力が発生したか、ゲームが終了したか否かを保持 boolean missTouch = false; //入力された文字がミスであったか否かを保持 boolean errorFlag = false; //エラー(例外)が発生したか否かを保持 String message , inputString , Filename; //問題文、入力された文字列、読み込むファイルの名前を保持 Date startTime , finishTime; //入力の開始時間と終了時間を保持 double spendTime; //所要時間を保持 char missChar; //今、入力ミスした文字を保持 public void init(){ Filename = getParameter("filename"); addKeyListener( this ); setBackground( Color.white ); try{ //行数カウントのためにファイルを開く URL url = new URL( getCodeBase(), Filename ); URLConnection in0 = url.openConnection(); InputStream in1 = in0.getInputStream(); InputStreamReader in2 = new InputStreamReader(in1,"SJIS"); BufferedReader in3 = new BufferedReader(in2); //問題文ファイルの行数をカウント lineCount = 0; while ( in3.readLine() != null ) lineCount++; in3.close(); } //例外発生時にエラーメッセージを問題文として渡し、エラー発生のフラグを立てる。 catch(java.net.MalformedURLException e) { message = ( e.toString() ); inputString ="設定を確認してアプレットを再始動してください"; errorFlag = true; } catch(java.io.IOException e) { message = ( e.toString() ); inputString ="ファイルの入出力で例外が発生しました。"; errorFlag = true; } gameStart(); } public void gameStart(){ //ゲーム再開の為の変数初期化 firstType = true; lastType = false; missTouch = false; gameOver = false; inputString = ""; currentNum=0; missCount = 0; try{ //問題文を決定するために再度ファイルを開く URL url = new URL( getCodeBase(), Filename ); URLConnection in0 = url.openConnection(); InputStream in1 = in0.getInputStream(); InputStreamReader in2 = new InputStreamReader(in1,"SJIS"); BufferedReader in3 = new BufferedReader(in2); //乱数を発生させて問題文を決定します。 Random rnd = new Random(); int r = rnd.nextInt(); r = Math.abs( r % lineCount ); //nextInt()は負の数も範囲に含むのでMath.abs()は必須なの。 //乱数で発生させた値の行にある文字列を問題文にします。 for ( int i = 0; i <= r; i++) message = in3.readLine(); in3.close(); } //例外発生時にエラーメッセージを問題文として渡し、エラー発生のフラグを立てる。 catch(java.net.MalformedURLException e) { message = ( e.toString() ); inputString ="設定を確認してアプレットを再始動してください"; errorFlag = true; } catch(java.io.IOException e) { message = ( e.toString() ); inputString ="ファイルの入出力で例外が発生しました。"; errorFlag = true; } } public void paint( Graphics g ){ /*フォントサイズは、改行させたいときのY座標値として頻繁に使用するので 変数として宣言しておくとよい*/ final int fontSize = 30; //問題文と入力文字に使用するフォントサイズ final int miniFontSize = 15; //所要時間とタッチミスの結果表示に使用するフォントサイズ final Font miniFont = new Font( "Courier", Font.BOLD, miniFontSize ); final Font textFont = new Font( "Courier", Font.BOLD, fontSize ); final int xpos = 5; //行頭位置のX座標値 final int msg_ypos = fontSize; //問題文のY座標値(1行目) final int inp_ypos = msg_ypos + fontSize; //入力文字のY座標値(2行目) g.setFont( textFont ); //例外が発生したときに色を変えてその旨を表示させます。 if ( errorFlag ){ g.setColor( Color.red ); removeKeyListener( this ); //キーの入力を受け付けなくします。 } else g.setColor( Color.blue ); //問題文の文字列を表示 g.drawString( message , xpos , msg_ypos ); //入力済みの文字列を表示 g.drawString( inputString , xpos , inp_ypos ); //タッチミスが発生した時に色を変化させてその文字を表示させる if ( missTouch ){ g.setColor( Color.red ); int width = getFontMetrics( textFont ).stringWidth( inputString ); g.drawString( new Character( missChar ).toString() , xpos + width , inp_ypos ); } //所要時間とミスタッチの回数を表示 if ( lastType ){ g.setFont( miniFont ); g.setColor( Color.black ); g.drawString( "Time : " + spendTime + " Sec." , xpos , inp_ypos + fontSize ); g.drawString( "Miss : " + missCount , xpos , inp_ypos + fontSize + miniFontSize ); //ゲーム終了後、任意のキー入力を求める表示 g.setColor( Color.red ); g.drawString( "Hit any key... " , xpos , inp_ypos + fontSize + miniFontSize * 3 ); //ゲームが終了したことを示すフラグをたてる。 gameOver = true; } } public void keyTyped( KeyEvent evt ){ char nowInput = evt.getKeyChar(); //今、押されたキーの文字を保持 //一文字目の入力だった場合の処理(開始時間を記録) if ( firstType == true){ startTime = new Date(); firstType = false; } //入力文字が正解だった場合の処理 if ( lastType == false && nowInput == message.charAt( currentNum ) ){ missTouch = false; inputString = inputString + nowInput; if ( message.length() > currentNum ) currentNum++; }else{ //入力文字が不正解だった場合の処理 if ( lastType == false && nowInput != message.charAt( currentNum ) ){ missTouch = true; missChar = nowInput; missCount++; } } //最後の文字が入力された場合の処理(終了時間を記録し、所要時間を計算) if ( currentNum >= message.length() && lastType == false ){ lastType = true; finishTime = new Date(); spendTime = ( finishTime.getTime() - startTime.getTime() ) /1000.00; } //結果表示後に任意のキーが押されたら次のゲームを開始する。 if ( gameOver ) gameStart(); repaint(); } public void keyPressed( KeyEvent evt ){ } public void keyReleased( KeyEvent evt ){ } }