Newer
Older
IoTprograming_A3_juggler / reel_center
//中リール
#include <M5Unified.h>
#include <esp_now.h>
#include <WiFi.h>

// =========================================================================
// 1. 画像データ(幅135px × 高さ1680px、16bit RGB565)
// =========================================================================
const uint16_t reel_image_data[226800] PROGMEM = {

  //----------------------カラーコードの塊のため省略----------------------

};
// =========================================================================
// 2. ソフトウェア制御用の設定
// =========================================================================

// --- 図柄の定義 ---
enum SymbolType {
  GRAPE = 0,  // ブドウ
  SEVEN = 1,  // 赤7
  BAR   = 2,  // BAR
  BELL  = 3,  // ベル
  RHINO = 4,  // ツノッチ(サイ)
  CLOWN = 5,  // ピエロ
  CHERRY= 6   // チェリー
  };

const int TOTAL_SYMBOLS = 21;      // 総図柄数
const int MY_REEL_ID = 1;
// --- リールの配列 ---
const SymbolType reel_array[TOTAL_SYMBOLS] = {
  RHINO, SEVEN, GRAPE, CHERRY, RHINO, BELL, GRAPE, CHERRY, RHINO, BAR, GRAPE,
  CHERRY, RHINO, BELL, GRAPE, CHERRY, RHINO, BAR, GRAPE, CHERRY, CLOWN
  };

// --- 内部フラグ(成立役)の定義 ---
enum InternalFlag {
  FLAG_BLANK  = 0, // ハズレ
  FLAG_REPLAY = 1, // リプレイ
  FLAG_GRAPE  = 2, // ブドウ
  FLAG_CHERRY = 3, // チェリー
  FLAG_BELL   = 4, // ベル
  FLAG_CLOWN  = 5, // ピエロ
  FLAG_BIG    = 6, // BIG
  FLAG_REG    = 7  // REG
  };

InternalFlag current_flag = FLAG_BLANK; // 現在の内部状態

// --- 左リール 第一停止用の制御表(下段基準) ---
// [注]引数0~20→図柄番号21~1
const int slip_tables[8][21] = {
  // [0] FLAG_BLANK (ハズレ)
  {2, 0, 1, 2, 2, 4, 3, 1, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1},
  // [1] FLAG_REPLAY (リプレイ)
  {2, 2, 0, 1, 0, 1, 0, 2, 4, 4, 0, 1, 1, 3, 4, 4, 2, 2, 4, 0, 1},
  // [2] FLAG_GRAPE (ブドウ)
  {2, 1, 1, 2, 0, 1, 0, 2, 4, 4, 0, 1, 2, 0, 0, 0, 2, 4, 4, 0, 1},
  // [3] FLAG_CHERRY (チェリー)
  {3, 4, 0, 4, 0, 4, 0, 0, 1, 2, 1, 4, 3, 4, 0, 0, 0, 1, 2, 1, 4},
  // [4] FLAG_BELL (ベル)
  {0, 1, 2, 2, 4, 4, 4, 2, 4, 4, 0, 1, 2, 1, 0, 0, 2, 4, 4, 0, 1},
  // [5] FLAG_CLOWN (ピエロ)
  {2, 1, 0, 4, 0, 4, 0, 2, 4, 4, 0, 1, 0, 1, 2, 3, 3, 3, 4, 0, 1},
  // [6] FLAG_BIG (BIGボーナス)
  {2, 0, 1, 2, 2, 4, 4, 4, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1},
  // [7] FLAG_REG (REGボーナス)
  {2, 0, 1, 2, 2, 4, 4, 4, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 3, 0, 1}
};

// =========================================================================
// 通信設定
// =========================================================================
// メイン機から受け取る「命令とテーブル」
typedef struct struct_main_to_reel {
  int command;
  int slip_table[21]; // メイン機が計算した21コマ分の滑り表
} struct_main_to_reel;
struct_main_to_reel receiveData;

// メイン機へ報告する「停止位置」
typedef struct struct_reel_to_main {
  int reel_id = 1;
  int stopped_index;
} struct_reel_to_main;
struct_reel_to_main reportData;

// 一斉送信(ブロードキャストアドレス)
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
esp_now_peer_info_t peerInfo;

enum ReelState { STOPPED, SPINNING, SLIPPING };
ReelState reel_state = STOPPED;

// --- メイン機からデータを受け取った時の処理 ---
void OnDataRecv(const esp_now_recv_info *info, const uint8_t *incomingData, int len) {
  // データの重さがメイン機からの「命令+テーブル」と一致した場合のみ処理
  if (len == sizeof(struct_main_to_reel)) {
    struct_main_to_reel temp;
    memcpy(&temp, incomingData, sizeof(temp));

    // commandが 99(全員一斉回転) か、自分のID(0〜2)宛ての専用テーブルの時のみ
    if (temp.command == 99 || temp.command == MY_REEL_ID) {
      memcpy(&receiveData, &temp, sizeof(receiveData));

      if (temp.command == 99 && reel_state == STOPPED) {
        reel_state = SPINNING;
        Serial.println(">> 全リール一斉回転スタート!");
      } else if (temp.command == MY_REEL_ID) {
        Serial.println(">> AIから最新の滑りテーブルを受信・更新しました");
      }
    }
  }
}

// =========================================================================
// ハードウェア設定
// =========================================================================
const int SYMBOL_W = 135;  const int SYMBOL_H = 80;
const int REEL_H = 1680;   const int WINDOW_H = 240;
M5Canvas canvas(&M5.Display);

int current_y = 0; int target_y = 0; int bita_y = 0; int scroll_speed = 48;

void setup() {
  auto cfg = M5.config(); M5.begin(cfg); Serial.begin(115200);
  M5.Display.setRotation(0); M5.Display.fillScreen(TFT_BLACK);
  canvas.createSprite(SYMBOL_W, WINDOW_H); canvas.setSwapBytes(true);

  WiFi.mode(WIFI_STA);
  if (esp_now_init() != ESP_OK) return;

  // 受信設定
  esp_now_register_recv_cb(OnDataRecv);

  // 送信設定
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0; peerInfo.encrypt = false;
  esp_now_add_peer(&peerInfo);
}

void loop() {
  M5.update();

  // --- Aボタン(ストップボタン) ---
  if (M5.BtnA.wasPressed()) {
    if (reel_state == SPINNING) {
      reel_state = SLIPPING;
      bita_y = (current_y / SYMBOL_H) * SYMBOL_H;
      int bita_top_index = bita_y / SYMBOL_H;
      int bita_btm_index = (bita_top_index + 2) % TOTAL_SYMBOLS;

      int slip_frames = receiveData.slip_table[bita_btm_index];

      target_y = bita_y - (slip_frames * SYMBOL_H);
      if (target_y < 0) target_y += REEL_H;
    }
  }

  // --- 回転・滑り処理 ---
  if (reel_state == SPINNING) {
    current_y -= scroll_speed;
    if (current_y < 0) current_y += REEL_H;
  } 
  else if (reel_state == SLIPPING) {
    int distance = current_y - target_y;
    if (distance < 0) distance += REEL_H;

    if (distance <= scroll_speed) {
      current_y = target_y;
      reel_state = STOPPED;

      int top_index = current_y / SYMBOL_H;
      int btm_index = (top_index + 2) % TOTAL_SYMBOLS;

      reportData.reel_id = 1;
      reportData.stopped_index = btm_index;
      esp_now_send(broadcastAddress, (uint8_t *) &reportData, sizeof(reportData));

      Serial.printf("【完了】下段インデックス %d で停止。メイン機へ報告しました。\n", btm_index);
    } else {
      current_y -= scroll_speed;
      if (current_y < 0) current_y += REEL_H;
    }
  }

  // --- 描画処理 ---
  if (current_y + WINDOW_H <= REEL_H) {
    canvas.pushImage(0, 0, SYMBOL_W, WINDOW_H, (uint16_t*)reel_image_data + (current_y * SYMBOL_W));
  } else {
    int first_part_h = REEL_H - current_y;
    int second_part_h = WINDOW_H - first_part_h;
    canvas.pushImage(0, 0, SYMBOL_W, first_part_h, (uint16_t*)reel_image_data + (current_y * SYMBOL_W));
    canvas.pushImage(0, first_part_h, SYMBOL_W, second_part_h, (uint16_t*)reel_image_data);
  }
  canvas.pushSprite(0, 0); delay(5);
}