サンプルプログラム:2 音階当てゲーム作成中っぽい何か。2


昨日は土曜出勤で音周りの作業ができない為
全然関係ないジャンケンゲームのプログラム構造練ってました。
自分なりに良い感じの構造が捻出できてて、
モジュール考えるのが今凄く楽しかったりしてます。
でも規模が今の程じゃないですが多少あるので時間掛かりそうな予感です。


「音階当てゲーム」できました。



大人の科学本誌よりも詳しい説明のある FX-マイコン PDF マニュアルの
「No.3 音階当てゲーム」の記述を実装してます。
同名のプログラムリストが No.98 としても収録されてますが
説明とフローチャートを見る限り、内蔵プログラムのものと動作が違うようなので参考にしませんでした。


プログラム構造を練るため紙にフローチャート殴り書き。
実機挙動などのコメントも色々記述。

プログラム構造に併せてコメントだけのソース作成。

コメントと一致するプログラムを作成。


ダイレクトなプログラム構造を書きたいときはやっぱりフローチャートが便利というか
紙と鉛筆しかない状況だとこれが直感的で手っ取り早いと。
PCが前にあってもフローが固まってないときとかも、紙にまとめるのは有用なのかもと思ってます。


音階生成のシード値に time(NULL) を使ってますが、
RTC がちゃんと動作するNDS エミュが(知る限り)ないので
srand() してるのに値が変わらないです。
実機ではちゃんと NOTE_QUIZ_INIT へ遷移する度にシード値が変化します。


ゲームを全問正解したら「終了音が出て、得点"A"(10点)が表示されます。」という記述がマニュアルにあって、
その通りの実装してますが実機で全問正解を1度も達成してない為、
GMC-4 的に正しい動作なのかまだ分かりません。


モジュールはこんな感じになりました。
各モジュールも微妙な手直しが発生したりしてます。
最初から完璧なもの作れるわけないのですが、ちょくちょく手直し入るのも結構萎えます。


NoteQuiz.h

/*---------------------------------------------------------------------------------
	
	Sample2 NoteQuiz module header
	
	version 0.01
	Nov 29, 2009
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#ifndef _NOTE_QUIZ_H_
#define _NOTE_QUIZ_H_


#ifdef __cplusplus
extern "C" {
#endif


void NoteQuiz_Update(void);
void NoteQuiz_Clear(void);
bool NoteQuiz_IsExit(void);


#ifdef __cplusplus
}
#endif

#endif	//_NOTE_QUIZ_H_


NoteQuiz.c

/*---------------------------------------------------------------------------------
	
	Sample2 NoteQuiz  module routine
	
	version 0.01
	Nov 29, 2009
	
	By. REGEKATSU
	
---------------------------------------------------------------------------------*/

#include <stdio.h>//debug print

#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <nds/ndstypes.h>

#include "NoteQuiz.h"

#include "Outport.h"
#include "Key.h"
#include "KeyState.h"
#include "Amp.h"


#define ROUND_MAX 10


typedef enum{
	
	NOTE_QUIZ_INIT, 
	NOTE_QUIZ_PLAY, 
	NOTE_QUIZ_EXIT
	
}NOTE_QUIZ_ACT;


typedef enum{
	
	NOTE_QUIZ_PLAY_INIT, 
	NOTE_QUIZ_PLAY_START, 
	NOTE_QUIZ_PLAY_QUES, 
	NOTE_QUIZ_PLAY_ANS, 
	NOTE_QUIZ_PLAY_STOP, 
	NOTE_QUIZ_PLAY_END
	
}NOTE_QUIZ_PLAY_ACT;


typedef struct{
	
	u16 act;
	u16 play_act;
	
	u8 round;
	u8 note_cnt;
	u8 note_buf[ROUND_MAX + 1];
	
}NoteQuizStatus;


static NoteQuizStatus st_note_quiz;


void noteQuiz_Init(void);
void noteQuiz_Play(void);
void noteQuiz_Exit(void);


//---------------------------------------------------------------------------------
void noteQuiz_Init(void) {
//---------------------------------------------------------------------------------
	
	srand(time(NULL));
	memset(&st_note_quiz, 0, sizeof(st_note_quiz));
	
	st_note_quiz.act = NOTE_QUIZ_PLAY;
	
}

//---------------------------------------------------------------------------------
void noteQuiz_Play(void) {
//---------------------------------------------------------------------------------
	
	static int interval = 0;
	u8 key;
	
	
	switch(st_note_quiz.play_act){
		
	//ゲーム初期化
	case NOTE_QUIZ_PLAY_INIT:
		
		st_note_quiz.round = 0;
		
		//出題音の生成
		int rnd, i;
		
		for(i = 0;i < ROUND_MAX + 1;i++){
			
			//1〜14までの範囲の乱数をセットする
			rnd = rand() % (NOTE_G_UP - NOTE_A_DOWN + 1) + NOTE_A_DOWN;
			st_note_quiz.note_buf[i] = (u8)rnd;
			
		}
		
		//最初の1音は必ずドの音になる
		st_note_quiz.note_buf[0] = NOTE_C;
		
		Outport_HideBinLED();
		Outport_HideNumLED();
		
		st_note_quiz.play_act = NOTE_QUIZ_PLAY_START;
		
		break;
		
		
	//ゲーム開始
	case NOTE_QUIZ_PLAY_START:
		
		//ラウンド数をインクリメントする
		st_note_quiz.round++;
		
		//ラウンドMAXを越えてたらゲーム終了する
		if(st_note_quiz.round > ROUND_MAX){
			
			Amp_CallEndSound();
			st_note_quiz.play_act = NOTE_QUIZ_PLAY_STOP;
			
		//ラウンドMAX以内ならゲーム続行する
		}else{
			
			Amp_PlaySound(NOTE_REST, AMP_SET_TIME(3));//ラウンド間の間隔を置く
			st_note_quiz.note_cnt = 0;
			st_note_quiz.play_act = NOTE_QUIZ_PLAY_QUES;
			
		}
		
		break;
		
		
	//出題音の再生
	case NOTE_QUIZ_PLAY_QUES:
		
		//出題音をラウンドに応じた数だけ再生する
		if(st_note_quiz.note_cnt <= st_note_quiz.round){
			
			//1音間の間隔を置く
			if(Amp_IsStopSound() && interval){
				Amp_PlaySound(NOTE_REST, AMP_SET_FRAME(1));
				interval = 0;
				
			//1音再生する
			}else if(Amp_IsStopSound()){
				Amp_PlaySound(st_note_quiz.note_buf[ st_note_quiz.note_cnt ++ ], AMP_SET_TIME(3));
				interval = 1;
				
			}
			
		//出題音の再生を全て終えた
		}else if(Amp_IsStopSound() && (st_note_quiz.note_cnt > st_note_quiz.round)){
			
			st_note_quiz.note_cnt = 0;
			st_note_quiz.play_act = NOTE_QUIZ_PLAY_ANS;
			
		}
		
		break;
		
		
	//出題音の回答
	case NOTE_QUIZ_PLAY_ANS:
		
		if(Amp_IsStopSound() && Key_IsKeyDown()){
			
			key = Key_GetKeyValue();
			
			if(key >= KEYPAD_1 && key <= KEYPAD_E){
				
				//出題音と等しい入力かどうか入力毎にラウンド値分、0からチェックする
				if(key == st_note_quiz.note_buf[ st_note_quiz.note_cnt ++ ]){
					Amp_PlaySound(key, AMP_SET_TIME(3));
					Outport_ShowNumLED(key);
					
				//一音でも入力間違いがあったらエラー音を再生してゲーム終了する
				}else{
					Amp_CallErrorSound();
					st_note_quiz.play_act = NOTE_QUIZ_PLAY_STOP;
					
				}
				
			}else if(key == KEYPAD_0 || key == KEYPAD_F){
				Outport_ShowNumLED(key);
				
			}
			
		}
		
		//入力が全て正しければ次のラウンドに進む
		if( Amp_IsStopSound() && (st_note_quiz.note_cnt > st_note_quiz.round) ){
			st_note_quiz.play_act = NOTE_QUIZ_PLAY_START;
		}
		
		break;
		
		
	//ゲーム終了
	case NOTE_QUIZ_PLAY_STOP:
		
		//得点(ラウンド数 - 1)を7セグへ表示する
		if(Amp_IsStopSound()){
			Outport_ShowNumLED(st_note_quiz.round - 1);
			st_note_quiz.play_act = NOTE_QUIZ_PLAY_END;
		}
		
		break;
		
		
	//ゲームの再スタート/モニタへ戻る かの選択を待つ
	case NOTE_QUIZ_PLAY_END:
		
		if(Key_IsKeyDown()){
			
			key = Key_GetKeyValue();
			
			//RUNならゲームを再スタートする
			if(key == KEYPAD_RUN){
				st_note_quiz.play_act = NOTE_QUIZ_PLAY_INIT;
				
			//RESETならゲーム終了してモニタへ戻る
			}else if(key == KEYPAD_RESET){
				st_note_quiz.act = NOTE_QUIZ_EXIT;
				
			}
			
		}
		
		break;
		
		
	}
	
}

//---------------------------------------------------------------------------------
void noteQuiz_Exit(void) {
//---------------------------------------------------------------------------------
	
	st_note_quiz.act = NOTE_QUIZ_INIT;
	
}



//---------------------------------------------------------------------------------
void NoteQuiz_Update(void) {
//---------------------------------------------------------------------------------
	
	//debug print (cheating)
	int i;
	printf("\x01b[4;0Hdebug print (cheating)\n");
	for(i = 0;i < ROUND_MAX + 1;i++){
		printf(" %01X", st_note_quiz.note_buf[i]);
	}
	
	
	switch(st_note_quiz.act){
		
	case NOTE_QUIZ_INIT:
		noteQuiz_Init();
		break;
		
	case NOTE_QUIZ_PLAY:
		noteQuiz_Play();
		break;
		
	case NOTE_QUIZ_EXIT:
		noteQuiz_Exit();
		break;
		
	}
	
}

//---------------------------------------------------------------------------------
void NoteQuiz_Clear(void) {
//---------------------------------------------------------------------------------
	
	st_note_quiz.act = NOTE_QUIZ_INIT;
	
}

//---------------------------------------------------------------------------------
bool NoteQuiz_IsExit(void) {
//---------------------------------------------------------------------------------
	
	return (st_note_quiz.act == NOTE_QUIZ_INIT) ? true:false;
	
}

//---------------------------------------------------------------------------------