HEART★6 ルーレット (ビット演算版)

 HEART★6基板(OUT1~6にLED,IN1~IN4にボタンを追加したシールド基板)とIchigoDakeを使った、6灯のLEDルーレットです。


1.遊び方

LEDを順番に点灯することで、ルーレットゲームの回転盤の動きを再現します。

  1. スタートを押して、回転を始めます。
  2. ストップを押して、回転を止めます。
  3. 回転はすぐに止めないで、徐々に止まるようにします。
  4. 回転が止まった場所をあたりにします。

2.しくみをつくる

「1.遊び方」をもとに、プログラムで動かすしくみを考えます。そして、考えたとおりの動きや形になるように、プログラムを組んでいきます。

2.1 使うボタンを決める

ルーレットゲームでは、回転盤を回すスタートと、回転を止めるストップができればよいので、両端にあるIN1ボタンとIN4ボタンを使うことにします。IN2ボタンとIN3ボタンは使いません。

ボタン役め命 令押された時の値離した時の値
IN1スタートIN(1)01
IN2つかわないIN(2)01
IN3つかわないIN(3)01
IN4ストップIN(4)01

 ボタンが押されたかどうかを調べるには、IN命令IF命令を使います。ボタンは押されたなら、離した(押されていない)ならになります。
次のテストプログラムで動きを確かめます。

30 PRINT “IN1ボタン ガ オサレテイナイ”,IN(1)
32 WAIT 30
35 IF IN(1) == 1 GOTO 30
36 PRINT “IN1ボタン ガ オサレタ”,IN(1)

50 PRINT “IN4ボタン ガ オサレテイナイ”,IN(4)
70 WAIT 30
100 IF IN(4) == 1 GOTO50
200 PRINT “IN4ボタン ガ オサレタ”,IN(4)


2.2 LEDを光らせる

 LEDを光らせたり消したりするには、OUT命令を使います。
今回は「OUT 1,1」や「OUT 1,0」のような書き方は使わず、「OUT x」のように、コンピュータの数値表現二進法)を使ってOUT命令を書く方法を考えます。

 さらに、シフト演算(シフト・レフト演算:IchigoJamBASICコマンド一覧の「<<」を参照)と組み合わせて、光の動きをつくります。
「x << n」は、「値xを左へn個分シフトする」という計算をします。このような計算のことをビット演算といいます。
今回使う「1<<N」は、1を左へn個分シフトするという計算式になり、数学でいうところの「2のn乗」と同じ答えを出してくれます。

※IchigoJamで使用できるビット演算には、つぎの種類があります
 1.論理和(| パイプ) 2.論理積(& アンパサンド) 3.排他的論理和(^ ハット) 4.シフト(<< と >>) 5.ビット反転(~ チルダ)

1<<N」がどんな結果になるのか、つぎのプログラムで確かめます。

NEW
OK
10 INPUT N
50 OUT 1<<N
RUN
?0
OK
RUN
?1
OK
RUN
?2

 つぎのOUT命令の結果(LEDの光り方)は、すべて同じになります。

LEDが
光る場所
ビット演算で
記述した命令
二進法で
記述した命令
十進法で
記述した命令
LED1(OUT1)OUT 1<<0OUT `000001OUT 1
LED2(OUT2)OUT 1<<1OUT `000010OUT 2
LED3(OUT3)OUT 1<<2OUT `000100OUT 4
LED4(OUT4)OUT 1<<3OUT `001000OUT 8
LED5(OUT5)OUT 1<<4OUT `010000OUT 16
LED6(OUT6)OUT 1<<5OUT `100000OUT 32

二進法で記述した命令を見ると、”1”の箇所のLEDだけが光ることがわかります。


2.3 光を動かす

 ビット演算のシフト数(変数Nの値)を0,1,2,3,4,5と順番に繰り返すと、対応したLEDも順番に光ります。これで光が回転している動きになりそうです。

シフト数を0から5までを繰り返すプログラムは、「0からはじめて、1ずつ足していき、6だったら0にする」という考え方でつくります。

10 LET N,0
50 OUT 1<<N
65 PRINT N,BIN$(1<<N,6)
70 WAIT 60

80 LET N,N+1
90 IF N==6 LET N,0
100 GOTO 50

RUN
0 000001

1 000010
2 000100
3 001000
4 010000
5 100000
0 000001
1 000010
2 000100
3 001000


2.4 スタート・ストップをする

 2.1で使うボタンを決めたので、スタートとストップをするしくみを考えます。さらに、ストップが押されたら、少しずつ回転を落とすしくみも考えます。

  • IN1ボタン(スタート)が押されていないなら、押されるまで待つ(30行目
  • 回転速度が変化できるように、変数を用意する(40行目、70行目
  • IN4ボタン(ストップ)が押されていないなら、回転を続ける(100行目
  • 少しずつ回転を落として、止まる速度になるまで回転を続ける(210行目、220行目

10 LET N,0
30 IF IN(1)==1 GOTO 30
40 LET W,10
50 OUT 1<<N
65 PRINT N,BIN$(1<<N,6)
70 WAIT W
80 LET N,N+1
90 IF N==6 LET N,0
100 IF IN(4)==1 GOTO 50

210 LET W,W+5
220 IF W<30 GOTO 50


2.5 問題を解決する

 しかし、このままだと思い通り動かないことがあります。
IN4ボタンを押したままなら少しずつ回転が落ちて止まるのですが、途中でボタンを離してしまうと回転を続けてしまいます(100行目の条件が成立してしまう)。

解決方法1

 解決方法のひとつに、”フラグ(旗)”という考えかたがあります。
”フラグ”を上げ下げすることで、プログラムの条件をコントロールする方法で、今回は、IN4ボタンを1回でも押せば、”フラグ”を上げて、100行目のIF条件が成立しないようにするのです。
プログラムでは、”フラグ”の役割として変数Fを使い、次のようなルールにします。

  • Fの値が0なら、1度もボタンは押されていない
  • Fの値が1なら、1度でもボタンを押されている

このルールを元に、IF命令で判断するようにプログラムします。

10 LET N,0: LET F,0
30 IF IN(1)==1 GOTO 30
40 LET W,10
50 OUT 1<<N
65 PRINT N,BIN$(1<<N,6)
70 WAIT W
80 LET N,N+1
90 IF N==6 LET N,0
100 IF N(4)==1 && F==0 GOTO 50

200 LET F,1
210 LET W,W+5
220 IF W<30 GOTO 50

100行目の「IN4ボタンが押されていない かつ フラグが0」の条件なら、GOTO50を実行して、回転を続けます。
しかし、一度でもIN4ボタンが押されると、200行目でFの値が1になるので、再度100行目を実行しても、条件は成立しなくなります。
これで、220行目の「止まる速度になるまで回転を続ける」ことができるようになります。

解決方法2

 もうひとつは、IN4ボタンを強制的に押したままの状態にする方法です。
IchigoJamの入出力端子は、入力から出力に切り替えたり、その逆にしたりすることができます(IchigoJamのI/O表を参照)。
こうすると、OUT命令で出力している値が、IN命令で常時読み込む値になります。
IN4をボタンを押したままの状態にするには、OUT11に0を設定します(1を設定すると、INボタンは離したままの状態になります)。

PRINT IN(4)
1
OK
OUT 11,0
OK
PRINT IN(4)
0
OK

再びIN4を入力として使う時は、OUT11に-1を設定します。

OUT 11,−1
OK
PRINT IN(4)
1
OK

今回は、”フラグ”の考え方よりもしくみが簡単で、修正箇所も少ないので、こちらの方法でプログラムすることにします。

10 LET N,0
30 IF IN(1)==1 GOTO 30
40 LET W,10
50 OUT 1<<N
65 PRINT N,BIN$(1<<N,6)
70 WAIT 60
80 LET N,N+1
90 IF N==6 LET N,0
100 IF IN(4)==1 GOTO 50

200 OUT 11,0
210 LET W,W+5
220 IF W<30 GOTO 50

310 OUT 11,-1

※IN1~IN3の出力端子はOUT8~OUT10になります(IchigoJamのI/O表を参照)
※IN9(BTN)とOUT7(LED)は入出力切り替えはできません


3.プログラムを完成させる

 ひと通りゲームができるようになりました。もうすこしゲームが楽しくできるように工夫しましょう。
細かいところも見直して、プログラムを完成させます。

  • プログラムにタイトルを付けてわかりやすくします(1行目)
  • スタート時に、LEDを光らせてボタン待ちします(20行目)
  • LEDの動きと連動するように、効果音も加えます(60行目)
  • 回転が止まったときは、別の音を鳴らして、当たりをわかりやすくします(320行目)
  • PRINT命令の表示する項目を増やし、値や変化がわかるようにします(65行目、45行目、300行目)
  • 再ゲームできるようにします(310行目、330行目)

1 ‘HEART*6ルーレット ver1.1 by NEXTDAY
10 LET N,2
20 OUT 1<<N
30 IF IN(1)==1 GOTO 30
40 LET W,1
45 PRINT “START!”

50 OUT 1<<N
60 BEEP 100
65 PRINT N,BIN$(1<<N,6),IN(4),IN(3),IN(2),IN(1),”W”;W
70 WAIT W
80 LET N,N+1
90 IF N==6 LET N,0
100 IF IN(4)==1 GOTO 50

200 OUT 11,0
210 LET W,W+2
220 IF W<30 GOTO 50

300 PRINT “STOP!”
310 OUT 11,-1
320 BEEP 5,60
330 GOTO 30

10行目 最初に点灯するLEDの位置を決める
20行目 LEDを点灯する(スタート待ちを点灯)
30行目 IN1ボタンが押されるまで、この行を繰り返して待つ
40行目 LEDの点灯時間を決める
    この値を変えると回転速度が変わる

50行目 LEDを点灯する(0,1,2,3,4,5の順に点灯)
60行目 LED光が移動する毎に音を鳴らす
65行目 状態を表示する
    LED点灯位置、LED点灯位置(二進値)、各ボタンの値、LED点灯時間
70行目 LED点灯時間
80行目 LED点灯位置を1つ増やす
90行目 回転が一周したら、LED点灯位置を最初の位置にする
100行目 IN4ボタンが押されていないなら、回転を続ける

200行目 IN4を入力から出力(OUT11)に切り替えて、0を出力する
     IN4ボタンは押したままと同じ状態になる(IN(4)の値は常に0になる)

210行目 LED点灯時間を徐々に長くする
220行目 点灯時間が30以下なら、回転をつづける

310行目 IN4を出力から入力に切り替える
     IN4ボタンが元通り使えるようになる
320行目 停止した合図音を鳴らす
330行目 ゲームを続ける

RUN
START!
2 000100 1 1 1 1 W1
3 001000 1 1 1 1 W1
4 010000 1 1 1 1 W1
5 100000 1 1 1 1 W1
0 000001 1 1 1 1 W1
1 000010 1 1 1 1 W1
2 000100 1 1 1 1 W1
3 001000 1 1 1 1 W1
4 010000 1 1 1 0 W3
5 100000 1 1 1 0 W5
0 000001 1 1 1 0 W7
1 000010 1 1 1 0 W9
2 000100 1 1 1 0 W11
3 001000 1 1 1 0 W13
4 010000 1 1 1 0 W15
5 100000 1 1 1 0 W17
0 000001 1 1 1 0 W19
1 000010 1 1 1 0 W21
2 000100 1 1 1 0 W23
3 001000 1 1 1 0 W25
4 010000 1 1 1 0 W27
5 100000 1 1 1 0 W29

STOP!



4.改良する

4.1 プログラムの一部を修正して改良する

・完成したプログラムにつぎの修正をすると、右回りLEDルーレットに変身します。

80 LET N,N-1
90 IF N<0 LET N,5

・右回りLEDルーレットは、OUT値が5,4,3,2,1,0のように変化すればよいので、つぎのように修正してもOKです。ただし、LED番号とNの値は合わなくなります。
20 OUT 1<<(5-N)
50 OUT 1<<(5-N)

 ビット演算を右シフトにしても、右回りになります。
20 OUT 32>>N
50 OUT 32>>N

・220行目に乱数を使って、回転が止まるまでの時間を、毎回変わるようにすることもできます。

220 IF W<20+R GOTO 50 ELSE LET R,RND(20)

・ボタン3を押したら一時停止させます。離したら再開します。

76 IF IN(3)==0 GOTO 60

・ボタン2を押すごとにBEEP音を鳴らしたり止めたりします(フラグの応用)。

60  BEEP 100*F
95  IF IN(2)==0 F=(F=0)*1
320 BEEP 5*F,60


5.いろいろなルーレット

★やっぱり「OUT 1,1」 de LEDルーレット

10 OUT 0:N=2
20 OUT N,1
30 IF IN(1) GOTO 30

40 W=1
50 N=N+1:IF N==7 N=1
55 OUT N,1
60 BEEP 100
70 WAIT W
100 IF IN(4)==1 OUT N,0:GOTO 50
300 BEEP 5,60

★かんたんLEDルーレット

10 N=2
50 OUT 1<<(N%6)
60 BEEP 100
70 WAIT 2
80 N=N+1
100 IF IN(4) GOTO 50
300 BEEP 5,60

★もっとかんたんに、1行プログラムのLEDルーレット

例1
10 OUT 1<<RND(6):IF IN(4) CONT

例2 
10 OUT 1<<(TICK()/2%6):IF IN(4) CONT
音を鳴らすなら、、、
10 OUT 1<<(TICK()/2%6):BEEP 10*!(TICK()%5),5:IF IN(4) CONT ELSE BEEP 10,30

例3 
10 OUT 1<<(TICK()%60):IF IN(4) CONT

例4 
10 T=TICK():OUT 1+T/10%6,T/60%2:IF IN(4) CONT ELSE OUT 1<<(TICK()/2%6)

例5 
10 OUT TICK()/60%2*255:IF IN(4) CONT ELSE OUT 1<<(TICK()/2%6)

例6 タクトSWでスタート・ストップ
10 OUT 1<<(TICK()/2%6):IF !BTN() CONT ELSE WAIT 180:CONT
 ※逆回転にするなら↓
10 OUT 32>>(TICK()/2%6) :IF !BTN() CONT ELSE WAIT 180: CONT

例7 ダイレクト実行
FORI=0TO1:OUT1<<(TICK()/2%6):I=!IN(4):NEXT


★デモンストレーションもできる、LEDルーレット

  • RUNして、すぐにルーレットをスタートする
  • ストップするタイミングを毎回変化させる(20行目)
  • LED位置(変数N)を除算の余りで求める(45行目)
  • 右回転にする(45行目)
  • どのボタンを押しても徐々にストップ&再スタートする(110行目)
    ※全ボタン一括入力をサブルーチン化(1000行目)
    ※全ボタン有効無効の切替をサブルーチン化(2000行目)
  • ストップせず放置していても、15秒後から徐々にストップする(110行目、30行目にて時間リセット)
  • ストップしたとき、止まったLEDを点滅する & 放置していても30秒後に再スタートする(340行目)

1 ‘HEART*6ルーレット v2.1 by NEXTDAY
10 @START
20 W=2+RND(3): R=20+RND(30):I=32767
30 CLT
40 @ROULETTE
45 I=I-1:N=I%6
50 OUT 1<<N
60 BEEP 100
65 GSB@PRINT
70 WAIT W
100 GSB@SW(S)
110 IF !S && TICK()<900 GOTO@ROULETTE
200 P=0:GSB@PORT(P)
210 W=W+2
220 IF W<R GOTO@ROULETTE
300 P=-1:GSB@PORT(P)
310 BEEP 5,60
320 GSB@SW(S):IF S CONT
330 CLT
340 GSB@SW(S):OUT N+1,TICK()/30%2:IF !S && TICK()<1800 CONT
350 GSB@SW(S):IF S CONT
360 GOTO@START
1000 @SW(S)
1010 S=!IN(4)<<3+!IN(3)<<2+!IN(2)<<1+!IN(1)
1020 RTN
2000 @PORT(P)
2010 OUT 8,P:OUT 9,P:OUT 10,P:OUT 11,P
2020 RTN
3000 @PRINT
3010 ? N,BIN$(1<<N,6),IN(4),IN(3),IN(2),IN(1),”S”;S,”W”;W
3020 RTN


※全ボタン一括入力は、つぎのように書いても同じ結果になる
1010 S=!IN(4)*8+!IN(3)*4+!IN(2)*2+!IN(1))


この教材は「Creative Commons — CC BY-SA 4.0」の下に提供されています。