//DFRobot.com
//Compatible with the Arduino IDE 1.0
//Bomb Disposal Game UNO Version
//Created by Ricky
//2014/3/31
//Version 1.0
#include <Wire.h>
#include "LiquidCrystal_I2C.h"
#include "pitches.h"
#include <Servo.h>
int timer=15; //15 seconds for bomb to expose
//LiquidCrystal_I2C lcd(0x20,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
//Sound Effect Part
// notes in the melody:
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {4, 8, 8, 4,4,4,4,4 };
//Led Pins
const int RedLedPin=4;
const int GreenLedPin=5;
const int BlueLedPin=6;
const int WhiteLedPin=7;
int On_Led_Pin=0;
boolean StartStatus=false;
boolean EndStatus=false;
boolean FirstSucess=false;
//Fuse Pins
int fuseinPins[] = {8, 9, 10, 11, 12,13};
//36->Red, 37->Orange,38->Yellow,39->Green,40->Blue,41->purple
//0->Red LED, 1->Green Led, 2->Blue Led,3->White, last bit ->Enable status
//Game Matrix
int connectMatrix[12][4]={
{0,1,9,0},
{3,2,8,0},
{1,2,13,0},
{0,3,11,0},
{1,3,9,0},
{2,0,10,0},
{2,1,10,0},
{3,0,13,0},
{1,0,12,0},
{2,3,11,0},
{0,2,8,0},
{3,1,12,0},
};
//Game Logic variable
int activerow=0;
int defusePin=0;
int previousdefusePin=20;
//Bomb trigger pins
Servo BombServo;
const int BombRelayA=10;
const int BombRelayB=11;
const int BuzzPin = 3;
void setup()
{
BombServo.attach(2); // attaches the servo on pin 9 to the servo object
BombServo.write(30);
Serial.begin(9600);
lcd.init(); // initialize the lcd
randomSeed(analogRead(0));
// Print a message to the LCD.
lcd.backlight();
lcd.print("Ready to Go?");
delay(1000);
pinMode(BuzzPin, OUTPUT);
//relay是继电器,控制大功率LED灯或灯泡:模拟强烈的闪光效果。控制电磁阀:用于控制气体或液体流动,模拟爆炸后释放的气体或液体
//或者是接雾化模块,生成点儿水雾
pinMode(BombRelayA, OUTPUT);
pinMode(BombRelayB, OUTPUT);
//BombServo.write(30);
digitalWrite(BombRelayA, LOW);
digitalWrite(BombRelayB, LOW);
//开局前的LED动画效果
for(int i=4;i<8;i++)
{
pinMode(i, OUTPUT);
digitalWrite(i,LOW);
delay(1000);
digitalWrite(i,HIGH);
}
//设置几个炸弹线
for(int i=8;i<14;i++)
{
//pinMode(i, INPUT);
pinMode(i, INPUT_PULLUP);
}
//Arduino MEGA 2560才有这么多口
/* for(int i=36;i<42;i++)
{
pinMode(i, INPUT);
}
for(int i=0;i<6;i++)
{
Serial.print(fuseinPins[i]);
Serial.print("=");
Serial.println(digitalRead(fuseinPins[i]));
}
*/
Serial.println("Game Starts...");
digitalWrite( BuzzPin,LOW);
EndStatus=false;
}
void loop()
{
if(EndStatus==false)
{
//lcd显示还剩多少秒
lcd.clear();
lcd.print((int)timer);
lcd.print(" seconds left Bomb Game\n");
//执行游戏逻辑
GameLogic();
//如果时间用完则引爆炸弹,否则把时间减少1,并播放音效
if(timer==0)
{
TriggerBomb();
}
else
{
timer--;
SoundEffect(timer);
}
delay(1000);
}
}
void GameLogic()
{
//游戏未开始,且没有引爆
if(StartStatus==false && EndStatus==false)
{
RandomLed();
RandomCondition();
StartStatus=true;
}
//不停地检查爆炸的状态
CheckBombStatus();
}
void RandomLed()
{
//led随机亮起
for(int i=0;i<20;i++)
{
On_Led_Pin=random(4,8);
digitalWrite(On_Led_Pin, LOW);
delay(20+i*15);
digitalWrite(On_Led_Pin, HIGH);
}
//播放音效
digitalWrite(BuzzPin, HIGH);
delay(1000);
digitalWrite(BuzzPin, LOW);
}
void RandomCondition()
{
//选出一道题目
while(true)
{
//随机生成一个题目矩阵的行号
activerow=random(0,12);
//如果这道题没做过(未标为1),选出题目退出循环
if(connectMatrix[activerow][3]!=1)
{
break;
}
}
Serial.print("Active Row is:");
Serial.println(activerow);
//显示出题目,设置好答案变量
for(int i=0;i<2;i++)
{
Serial.print("Light on:");
Serial.println(connectMatrix[activerow][i]);
//题目的第一个圆圈是什么颜色,对应的灯就闪一下
//题目的第二个圆圈是什么颜色,对应的灯就闪一下
switch(connectMatrix[activerow][i])
{
case 0:
{
digitalWrite(RedLedPin,LOW);
delay(300);
digitalWrite(RedLedPin,HIGH);
break;
}
case 1:
{
digitalWrite(GreenLedPin,LOW);
delay(300);
digitalWrite(GreenLedPin,HIGH);
break;
}
case 2:
{
digitalWrite(BlueLedPin,LOW);
delay(300);
digitalWrite(BlueLedPin,HIGH);
break;
}
case 3:
{
digitalWrite(WhiteLedPin,LOW);
delay(300);
digitalWrite(WhiteLedPin,HIGH);
break;
}
}
}
//在串口通信中输出答案,方便调试
Serial.print("Defuse Pin is:");
defusePin=connectMatrix[activerow][2];
Serial.println(defusePin);
}
void CheckBombStatus()
{
for(int i=0;i<6;i++)//Scan Fuse Pin
{
Serial.print(fuseinPins[i]);
Serial.print("=");
Serial.println(digitalRead(fuseinPins[i]));
//如果第i根线被拔了,且不是上一轮的答案
//线一开始是连接上的,相当于按钮按下去了,所以连接上时读数为0,断开后读数为1
if(digitalRead(fuseinPins[i])==HIGH && fuseinPins[i] != previousdefusePin)
{
//如果这根线不是答案,就引爆炸弹
if(fuseinPins[i]!=defusePin)
{
TriggerBomb();
}
else
{
//拆的这根是正确答案,且如果之前已经成功拆过一次(共需拆两次)
if(FirstSucess==true)
{
BombDefused();
}
else
{
//如果之前没有成功拆过,则把这道题标记为已经做过
for(int i=0;i<12;i++)//set defused flag to 1
{
if(connectMatrix[activerow][2]==defusePin)
{
connectMatrix[activerow][3]=1;
}
}
//标记为之前的答案,标记为已经成功过一次,标记已经开始玩
previousdefusePin=defusePin;
FirstSucess=true;
StartStatus=false;
}
}
}
}
}
//屏幕显示成功,并播放音乐
void BombDefused()
{
lcd.clear();
lcd.print("Well Done");
EndStatus=true;
//响一阵音乐
for(int thisNote = 0; thisNote < 8; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[thisNote];
tone(BuzzPin, melody[thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(BuzzPin);
}
}
void TriggerBomb()
{
lcd.clear();
lcd.print("Mission Failed!");
digitalWrite(BuzzPin, HIGH);
//标记游戏结束
EndStatus=true;
//舵机转动,刺破气球
BombServo.write(120);
delay(100);
digitalWrite(BombRelayA, HIGH);
digitalWrite(BombRelayB, HIGH);
delay(500);
digitalWrite(BombRelayA, LOW);
digitalWrite(BombRelayB, LOW);
delay(5000);
digitalWrite(BuzzPin, LOW);
}
//剩余时间越少,响的频率越快
void SoundEffect(int time)
{
if(time>10)
{
digitalWrite(BuzzPin, HIGH);
delay(100);
digitalWrite(BuzzPin, LOW);
}
if(time<=10&&time>=5)
{
for(int i=0;i<3;i++)
{
digitalWrite(BuzzPin, HIGH);
delay(50);
digitalWrite(BuzzPin, LOW);
delay(50);
}
}
if(time<=5)
{
for(int i=0;i<8;i++)
{
digitalWrite(BuzzPin, HIGH);
delay(20);
digitalWrite(BuzzPin, LOW);
delay(20);
}
}
}