今日は12月3日。「いずみ」と読むことができ、大石泉の日。
大石泉すき (診断)
大石泉すき (診断) とは、診断メーカー上の診断の一つで、日替わりで「大」「石」「泉」「す」「き」の5文字の中からランダムに5回文字が選ばれ、表示されるものである。
自分は、この診断を原則として毎日行い、結果について以下の定義の「ヒット」および「ブロー」の判定を行ってツイート/ポストしている。
- 「ヒット」:ある文字が「大石泉すき」となるためにあるべき位置にある
- 「ブロー」:「ヒット」にならなかった文字で「大石泉すき」を構成するものが、位置にかかわらずある (「ヒット」で構成した文字を除き、構成するために使う数までのみを有効とする)
例として、今日の結果を見てみよう。
石き泉き石#大石泉すき #shindanmakerhttps://t.co/zVrrjIc4eC
— みけCAT (@mikecat_mixc) December 2, 2023
1ヒット2ブロー
- 石:「大石泉すき」を構成するが、あるべき位置ではないので、ブロー
- き:「大石泉すき」を構成するが、あるべき位置ではないので、ブロー
- 泉:「大石泉すき」を構成するためにあるべき位置にあるので、ヒット
- き:「大石泉すき」を構成する「き」は既にあり、貢献しないので、なんでもない
- 石:「大石泉すき」を構成する「石」は既にあり、貢献しないので、なんでもない
あわせて「1ヒット2ブロー」である。
今回の制作物
今回は、ORANGE pico でこの「大石泉すき」(診断) をシミュレーションし、ヒット数とブロー数を計算し、統計を取るプログラムを作成した。
プログラム
10 cpeek &H91E5:cpoke &HF0,-1:cpeek &H90CE:cpoke &HF1,-1:cpeek &H90F2:cpoke &HF2,-1:cpeek &H82B7:cpoke &HF3,-1:cpeek &H82AB:cpoke &HF4,-1:cpeek &H82CC:cpoke &HF5,-1:cpeek &H8B74:cpoke &HF6,-1:cpeek &H815F:cpoke &HF7,-1
20 cpeek &H82AA:cpoke &HF8,-1:cpeek &H8F6F:cpoke &HF9,-1:cpeek &H82BD:cpoke &HFA,-1:cpeek &H91B5:cpoke &HFB,-1:cpeek &H82C1:cpoke &HFC,-1
30 dim choice(4):dim exists(4)
40 cls:locate 0,10:print "ヒット\xF7";:locate 2,9:print "\xF7ブロー";
50 for i=0 to 5
60 locate 4+6*i+5,9:print i;:locate 3,11+i:print i;
70 next
80 for h=0 to 5
90 for b=0 to 5
100 work=0:gosub 1000+100*h+10*b
110 locate 4+6*b+5,11+h:print 0;
120 next
130 next
140 locate 0,18:print "トータル";:locate 4+7,18:print 0;
150 locate 14,18:print "\xF0\xF1\xF2";:locate 18+7,18:print 0;
160 locate 27,18:print "\xF0\xF1\xF2\xF5\xF6";:locate 32+7,18:print 0;
170 locate 0,0:trynum=0:total=0:ooisiizumi=0:gyaku=0
180 k=inkey()
190 if k==&H72 || k==&H52 then goto 40
200 if k==&H73 || k==&H53 then trynum=0
210 if trynum<>0 then goto 300
220 if k==&H31 then trynum=1
230 if k==&H32 then trynum=10
240 if k==&H33 then trynum=100
250 if k==&H34 then trynum=1000
260 if k==&H35 then trynum=10000
270 if k==&H36 then trynum=100000
280 if k==&H37 then trynum=1000000
290 if k==&H30 then trynum=-1
300 if k==&H6F || k==&H4F then trynum=-2
310 if trynum==0 then goto 180
320 if trynum>0 then trynum=trynum-1
330 total=total+1
340 result$="":hit=0:blow=0
350 for i=0 to 4
360 choice(i)=rnd(5)
370 result$=result$+chr$(&HF0+choice(i))
380 if choice(i)==i then hit=hit+1:exists(i)=1 else exists(i)=0
390 next
400 for i=0 to 4
410 if exists(choice(i))==0 then blow=blow+1:exists(choice(i))=1
420 next
430 locate 18,1:print result$;:locate 16,3:print hit;"ヒット ";blow;"ブロー";
440 locate 16,5:if instr(result$,"\xF0\xF1\xF2") then print "「\xF0\xF1\xF2」\xF8\xF9\xFA";:ooisiizumi=ooisiizumi+1:locate 18,18:print format$("%8d",ooisiizumi); else print " ";
450 locate 16,6:if hit==5 then print "\xFB\xFC\xFA!!!!!";:goto 470
460 if instr(result$,"\xF2\xF1\xF0") then print "「\xF0\xF1\xF2」\xF5\xF6\xF8\xF9\xFA";:gyaku=gyaku+1:locate 32,18:print format$("%8d",gyaku); else print " ";
470 locate 4,18:print format$("%8d",total);
480 gosub 2000+100*hit+10*blow
490 work=work+1
500 gosub 1000+100*hit+10*blow
510 locate 4+6*blow,11+hit:print format$("%6d",work);
520 if trynum==-2 && hit==5 then trynum=0
530 goto 180
1000 h0b0=work:return
1010 h0b1=work:return
1020 h0b2=work:return
1030 h0b3=work:return
1040 h0b4=work:return
1050 h0b5=work:return
1100 h1b0=work:return
1110 h1b1=work:return
1120 h1b2=work:return
1130 h1b3=work:return
1140 h1b4=work:return
1150 h1b5=work:return
1200 h2b0=work:return
1210 h2b1=work:return
1220 h2b2=work:return
1230 h2b3=work:return
1240 h2b4=work:return
1250 h2b5=work:return
1300 h3b0=work:return
1310 h3b1=work:return
1320 h3b2=work:return
1330 h3b3=work:return
1340 h3b4=work:return
1350 h3b5=work:return
1400 h4b0=work:return
1410 h4b1=work:return
1420 h4b2=work:return
1430 h4b3=work:return
1440 h4b4=work:return
1450 h4b5=work:return
1500 h5b0=work:return
1510 h5b1=work:return
1520 h5b2=work:return
1530 h5b3=work:return
1540 h5b4=work:return
1550 h5b5=work:return
2000 work=h0b0:return
2010 work=h0b1:return
2020 work=h0b2:return
2030 work=h0b3:return
2040 work=h0b4:return
2050 work=h0b5:return
2100 work=h1b0:return
2110 work=h1b1:return
2120 work=h1b2:return
2130 work=h1b3:return
2140 work=h1b4:return
2150 work=h1b5:return
2200 work=h2b0:return
2210 work=h2b1:return
2220 work=h2b2:return
2230 work=h2b3:return
2240 work=h2b4:return
2250 work=h2b5:return
2300 work=h3b0:return
2310 work=h3b1:return
2320 work=h3b2:return
2330 work=h3b3:return
2340 work=h3b4:return
2350 work=h3b5:return
2400 work=h4b0:return
2410 work=h4b1:return
2420 work=h4b2:return
2430 work=h4b3:return
2440 work=h4b4:return
2450 work=h4b5:return
2500 work=h5b0:return
2510 work=h5b1:return
2520 work=h5b2:return
2530 work=h5b3:return
2540 work=h5b4:return
2550 work=h5b5:return
解説
- 10~20行目:使う文字を内蔵フォントから読み込む。
- 30行目:ヒット・ブローの判定に用いる配列を定義する。
- 40~170行目:画面表示と統計を初期化する。
- 180~300行目:キー操作を受け付ける。
- 310~320行目:自動実行の管理を行う。
- 330~530行目:診断のシミュレーションとヒット・ブロー判定を行い、統計を更新する。
- 1000~1550行目:配列のかわりに統計情報をストアする。
- 2000~2550行目:配列のかわりに統計情報をロードする。
配列だと1要素で16ビットしか使えないので、普通の変数を並べて行番号でアクセスできるようにすることで、1要素32ビットの配列を擬似的に実現している。
配列 choice
に診断結果を格納し、配列 exists
で診断結果に含まれる文字を管理する。
まずヒットの情報を exists
に格納する。
続いて、配列 choice
に格納した診断結果を用い、ブローの判定 (すなわち、今回は目標の「大石泉すき」に同じ文字は1個ずつしか無いので、まだ出ていない文字が出たかの判定) を行う。
さらに、診断結果に「大石泉」およびその逆「泉石大」が含まれるかを判定し、判定結果に応じた画面表示とカウントの更新を行う。
操作方法
キーボードを用いて操作を行う。
-
1
:1回診断を行う。 -
2
:10回診断を行う。 -
3
:100回診断を行う。 -
4
:1,000回診断を行う。 -
5
:10,000回診断を行う。 -
6
:100,000回診断を行う。 -
7
:1,000,000回診断を行う。 -
0
(ゼロ):無限に診断を行う。 -
O
(オー):「大石泉すき」が出るまで診断を行う。 -
S
:診断の自動実行を止める。 -
R
:診断の自動実行を止め、統計をリセットする。
S
および R
以外の操作は、診断の自動実行中は無効である。
ライセンス
今回のプログラムは、CC BY 4.0 でライセンスする。
このプログラム (改造したものを含む) を公開の場で利用する際は、出典を示していただけると嬉しい。
これは、Qiitaの利用規約に基づくプログラムの利用を妨げるものではない。
実行結果例
初期画面
1回診断を行った結果
「大石泉」の逆が出た
「大石泉」が出た
「大石泉すき」が揃った
100,000回診断を行った結果
動画:10,000回診断を行う
ちなみに
たとえば、診断結果が「大大大大大」のとき1ヒット0ブロー、「すきすきす」のとき0ヒット2ブローとなる。
「大石泉すき」を構成する文字しか出てこないので、0ヒット0ブローはあり得ない。
さらに、文字が1種類のときは必ず正しい位置にもその文字があるので、0ヒット1ブローもあり得ない。
また、5文字しかないので、ヒットの数とブローの数を足して5を超えるのもあり得ない。
関連記事
いつになったら「大石泉すき」は揃うのか? #Python - Qiita (他の人の記事)