// 『昼夜逆転』工作室 http://jsdiy.web.fc2.com/ // ATtiny2313 // 7セグ4桁ボード // // 箱 // // 2008/10/10 v1.00 初版 /* 【ゲーム内容】 3個の箱の位置を当てるゲーム。 【ゲームの始め方】 電源オンでタイトル画面「HAKO」。 スイッチA0/A1でゲーム開始。 【ゲームの操作方法】 1〜3桁目が箱、4桁目が現在当たっている個数。 スイッチA0: 桁を移動する。「.」が付いている桁が現在操作できる。 スイッチA1: 1〜3桁目のとき、箱を上下する。 4桁目のとき、解答する。 【判定】 解答は3回まで。 正解すると「Good」、スイッチA0/A1で次の問題へ。 外れると、現在当たっている個数が表示される。ゲーム続行。 3回目も外れると「bYE」、スイッチA0/A1でタイトル画面へ。 */ /* ポート対応 [ATtiny2313] bit 7 6 5 4 3 2 1 0 PORTA - - - - - - swL swR PORTB - - - DP 桁4 桁3 桁2 桁1 LEDボードでは左から桁1-桁4 PORTD - G F E D C B A 7セグのセグメント(下図) 7セグのセグメント図 +-A-+ F B +-G-+ E C +-D-+ DP */ #define _CATHODE_CMN_ 0 #if _CATHODE_CMN_ #define SET_PORTB(n) PORTB = (n) #define SET_PORTD(n) PORTD = (n) #else #define SET_PORTB(n) PORTB = (~(n) & 0b00011111) #define SET_PORTD(n) PORTD = (~(n) & 0b01111111) #endif #include #include const uint8_t SEGCHAR[] = { // 0b0GFEDCBA 0b00111111, //0 0b00000110, //1 0b01011011, //2 0b01001111, //3 0b01100110, //4 0b01101101, //5 0b01111101, //6 0b00100111, //7 0b01111111, //8 0b01101111, //9 0b00000000, //null // 0b0GFEDCBA 0b01100011, //箱・上 0b01011100, //箱・下 0b01110110, //H 0b01110111, //A 0b01110101, //K 0b00111111, //O 0b00111101, //G 0b01011100, //o 「箱・下」と同じ形だが敢えて区別する 0b01011110, //d 0b01111100, //b 0b01101110, //Y 0b01111001 //E }; enum _SIDX { SIDX_NULL = 10, SIDX_UP, SIDX_DOWN, SIDX_H, SIDX_A, SIDX_K, SIDX_O, SIDX_G, SIDX_o, SIDX_d, SIDX_b, SIDX_Y, SIDX_E }; #define SEG_DP 0b00010000 enum _STATUS { ST_TITLE, ST_INIT, ST_PLAY, ST_CLEAR, ST_OVER }; #define MAX_ANS 3 //解答できる回数 int main(void) { uint8_t sidx[4] = {0}; uint8_t segDP[4] = {0}; uint8_t k, state, i; uint8_t sw, psw, loopCnt; uint8_t swOnA[2] = {0}; //スイッチの入力状態 1:on 0:off uint8_t box[3] = {0}, ans[3] = {0}; //出題(正解)、解答(プレイヤーの入力) uint8_t idx; //操作中の桁のインデックス uint8_t flgAns; //解答操作をしたことのフラグ uint8_t ansCnt; //解答回数 uint8_t hitCnt; //当たってる個数 //ポート設定 DDRD = 0b01111111; //7セグLEDのA-G = PD0-PD6 DDRB = 0b00011111; //7セグLEDの桁位置(LEDボードの左から) = PB0-PB3, 7セグLEDのDP = PB4 PORTA = 0b00000011; //スイッチが2個(制御ボードの右から) PA0-PA1 state = ST_TITLE; k = 0; sw = psw = 0; loopCnt = 0; idx = 0; flgAns = 0; ansCnt = 0; while (1) { //スイッチ読み取り swOnA[0] = swOnA[1] = 0; if ((++loopCnt & 0x40) == 0x40) //チャタリングが回避できる程度にループ間隔を空ける { sw = PINA; if (psw != sw) { swOnA[0] = ~sw & 0b00000001; swOnA[1] = ~sw & 0b00000010; psw = sw; } } //動作状態 switch (state) { case ST_INIT: sidx[0] = sidx[1] = sidx[2] = SIDX_DOWN; sidx[3] = SIDX_NULL; segDP[0] = SEG_DP; segDP[1] = segDP[2] = segDP[3] = 0; idx = 0; for (i = 0; i < 3; i++) box[i] = rand() % 2; ans[0] = ans[1] = ans[2] = 0; ansCnt = 0; flgAns = 0; state = ST_PLAY; break; case ST_PLAY: //桁移動 if (swOnA[0]) { segDP[idx] = 0; idx = (idx + 1) % 4; segDP[idx] = SEG_DP; //解答直後の移動だったと仮定して sidx[3] = SIDX_NULL; flgAns = 0; } //箱の上下 if (swOnA[1] && idx < 3) { ans[idx] = 1 - ans[idx]; sidx[idx] = ans[idx] ? SIDX_UP : SIDX_DOWN; } //解答 //前回の解答から桁移動せずに再度スイッチを押しても無効とするため、flgAnsをチェックする if (swOnA[1] && idx == 3 && !flgAns) { flgAns = 1; hitCnt = 0; for (i = 0; i < 3; i++) if (box[i] == ans[i]) hitCnt++; sidx[3] = hitCnt; if (hitCnt == 3) state = ST_CLEAR; else if (++ansCnt == MAX_ANS) state = ST_OVER; } break; case ST_CLEAR: sidx[0] = SIDX_G; sidx[1] = SIDX_o; sidx[2] = SIDX_o; sidx[3] = SIDX_d; segDP[0] = segDP[1] = segDP[2] = segDP[3] = 0; if (swOnA[0] || swOnA[1]) state = ST_INIT; break; case ST_OVER: sidx[0] = SIDX_b; sidx[1] = SIDX_Y; sidx[2] = SIDX_E; sidx[3] = SIDX_NULL; segDP[0] = segDP[1] = segDP[2] = segDP[3] = 0; if (swOnA[0] || swOnA[1]) state = ST_TITLE; break; default: //ST_TITLE sidx[0] = SIDX_H; sidx[1] = SIDX_A; sidx[2] = SIDX_K; sidx[3] = SIDX_O; segDP[0] = segDP[1] = segDP[2] = segDP[3] = 0; if (swOnA[0] || swOnA[1]) { srand(loopCnt); state = ST_INIT; } break; } //表示 SET_PORTB(0); SET_PORTD(0); SET_PORTB((1<< k) | segDP[k]); SET_PORTD(SEGCHAR[sidx[k]]); k = (k + 1) % 4; } return 0; }