電子工作

SIMONゲームを作ってみた

  • 閲覧数: 3146
  • 4

作品画像

  • C.120x80.5a5d5f2a0ee37ac2699e6f5b0f40ff62
  • C.120x80.964359f591a961114a23dc16e50a8a7e
  • C.120x80.18949ce14c889f7e37ea42978df04fc4
  • C.120x80.36927544e53b32dda49540d390bfcd82
  • C.120x80.98f3304a5999071bafbfc82b1b7ceaf6

作品説明

SIMONという古典的なゲームをArduinoを使って再現してみました。

赤ボタン・緑ボタン・青ボタン・黄色ボタンがランダムに点灯し、点灯した色のボタンを押します。次はそれから一つ色が増えたものが点灯し、その通りにボタンを押していきます。それがだんだん増えていきある一定の回数まで正しくボタンを押すことが出来れば、ゲームに勝つことができます。

詳しくはWikipediaに譲ります。おもちゃ屋さんに発売されていた頃の写真も掲載されています。
私はUbuntuの教育版Edubuntuをインストールした時にプリインストールされていて知りました。

このSIMONというゲームをArduinoを使って電子工作してみました。

プログラムはSparkfunSimonのキット用のソフトが公開されていたので参考にしましたが、公開されていたのはC言語で、Arduinoの機能を使用しないものだったので、Arduino言語にのっとって作り直しました。参考にはしましたが、一から作ったと言っていいと思います。

出来上がったのが
ボタン部分

本体

です。
お菓子の箱に穴を開けて、照明付きボタンを配置しています。

フタの裏側は

ボタンの裏側

ボタンの裏側


箱の中身は

中身

中身


です。

Arduinoコンパチのスイッチサイエンス製のCielduinoを使用しています。理由はほんの少しだけユニバーサル基板が必要だったのですが、ユニバーサル基板タイプのシールドを使うほどではなかったので、Cielduinoで代用しました。

電池を1つ使っていますが、これはSparkfunの5V DC to DC Step Up - 1xAAという電池ボックスで1.5Vを5Vに昇圧しています。

レシピ

マイコンにはArduino互換のスイッチサイエンス製Cielduinoを使用しています。
Arduinoの電源には単3の電池を5Vに昇圧する電池ボックスを使用。
リレーを組み合わせることにより、AutoPowerOffを実現しています。

今回はじめてFritzingを使ってみました。
フリーで使える回路図作成ソフトの一つです。
そのうち、DesignSparkとの比較をブログを書いてみたいと思います。

ブレットボードビューです。


実際とはかなり違います。
電池部分は単3を1本使い、5Vに昇圧する電池ボックスを使用しています。

5Vの照光スイッチを使用しているので、スイッチとLEDは一体です。
あと、トランジスタはSC1815を使用していますが、ベースとコレクタの位置が逆です。

上記のブレットボードを回路図にしたもの

回路図

回路図



今回のSIMONを作るにあたって、どうしても入れたかった機能がAUTO POWER OFFです。
電気設備の電磁開閉器の保持回路を参考にしています。

回路図の左上の部分がそれです。
電源スイッチを入れるとリレーが働き、それによってArduinoの電源が入ります。このままだと、スイッチから手を話すと電源が切れてしまいます。そのため、すぐに4番の出力ポートをHIGHし、リレーに電源を供給し続ければArduinoは動き続けます。そして、4番の出力ポートをLOWにすると自分自身の電源を落とすることになるのです。

ただ、4番ポートの出力を直接リレーにつないでしまうと負荷が大きすぎるので、トランジスタを使っています。

プログラムは

#define  LED_RED            0
#define  LED_GREEN          1
#define  LED_BLUE           2
#define  LED_YELLOW         3
#define  FAILURE            9
#define  LED_RED_PIN       10
#define  LED_GREEN_PIN     11
#define  LED_BLUE_PIN      12
#define  LED_YELLOW_PIN    13
#define  RELAY              4
#define  BUTTON_RED_PIN     6
#define  BUTTON_GREEN_PIN   7
#define  BUTTON_BLUE_PIN    8
#define  BUTTON_YELLOW_PIN  9
#define  TIME_LIMIT       300
#define  MOVE_TO_WIN        8
#define  MARK_OF_LOST       false
#define  MARK_OF_WIN        true

int moves[32];
int nmoves = 0;
int leave_counter;

void setup() {
  pinMode(LED_RED_PIN, OUTPUT);  
  pinMode(LED_GREEN_PIN, OUTPUT);  
  pinMode(LED_BLUE_PIN, OUTPUT);  
  pinMode(LED_YELLOW_PIN, OUTPUT);  
  pinMode(BUTTON_RED_PIN, INPUT);  
  pinMode(BUTTON_GREEN_PIN, INPUT);  
  pinMode(BUTTON_BLUE_PIN, INPUT);  
  pinMode(BUTTON_YELLOW_PIN, INPUT);
  pinMode(RELAY,OUTPUT);
  digitalWrite(RELAY,HIGH);
  play_winner(3);
  randomSeed(analogRead(0));
}

void loop() {
  delay(1000);
  if (game_mode() == MARK_OF_WIN){
    play_winner(10);
  }else{
    play_loser();
  }
}

void led_all_switch_on(){
  for ( int i = 0 ; i <= 25 ; ++i){
    for ( int j = 0 ; j<= 3 ; ++j){
      set_leds(j);
      delay(1);
    }
  }
}

void play_loser(){
  for (int i = 0; i <=5 ;++ i){
    led_all_switch_on();
    set_leds(4);
    delay(100);
  }
}

void play_winner(int count){
  for ( int i = 0 ; i <= count ; ++i){
      set_leds(0);
      delay(80);
      set_leds(1);
      delay(80);
      set_leds(3);
      delay(80);
      set_leds(2);
      delay(80);
      set_leds(4);
  }
}

//問題を表示する
void play_moves(){
  for (int c_move = 0 ; c_move < nmoves ; ++c_move){
    set_leds(moves[c_move]);
    delay(200);
    set_leds(4);
    delay(200);
  }
}

//新しい色を加える
void add_to_moves(){
  int new_button;
  moves[nmoves] = random(4);
  ++nmoves;
}
  
// ボタンが押されるか、タイムアウトまで待つ。返り値は0から3までの色かFAILURE=9のどれか。
int wait_for_button(){
  int old_button = FAILURE;
  int time_limit = TIME_LIMIT;
  while( time_limit > 0){
    int button;
    button = check_button();
    if (((old_button == 0)||(old_button == 1)||(old_button == 2)||(old_button == 3))&&(button == FAILURE)){
      return old_button;
    }
    old_button = button;
    delay(10);
    --time_limit;
  }
  return FAILURE;
}

//ゲームのメインサブルーチン
boolean game_mode(){
  nmoves= 0;
  while ( nmoves < MOVE_TO_WIN){
    add_to_moves();
    play_moves();
    for ( int c_move = 0 ; c_move < nmoves ; ++c_move){
      int choice = wait_for_button();
      if (choice == FAILURE) {
//リレーを操作  auto power off
        if (nmoves == 1) {
          ++leave_counter ;
          if (leave_counter >= 5) digitalWrite(RELAY,LOW);
        }else leave_counter =0;
//        
        return MARK_OF_LOST;
      }
      
      set_leds(choice);
      delay(200);
      if (choice != moves[c_move]) return MARK_OF_LOST;
      set_leds(4);
    }
    delay(1000);
  }
  return MARK_OF_WIN;

//ボタンをチェック。0~3の色かFAILURE=9の返り値    
int check_button(){
  int i = FAILURE;
  if (digitalRead(BUTTON_RED_PIN) == HIGH){
    delay(10);
    i = LED_RED;
  }
  if (digitalRead(BUTTON_GREEN_PIN) == HIGH){
    delay(10);
    i = LED_GREEN;
  }
  if (digitalRead(BUTTON_BLUE_PIN) == HIGH){
    delay(10);
    i = LED_BLUE;
  }
  if (digitalRead(BUTTON_YELLOW_PIN) == HIGH){
    delay(10);
    i = LED_YELLOW;
  }
  return i;
}

//LEDの表示。返り値なし  
void set_leds(int leds){
  digitalWrite(LED_RED_PIN,LOW);  
  digitalWrite(LED_GREEN_PIN,LOW);  
  digitalWrite(LED_BLUE_PIN,LOW);  
  digitalWrite(LED_YELLOW_PIN,LOW);  
  switch (leds){
    case 0:
      digitalWrite(LED_RED_PIN,HIGH);
      break;
    case 1:
      digitalWrite(LED_GREEN_PIN,HIGH);
      break;
    case 2:
      digitalWrite(LED_BLUE_PIN,HIGH);
      break;
    case 3:
      digitalWrite(LED_YELLOW_PIN,HIGH);
      break;
  }
}

コメント (0件)

コメントはまだありません