HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0517
ikaタイピングソフトの正誤判定7解決


ika

リンク

2020/5/17(Sun) 03:25:12|NO.90577

アルファベットが一文字ずつ表示され、時間内に正解を押せたら次のアルファベットを表示、
間違えたり時間切れの場合はアルファベットを赤くして次のアルファベットを表示するという
タイピングソフトを制作しています。

しかし、正解不正解にかかわらずキーボードが押されたら不正解の判定になってしまいます。
正しく動作させるにはどのようにすればいいですか?
また、問題が終了したら「クリア」のダイアログを表示させたいのですが、配列の要素が無効と表示されます。(*typemissのところ)
この原因も説明していただきたけると嬉しいです。


#uselib "KERNEL32.DLL" #func Sleep "Sleep" sptr notesel buf noteload "mondai.txt" ;ファイル読み込み noteget time, 0 noteget moji, 1 displaytime=int(time) ;文字列型を整数型に変換 screen 0,500, 400 sdim mondai, 50, 2 mondai=strlen(moji) repeat mondai;アスキーを取得 asc(i) = peek(moji,cnt) ;配列asc()にA~Zのアスキーを格納 i++ loop onkey gosub *typein *main for i, 0, mondai, 1 ;mondaiとアスキーを比較 letter=strmid(moji,i,1) if i<7 {pos 140+33*i, 5 }else :if 7 <=i&i<14 {pos 140+33*(i-7), 40 ;改行の作業 }else :if 14<=i&i<21 {pos 140+33*(i-14), 75 }else :if 21<=i&i<28 {pos 140+33*(i-21), 110 }else :if 28<=i&i<35 {pos 140+33*(i-28), 145 } gosub *ascii Sleep displaytime await 0 ;時間待ち next *typein ;正誤判定 cursor=0 a=0:a=peek(mondai,cursor) if a!=iparam:goto *typemiss len=strlen(mondai) cursor=cursor+1:if cursor<len : return goto *win stop *mba ;アスキーが65で黒Aを表示する buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100, 35, 28, 30 return *mbb buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100+34, 35, 28, 30 return 以下zまで同様の操作 *owari end; *ascii if asc(i)=65{ gosub *mba }else :if asc(i)=66{ gosub *mbb 以下zまで同様の操作 return *typemiss if asc(i)=65{ gosub *mra }else :if asc(i)=66{ gosub *mrb 以下zまで同様の操作 }else{ goto *win } return *win onkey 0 dialog "クリア" end

※mondai.txtには1行目に制限時間、2行目以降に問題が書かれています。



この記事に返信する


あらや

リンク

2020/5/17(Sun) 05:41:25|NO.90578

ファイルの内容が不明なので軽く見ただけですが
始めの段階で不明な箇所が。。。

sdim mondai, 50, 2 mondai=strlen(moji) repeat mondai;アスキーを取得 asc(i) = peek(moji,cnt) ;配列asc()にA~Zのアスキーを格納 i++ loop
変数mondaiを文字列型で定義しているのに
次の行で整数型の数値を代入しているのは意味が無いですね。

*typeinの中でpeekやstrlenで変数mondaiの文字コードを読み込もうとしていますが
上記の理由で整数型として上書きされているので文字列としては扱えません。



*typemiss内のgosub *mraと*mrbに関しては
誤字かもしれませんが存在すらしていないので
実行確認ができません。

*mraと*mrbが誤字だとしてもmondai.txtとmondai300x100.jpgが無ければ
実行確認が出来ません。

ソースをたどるだけでは時間が掛かるので
少し書き換えて外部ファイルが不要な形のソースにしていただけると
ほかにもおかしな箇所を指摘しやすくなると思います。



ika

リンク

2020/5/18(Mon) 02:44:49|NO.90586

ご回答ありがとうございます。指摘された箇所を自分なりに直し、多少改良もしてみました。

・変数mondaiを削除し、文字数を格納する変数mojisuuを新たに作成しました。
・*mraと*mrbは省略する際に間違って消してまってました。申し訳ありません。

まだ意味不明な箇所がありましたら、また指摘していただけますか? また、やはり正誤判定の点は解決できていません。


notesel buf noteload "mondai.txt" ;ファイル読み込み noteget time, 0 ;秒数を文字型でtimeに保存 noteget moji, 1 ;問題を文字型でmojiに保存 displaytime=int(time) ;秒数を整数型に変換 mojisuu=strlen(moji);問題の文字数をmojisuuに保存 screen 0,500, 400 ;スクリーンサイズ i=0 ;mojiのアスキーを取得作業 repeat mojisuu ;文字数分、繰り返す asc(i) = peek(moji,cnt) ;配列asc(i)にmojiのアスキーを格納 i++ ;i=i+1 loop onkey gosub *typein *main ;mojiとアスキーを比較し、アスキーに対応した画像の用意 for i, 0, mojisuu, 1 ;初期値0, mojisuuの数だけ繰り返す, i+1する if i<7 {pos 140+33*i, 5 }else :if 7 <=i&i<14 {pos 140+33*(i-7), 40 ;改行の作業 }else :if 14<=i&i<21 {pos 140+33*(i-14), 75 }else :if 21<=i&i<28 {pos 140+33*(i-21), 110 }else :if 28<=i&i<35 {pos 140+33*(i-28), 145 } gosub *ascii Sleep displaytime await 10 ;時間待ち next *typein ;正誤判定 cursor=0 a=0 a=peek(moji,cursor) ;aにmojiのcursor番目のアスキーを保存 if a!=iparam ;押されたキーとaが等しくなければ goto *typemiss ;typemissへ移動 len=strlen(moji) cursor++ if cursor<len ;問題が残っていたら return goto *win stop *mba ;アスキーが65で黒Aを表示する buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100, 35, 28, 30 return *mbb buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100+34, 35, 28, 30 return . . 以下zまで同様の操作 . *mbz buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 815+36*4, 35, 32, 35 return *mra ;赤A表示する buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100, 97, 28, 30 return *mrb buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 100+34, 97, 28, 30 return . . 以下zまで同様の操作 . *mrz buffer 1 picload "mondai300x100.jpg" gsel 0, 1 gcopy 1, 815+36*4, 97, 32, 35 return *owari end; *ascii if asc(i)=65{ gosub *mba }else :if asc(i)=66{ gosub *mbb . . 以下zまで同様の操作 . }else :if asc(i)=90{ gosub *mbz }else{ goto *win } return *typemiss if asc(i)=65{ gosub *mra }else :if asc(i)=66{ gosub *mrb . . 以下zまで同様の操作 . }else :if asc(i)=90{ gosub *mrz }else{ goto *win } return *win onkey 0 dialog "終了" end


※mondai.txtには1行目に制限時間、2行目以降に問題が書かれています。
※mondai300x100.jpgにはアルファベットと数字の赤と黒の画像が並んでいて、これをgcopyで切り取って問題を表示しています



あらや

リンク

2020/5/18(Mon) 05:27:20|NO.90587

>※mondai.txtには1行目に制限時間、2行目以降に問題が書かれています。
>※mondai300x100.jpgにはアルファベットと数字の赤と黒の画像が並んでいて、これをgcopyで切り取って問題を表示しています
いえファイル内容の説明ではなく、
ファイル自体が不要なソースにして欲しかったのですが。。。

// 例 buf = "5000\nABCDEF"; mondai.txtを文字列で代用 buffer 1, 400, 60, 0; mondai300x100.jpgを代用 font msgothic, 30 mes "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 黒文字 color 255, 0, 0 mes "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 赤文字



それはさておき、ざっと見て気付いたおかしな箇所を指摘させていただきます。

>*typein ;正誤判定
> cursor=0
> a=0
> a=peek(moji,cursor) ;aにmojiのcursor番目のアスキーを保存
> if a!=iparam ;押されたキーとaが等しくなければ
> goto *typemiss ;typemissへ移動
> len=strlen(moji)
> cursor++
> if cursor<len ;問題が残っていたら
> return
> goto *win
> stop

キー入力された時に『*typein』に飛ぶわけですが
最初にcursor=0としているので、
何問目であろうと最初の文字と正誤判定しています。

そしてif文の書き方が、間違っています。
複数行で書く場合{}このカッコを使わなければいけません。

if a!=iparam { ;押されたキーとaが等しくなければ goto *typemiss ;typemissへ移動 } len=strlen(moji) cursor++ if cursor<len { ;問題が残っていたら return }
カッコを無しで複数行にすると、
ifの条件に一致しても不一致でもifの次の行が実行されます。

もしくはif文を一行で書く場合はコロンを使用します。

if a!=iparam : goto *typemiss ;typemissへ移動 len=strlen(moji) cursor++ if cursor<len : return



あと間違いではないのですが、
*mba、*mbb……*mbz
*mra、*mrb……*mrz
これらに共通する無駄な処理として
> buffer 1
> picload "mondai300x100.jpg"
> gsel 0, 1
この画像読み込みは最初にscreenの前に一度やるだけで良いのではないでしょうか。

buffer 1 picload "mondai300x100.jpg" // screen命令を使った段階で描画対象がID 0になるのでgselは不要 screen 0,500, 400 ;スクリーンサイズ

さらに、一文字ずつ別の処理をしなくても
文字幅が一定になるように画像を用意しておけば
計算でgcopyの位置を算出できるのではないでしょうか。

*ascii // 黒文字(マイナス65は最初の文字Aの文字コード) gcopy 1, 100+(asc(i)-65)*文字幅, 35, 28, 30 // 大体このような感じの計算 return *typemiss // 赤文字 gcopy 1, 100+(asc(i)-65)*文字幅, 97, 28, 30 return



ika

リンク

2020/5/18(Mon) 21:51:42|NO.90597

ご回答ありがとうございます。アドバイス通りにアルファベットの横幅が全て同じ大きさのフォントにした画像を用意して、計算で等間隔に並べるようにしたら250行も省略できました。
あれから少し考えて、*typein の cursor=0 も消し、念のためタイピングが正解したときのラベルを用意してみましたが、どのキーボードを押しても不正解になるという結果は変わりませんでした。

やはりcursorの使い方が間違っているのでしょうか?
自分としては、cursorの初期値は0で、一周するたびに1ずつ増えて、cursorが文字数(mojisuu)と同じ値になったら終了する。。。というのを想像しています。

質問用に外部ファイルを使わない形にするには少し手間取ってて、申し訳ありませんがもう少し待っていただけますか? 次に質問するときには完成するようにします。


#uselib "KERNEL32.DLL" #func Sleep "Sleep" sptr notesel buf noteload "mondai.txt" ;ファイル読み込み noteget time, 0 ;秒数を文字型でtimeに保存 noteget moji, 1 ;問題を文字型でmojiに保存 displaytime=int(time) ;秒数を整数型に変換 mojisuu=strlen(moji);問題の文字数をmojisuuに保存 buffer 1 picload "mondai1400x900.jpg" screen 0,500, 400 ;スクリーンサイズ i=0 ;mojiのアスキーを取得作業 repeat mojisuu ;文字数分、繰り返す asc(i) = peek(moji,cnt) ;配列asc(i)にmojiのアスキーを格納 i++ ;i=i+1 loop onkey gosub *typein *main ;mojiとアスキーを比較し、アスキーに対応した画像の用意 for i, 0, mojisuu, 1 ;初期値0, mojisuuの数だけ繰り返す, i+1する if i<7 {pos 140+30*i, 10 }else :if 7 <=i&i<14 {pos 140+30*(i-7), 60 ;改行の作業 }else :if 14<=i&i<21 {pos 140+30*(i-14), 110 }else :if 21<=i&i<28 {pos 140+30*(i-21), 160 }else :if 28<=i&i<35 {pos 140+30*(i-28), 210 } gosub *ascii Sleep displaytime await 10 ;時間待ち next *typein ;正誤判定 a=0 a=peek(moji,cursor) ;aにmojiのcursor番目のアスキーを保存 if a=iparam{ goto *typecorrect ;押されたキーとaが等しければtypecorrectへ }else{ goto *typemiss ;間違ってたらtypemissへ } *ascii // 黒文字 gcopy 1, 35+(asc(i)-65)*46,150,28,40 return *typecorrect cursor++ if cursor<mojisuu : return : else : goto *win return *typemiss // 赤文字 gcopy 1, 35+(asc(i)-65)*46,265,28,40 cursor++ if cursor<mojisuu : return : else : goto *win return *win onkey 0 dialog "終了" end



あらや

リンク

2020/5/18(Mon) 23:10:44|NO.90598

>質問用に外部ファイルを使わない形にするには少し手間取ってて、申し訳ありませんがもう少し待っていただけますか?
待つのは構いませんが、
とりあえず実行確認が出来る範囲で良いので、
正確な画像にする必要はありませんよ。

例で出したmesを使ったバッファ程度でも問題ありませんし、
それに合わせてgcopyの位置やサイズに合わせる必要がありますが。。。

なんなら画像ではなく文字をそのまま表示する形でも問題ありません。



今回気付いた範囲で指摘させていただきます。

『*main』のforループの後に何も書かれていないので
forループ完了後に『*typein』に続いてしまい、
何も入力されていないのでそのまま『goto *typemiss』に飛び、
変数iの値が配列の範囲を超えてしまうため
gcopyでエラーが発生してしまいます。

forループの後『*win』など、終了処理を行なうラベルに飛ばすべきかと。



Sleep関数に関して、
onkeyのジャンプはwait、await、stopのどれかのウェイト中に飛ぶのですが、
Sleep関数はジャンプはしないものの入力情報はスタックに貯まるようです。

例えば問題の文字列が『ABC』の3文字だった場合、
初回のSleep中に何かのキーを3回以上入力すると
awaitに入った瞬間に一瞬で3文字全ての正誤処理が行なわれて即座に終了してしまいます。

何かしらSleepを使わない方法を考えた方が良いかもしれません。

>どのキーボードを押しても不正解になるという結果は変わりませんでした。
これは同じくSleep関数のスタックが関係しているのかもしれません。

逆に制限時間内に何もキーを押さなかった場合、
キー割り込みが無いため、正誤判定無しで次の問題へ……
最後までそのまま放置するとforループ完了後に『*typein』に続き、
先述の流れと同じでgcopyでエラーが発生してしまいます。

ジャンプしたかどうかの判定用変数を用意して
対処した方が良いかと思います。



沢渡

リンク

2020/5/20(Wed) 19:17:22|NO.90611

Sleepではなく、awaitを含めながらループを行ってキー入力を待ち、
時間計測はTimeGetTimeで行うようにしてみました。
画像がないので、仮の処置としてmesで文字を表示するようにしています。

//・画像がないのでmes文で文字を表示します。 //・「仮」と書いてある部分は文字をmesで表示するためのものです。 // 画像で文字を表示する場合はこの部分は削除してください。 #include "winmm.as" //TimeGetTimeを使えるようにする notesel buf noteload "mondai.txt" ;ファイル読み込み noteget time, 0 ;秒数を文字型でtimeに保存 noteget moji, 1 ;問題を文字型でmojiに保存 displaytime=int(time) ;秒数を整数型に変換 mojisuu=strlen(moji);問題の文字数をmojisuuに保存 //buffer 1 //picload "mondai1400x900.jpg" screen 0,500, 400 ;スクリーンサイズ font msgothic,50 //仮 t=" " //仮 文字表示用 onkey gosub *typein *main for i, 0, mojisuu, 1 ;初期値0, mojisuuの数だけ繰り返す, i+1する cursor=i //現在のカーソル位置 xpos=140+30*(cursor\7) : ypos=10+50*(cursor/7) //文字を表示する位置。7文字ごとに改行。 gosub *ascii TimeGetTime start=stat //計測開始時の時間を記録 flag=0 //0:入力待ち 1:正解 2:不正解 repeat TimeGetTime if stat-start>displaytime : gosub *typemiss //時間切れはミス扱い if flag : break //flagが0以外ならループを抜ける await 33 ;入力待ち //30fps相当 loop next goto *win *typein ;正誤判定 if peek(moji,cursor)=iparam { gosub *typecorrect ;押されたキーと「mojiのcursor番目の文字」が等しければtypecorrectへ }else{ gosub *typemiss ;間違ってたらtypemissへ } return *ascii // 黒文字 pos xpos,ypos //gcopy 1, 35+(asc(i)-65)*46,150,28,40 color 0,0,0 //仮 poke t,0,peek(moji,cursor) //仮 mes t //仮 return *typecorrect //正解 flag=1 //正解フラグ return *typemiss //不正解 // 赤文字 pos xpos,ypos //gcopy 1, 35+(asc(i)-65)*46,265,28,40 color 255,0,0 //仮 poke t,0,peek(moji,cursor) //仮 mes t //仮 flag=2 //不正解フラグ return *win onkey 0 dialog "終了" end



ika

リンク

2020/5/25(Mon) 16:30:32|NO.90634

返信が遅くなって申し訳ありません。

>沢渡さん
提案していただいたプログラムを画像を使用するように試してみたところ、正常に作動しました。
私もTimeGetTime関数を使うということに気づいたのですが、正常に作動せず行き詰っていたので助かりました。
自分が想像した通りのプログラムを提案していただき本当にありがとうございます。

>あらやさん
何度も丁寧なアドバイスをしていただきありがとうございます。
おかげさまでスクリプトの効率化や、awaitを利用したTimeGetTime関数を使うということに気づくことができ、
hspの良い勉強になりました。



ONION software Copyright 1997-2023(c) All rights reserved.