#include <IRremote.h>
// 各コンポーネントのピン定義
const int RECV_PIN = 2; // 赤外線センサ
const int LED_RED_PIN = 10; // 赤色LED
const int LED_GREEN_PIN = 9; // 緑色LED
const int LED_BLUE_PIN = 8; // 青色LED
const int SPEAKER_PIN = 13; // スピーカー
const int MOTOR1_PIN_A = 6; // モータ1
const int MOTOR1_PIN_B = 7;
const int MOTOR2_PIN_A = 4; // モータ2
const int MOTOR2_PIN_B = 5;
// リモコンの各ボタンのコード(ユーザー指定のHEX値)
#define CODE_FORWARD  0xFF02FD
#define CODE_BACKWARD 0xFF9867
#define CODE_RIGHT    0xFF906F
#define CODE_LEFT     0xFFE01F
#define CODE_1        0xFF30CF
#define CODE_2        0xFF18E7
#define CODE_3        0xFF7A85
#define CODE_4        0xFF10EF
#define CODE_5        0xFF38C7
#define CODE_6        0xFF5AA5
#define CODE_7        0xFF42BD
#define CODE_9        0xFF52AD
// IRremoteライブラリのインスタンス
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
  // ピンモード設定
  pinMode(RECV_PIN, INPUT);
  pinMode(LED_RED_PIN, OUTPUT);
  pinMode(LED_GREEN_PIN, OUTPUT);
  pinMode(LED_BLUE_PIN, OUTPUT);
  pinMode(SPEAKER_PIN, OUTPUT);
  pinMode(MOTOR1_PIN_A, OUTPUT);
  pinMode(MOTOR1_PIN_B, OUTPUT);
  pinMode(MOTOR2_PIN_A, OUTPUT);
  pinMode(MOTOR2_PIN_B, OUTPUT);
  // 赤外線受信の開始
  irrecv.enableIRIn();
}
void loop() {
  // 赤外線信号を受信
  if (irrecv.decode(&results)) {
    // ボタンのコードを比較して動作を実行
    switch (results.value) {
      case CODE_FORWARD:
        goForward();
        break;
      case CODE_BACKWARD:
        goBackward();
        break;
      case CODE_RIGHT:
        turnRight();
        break;
      case CODE_LEFT:
        turnLeft();
        break;
      case CODE_1:
        blinkLED(LED_RED_PIN, 1000);
        break;
      case CODE_2:
        blinkLED(LED_BLUE_PIN, 1000);
        break;
      case CODE_3:
        blinkLED(LED_GREEN_PIN, 1000);
        break;
      case CODE_4:
        blinkMultiLED(LED_RED_PIN, LED_BLUE_PIN, 1000);
        break;
      case CODE_5:
        blinkMultiLED(LED_GREEN_PIN, LED_BLUE_PIN, 1000);
        break;
      case CODE_6:
        blinkMultiLED(LED_GREEN_PIN, LED_RED_PIN, 1000);
        break;
      case CODE_7:
        blinkAllLEDs(1000);
        break;
      case CODE_9:
        resetArduino();
        break;
      default:
        // 上記以外のボタン
        defaultAction();
        break;
    }
    // 次の信号を受信可能にする
    irrecv.resume();
  }
}
// 1秒間前進
void goForward() {
  digitalWrite(LED_BLUE_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_BLUE_PIN, LOW);
 
  digitalWrite(MOTOR1_PIN_A, HIGH);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, HIGH);
  digitalWrite(MOTOR2_PIN_B, LOW);
  delay(1000);
  stopMotors();
}
// 1秒間後退
void goBackward() {
  digitalWrite(LED_GREEN_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_GREEN_PIN, LOW);
 
  digitalWrite(MOTOR1_PIN_A, LOW);
  digitalWrite(MOTOR1_PIN_B, HIGH);
  digitalWrite(MOTOR2_PIN_A, LOW);
  digitalWrite(MOTOR2_PIN_B, HIGH);
  delay(1000);
  stopMotors();
}
// 0.1秒右折後0.1秒前進
void turnRight() {
  digitalWrite(LED_RED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_RED_PIN, LOW);
 
  // 右折(片方のモータを前進、もう一方を停止)
  digitalWrite(MOTOR1_PIN_A, HIGH);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, LOW);
  digitalWrite(MOTOR2_PIN_B, LOW);
  delay(100);
 
  // 前進
  digitalWrite(MOTOR1_PIN_A, HIGH);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, HIGH);
  digitalWrite(MOTOR2_PIN_B, LOW);
  delay(100);
 
  stopMotors();
}
// 0.1秒左折後0.1秒前進
void turnLeft() {
  digitalWrite(LED_RED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_RED_PIN, LOW);
 
  // 左折(片方のモータを停止、もう一方を前進)
  digitalWrite(MOTOR1_PIN_A, LOW);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, HIGH);
  digitalWrite(MOTOR2_PIN_B, LOW);
  delay(100);
 
  // 前進
  digitalWrite(MOTOR1_PIN_A, HIGH);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, HIGH);
  digitalWrite(MOTOR2_PIN_B, LOW);
  delay(100);
 
  stopMotors();
}
// モータを停止
void stopMotors() {
  digitalWrite(MOTOR1_PIN_A, LOW);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, LOW);
  digitalWrite(MOTOR2_PIN_B, LOW);
}
// 単一LEDを点滅
void blinkLED(int pin, int duration) {
  digitalWrite(pin, HIGH);
  delay(duration);
  digitalWrite(pin, LOW);
}
// 複数LEDを同時に点灯
void blinkMultiLED(int pin1, int pin2, int duration) {
  digitalWrite(pin1, HIGH);
  digitalWrite(pin2, HIGH);
  delay(duration);
  digitalWrite(pin1, LOW);
  digitalWrite(pin2, LOW);
}
// 全LEDを点灯
void blinkAllLEDs(int duration) {
  digitalWrite(LED_RED_PIN, HIGH);
  digitalWrite(LED_GREEN_PIN, HIGH);
  digitalWrite(LED_BLUE_PIN, HIGH);
  delay(duration);
  digitalWrite(LED_RED_PIN, LOW);
  digitalWrite(LED_GREEN_PIN, LOW);
  digitalWrite(LED_BLUE_PIN, LOW);
}
// Arduinoをリセット
void resetArduino() {
  // ソフトウェアリセットの代わりに、簡潔なメッセージを表示して通知
  // ハードウェアリセットは、外部の回路やボタンを使用する必要があるため、
  // この例ではソフトウェアで可能な範囲で対応
  Serial.println("Arduino is resetting...");
  // 実際のリセットは、asm("jmp 0;") を使用することが多いが、
  // IRremoteライブラリとの互換性や安定性を考慮し、
  // ここでは動作を停止してリセット状態をシミュレート
  stopMotors();
  delay(100);
  digitalWrite(LED_RED_PIN, HIGH);
  digitalWrite(LED_GREEN_PIN, HIGH);
  digitalWrite(LED_BLUE_PIN, HIGH);
  delay(2000);
  digitalWrite(LED_RED_PIN, LOW);
  digitalWrite(LED_GREEN_PIN, LOW);
  digitalWrite(LED_BLUE_PIN, LOW);
}
// その他のボタンの動作
void defaultAction() {
  // 0.3秒前進
  digitalWrite(MOTOR1_PIN_A, HIGH);
  digitalWrite(MOTOR1_PIN_B, LOW);
  digitalWrite(MOTOR2_PIN_A, HIGH);
  digitalWrite(MOTOR2_PIN_B, LOW);
 
  // スピーカーを0.3秒鳴らす
  tone(SPEAKER_PIN, 1000); // 1000Hzの音
 
  delay(300);
 
  stopMotors();
  noTone(SPEAKER_PIN);
}