バイオリズム。2
この前のバイオリズムに年月変更操作を追記しました。
誕生日は変わらずマジックナンバーです。
題材とするアルゴリズムに含まれない部分は敢えて書いてません。
NDS の方だけは本体設定の誕生日から取得しようかと思ったのですが
元々誕生年が設定できない仕様な為、実装は止めました(月日だけじゃバイオリズムは割り出せないので。)。
本体設定の表示方法とかはそのうち書いておきます。
ヘッダ見る限りでは ARM9 から拾える感じでした。
但しメッセージとかニックネームの 2 バイト文字は UTF-16 だったりするので
この辺になると日本語ライブラリ作ってそれを使った説明とかになると思います。
結構前の Shift-JIS 決め打ちな作りかけが…。
devkitPro - NDS 版
・ビルド手順
1. 下記ソースを *.c ファイルに保存。 2. /* コンパイラ_ターゲットの選択設定 */ の部分にある #define _VC2010_WIN_ をコメントアウトして、 #define _DEVKITPRO_NDS_ のコメントアウトを取り除く。 3. devkitPro/examples/nds/templates/arm9 等のテンプレートプロジェクトを流用して ./source/main.c を *.c と差し替える。 4. Makefile のリンクオプションに "-lm" を追記してビルド。 LIBS := -lnds9 -lm
Visual C++ 2010 - Win32 コンソール版
・ビルド手順
1. 下記ソースを *.c ファイルに保存。 2. /* コンパイラ_ターゲットの選択設定 */ の部分にある #define _DEVKITPRO_NDS_ をコメントアウトして、 #define _VC2010_WIN_ のコメントアウトを取り除く。 3. ファイル-新規作成-プロジェクト-Win32 コンソール アプリケーション で空のプロジェクト作って ソース ファイル-追加-既存の項目 で *.c を追加してビルド。
main.c
/*--------------------------------------------------------------------------------- Biorhythm version 0.011 Dec 11, 2011 By REGEKATU ---------------------------------------------------------------------------------*/ /* コンパイラ_ターゲットの選択設定 */ //#define _VC2010_WIN_ #define _DEVKITPRO_NDS_ #ifdef _VC2010_WIN_ #define _USE_MATH_DEFINES #endif #include <math.h> #include <stdio.h> #include <time.h> #ifdef _VC2010_WIN_ #include <Windows.h> #endif #ifdef _DEVKITPRO_NDS_ #include <nds.h> #endif /* ブール型定義 */ #ifndef bool #define bool unsigned char #endif #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif /* コンソール定数 */ #ifdef _VC2010_WIN_ #define CONSOLE_WIDTH 80 /* 表示環境の横表示可能文字数*/ #define CONSOLE_HEIGHT 25 /* 表示環境の縦表示可能文字数*/ #endif #ifdef _DEVKITPRO_NDS_ #define CONSOLE_WIDTH 32 /* 表示環境の横表示可能文字数*/ #define CONSOLE_HEIGHT 24 /* 表示環境の縦表示可能文字数*/ #endif typedef enum{ /* setColor 関数用色定義 */ L_BLACK = 0, /* \x1b[30m 低輝度・黒色 */ L_BLUE, /* \x1b[34m 低輝度・青色 */ L_GREEN, /* \x1b[32m 低輝度・緑色 */ L_CYAN, /* \x1b[36m 低輝度・水色 */ L_RED, /* \x1b[31m 低輝度・赤色 */ L_PURPLE, /* \x1b[35m 低輝度・紫色 */ L_YELLOW, /* \x1b[33m 低輝度・黄色 */ L_WHITE, /* \x1b[37m 低輝度・白色 */ H_BLACK, /* \x1b[40m 高輝度・黒色 */ H_BLUE, /* \x1b[44m 高輝度・青色 */ H_GREEN, /* \x1b[42m 高輝度・緑色 */ H_CYAN, /* \x1b[46m 高輝度・水色 */ H_RED, /* \x1b[41m 高輝度・赤色 */ H_PURPLE, /* \x1b[45m 高輝度・紫色 */ H_YELLOW, /* \x1b[43m 高輝度・黄色 */ H_WHITE /* \x1b[47m 高輝度・白色 */ }COLOR; /* バイオリズム定数 */ typedef enum{ /* 生命の周期 */ CYCLE_PHYSICAL = 23, /* 身体の周期 */ CYCLE_SENSITIVITY = 28, /* 感情の周期 */ CYCLE_INTELLECUTUAL = 33 /* 知性の周期 */ }CYCLE; #define CURVE_TO_POS(c) ((int)(c * 5.3) * -1 + 5) /* サインカーブ値を文字表示の位置情報に変換する */ typedef enum{ /* 状態遷移定数 */ INIT = 0, /* プログラム初期化 */ DRAW, /* バイオリズム表示 */ READY /* 表示年月変更待ち */ }ACT; /* コンソール変数 */ #ifdef _VC2010_WIN_ HANDLE hOut; /* コンソールスクリーンバッファのハンドル */ COORD dwPos; /* コンソールスクリーンカーソル指定用構造体 */ CONSOLE_SCREEN_BUFFER_INFO csbi; /* コンソールスクリーンバッファ情報の構造体 */ DWORD written; /* 書き込まれたセル数へのポインタ */ #endif /* バイオリズム変数 */ int act; /* 状態遷移変数 */ int birth_year; /* 誕生年 */ int birth_month; /* 誕生月 */ int birth_day; /* 誕生日 */ int now_year; /* 現在表示年 */ int now_month; /* 現在表示月 */ int old_year; /* 前回表示年 */ int old_month; /* 前回表示月 */ /* メイン関数 */ int main(void); /* メインプログラム */ /* バイオリズム関数 */ void drawBiorhythm(int birth_year, int birth_month, int birth_day, /* 指定した誕生日に対する指定年月の、バイオリズムを表示する */ int year, int month); double getBioCurve(int birth_year, int birth_month, int birth_day, /* 指定した誕生日に対する指定日の、指定周期に対するサインカーブ値を返す */ int year, int month, int day, int cycle); /* 日付関数 */ int getDateDiff(int year1, int month1, int day1, int year2, int month2, int day2); /* 指定された2つの年月日の差を日数で返す */ int getDayOfYear(int year, int month, int day); /* 指定された年月日の年間積算日を返す */ int getDaysInYear(int year); /* 指定した年の日数を返す */ int getDaysInMonth(int year, int month); /* 指定年の、指定した月の日数を返す */ bool isLeapYear(int year); /* 指定した年が閏年かどうかを確認する */ void addYears(int year1, int* year2, int years); /* 指定した年から指定した年数が経過した後の年を返す */ void addMonths(int year1, int month1, int* year2, int* month2, int months); /* 指定した年月から指定した月数が経過した後の年月を返す */ /* コンソール関数 */ void setLocate(int x, int y); /* 文字の表示位置を設定する */ void setColor(int fore, int back); /* 文字の表示色、背景色を設定する */ void clearScreen(void); /* コンソール画面を消去する */ //--------------------------------------------------------------------------------- int main(void){ //--------------------------------------------------------------------------------- /* メインプログラム */ time_t timer; struct tm tm; #ifdef _DEVKITPRO_NDS_ /* キーリピートを設定する */ unsigned long keys; keysSetRepeat(30, 1); #endif /* コンソールを初期化する */ #ifdef _VC2010_WIN_ hOut = GetStdHandle(STD_OUTPUT_HANDLE); #endif #ifdef _DEVKITPRO_NDS_ consoleDemoInit(); #endif /* メインループ */ while(1){ /* ゲームを一定間隔で更新する */ #ifdef _VC2010_WIN_ Sleep(16); #endif #ifdef _DEVKITPRO_NDS_ swiWaitForVBlank(); #endif #ifdef _DEVKITPRO_NDS_ /* キー情報を更新する */ scanKeys(); keys = keysDownRepeat(); #endif switch(act){ /* プログラム初期化 */ case INIT: /* 誕生日を設定する */ birth_year = 2000; birth_month = 9; birth_day = 13; /* 現在の日時を取得する */ timer = time(NULL); #ifdef _VC2010_WIN_ localtime_s(&tm, (const time_t *)&timer); #else tm = *localtime((const time_t *)&timer); #endif /* 表示する年月を設定する */ old_year = now_year = tm.tm_year + 1900; old_month = now_month = tm.tm_mon + 1; act = DRAW; break; /* バイオリズム表示 */ case DRAW: /* バイオリズムを表示する */ drawBiorhythm(birth_year, birth_month, birth_day, now_year, now_month); act = READY; break; /* 表示年月変更待ち */ case READY: /* 先月に進める */ #ifdef _VC2010_WIN_ if(GetAsyncKeyState(VK_LEFT) == 0xffff8001){ #endif #ifdef _DEVKITPRO_NDS_ if(keys & KEY_LEFT){ #endif old_year = now_year; old_month = now_month; addMonths(old_year, old_month, &now_year, &now_month, -1); act = DRAW; } /* 次月に進める */ #ifdef _VC2010_WIN_ if(GetAsyncKeyState(VK_RIGHT) == 0xffff8001){ #endif #ifdef _DEVKITPRO_NDS_ if(keys & KEY_RIGHT){ #endif old_year = now_year; old_month = now_month; addMonths(old_year, old_month, &now_year, &now_month, 1); act = DRAW; } break; } } } //--------------------------------------------------------------------------------- void drawBiorhythm(int birth_year, int birth_month, int birth_day, int year, int month){ //--------------------------------------------------------------------------------- /* 指定した誕生日に対する指定年月の、バイオリズムを表示する */ int i, temp_year, temp_month; double curve; /* 画面を消去して、文字色を白に設定する */ clearScreen(); setColor(H_WHITE, L_BLACK); /* タイトル、バージョン、コピーライトを表示する */ setLocate(1, 0); printf("Biorhythm ver 0.01 By REGEKATU"); /* 誕生日を表示する */ setLocate(1, 2); printf("your birthday %4d/%2d/%2d", birth_year, birth_month, birth_day); /* 描画年月を表示する */ setLocate(1, 4); printf("draw month & years %4d/%2d", year, month); /* 日付を表示する */ for(i = 1;i <= getDaysInMonth(year, month);i++){ if(i % 10 == 0){ setLocate(i, 6); printf("%d", i / 10); } } for(i = 1;i <= getDaysInMonth(year, month);i++){ setLocate(i, 7); printf("%d", i % 10); } /* 罫線を表示する */ for(i = 1;i <= getDaysInMonth(year, month);i++){ setLocate(i, 13); printf("-"); } for(i = 0;i <= 10;i++){ setLocate(0, i + 8); if(i == 0) printf("+"); else if(i == 5) printf("0"); else if(i == 10) printf("-"); else printf("|"); } /* 身体の周期を赤で表示する */ setColor(H_RED, L_BLACK); for(i = 1;i <= getDaysInMonth(year, month);i++){ curve = getBioCurve(birth_year, birth_month, birth_day, year, month, i, CYCLE_PHYSICAL); setLocate(i, CURVE_TO_POS(curve) + 8); printf("P"); } /* 感情の周期を緑で表示する */ setColor(H_GREEN, L_BLACK); for(i = 1;i <= getDaysInMonth(year, month);i++){ curve = getBioCurve(birth_year, birth_month, birth_day, year, month, i, CYCLE_SENSITIVITY); setLocate(i, CURVE_TO_POS(curve) + 8); printf("S"); } /* 知性の周期を青で表示する */ setColor(H_BLUE, L_BLACK); for(i = 1;i <= getDaysInMonth(year, month);i++){ curve = getBioCurve(birth_year, birth_month, birth_day, year, month, i, CYCLE_INTELLECUTUAL); setLocate(i, CURVE_TO_POS(curve) + 8); printf("I"); } /* 先月と次月のプロンプトを表示する */ setColor(H_WHITE, L_BLACK); setLocate(1, 22); addMonths(year, month, &temp_year, &temp_month, -1); printf("<<%4d/%2d", temp_year, temp_month); setLocate(22, 22); addMonths(year, month, &temp_year, &temp_month, 1); printf("%4d/%2d>>", temp_year, temp_month); } //--------------------------------------------------------------------------------- double getBioCurve(int birth_year, int birth_month, int birth_day, int year, int month, int day, int cycle){ //--------------------------------------------------------------------------------- /* 指定した誕生日に対する指定日の、指定周期に対するサインカーブ値を返す */ return sin( (double)(getDateDiff(birth_year, birth_month, birth_day, year, month, day) % cycle) / cycle * 2 * M_PI ); } //--------------------------------------------------------------------------------- int getDateDiff(int year1, int month1, int day1, int year2, int month2, int day2){ //--------------------------------------------------------------------------------- /* 指定された2つの年月日の差を日数で返す */ int days, i; /* 指定年1が指定年2より以前だった場合 */ if(year1 < year2){ /* 指定年月日1から、指定年1の末日までの日数を計算する */ days = getDaysInYear(year1); days -= getDayOfYear(year1, month1, day1); /* 指定年1の翌年から、指定年2の前年までの日数を合計する */ for(i = year1 + 1;i <= year2 - 1;i++) days += getDaysInYear(year1); /* 指定年2の指定月日2までの年間積算日を合計する */ days += getDayOfYear(year2, month2, day2); /* 指定年1が指定年2以上だった場合 */ }else{ /* 指定月日2から指定月日1間の日数を計算する */ days = getDayOfYear(year2, month2, day2) - getDayOfYear(year1, month1, day1); } /* 計算した日数を「数え」で返す */ return days + 1; } //--------------------------------------------------------------------------------- int getDayOfYear(int year, int month, int day){ //--------------------------------------------------------------------------------- /* 指定された年月日の年間積算日を返す */ int days, i; /* 年始月から指定した月の前月までの日数を集計する */ days = 0; for(i = 1;i <= month - 1;i++) days += getDaysInMonth(year, i); /* 前月までの日数と今月の日数を合計した値を返す */ return days + day; } //--------------------------------------------------------------------------------- int getDaysInYear(int year){ //--------------------------------------------------------------------------------- /* 指定した年の日数を返す */ return (isLeapYear(year)) ? 366 : 365; } //--------------------------------------------------------------------------------- int getDaysInMonth(int year, int month){ //--------------------------------------------------------------------------------- /* 指定年の、指定した月の日数を返す */ /* 各月の日数を設定する */ int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* 指定した年が閏年なら2月の日数をを29日に変更する */ if(isLeapYear(year)) mon[2] = 29; return mon[month]; } //--------------------------------------------------------------------------------- bool isLeapYear(int year){ //--------------------------------------------------------------------------------- /* 指定した年が閏年かどうかを確認する */ bool ret = false; /* 西暦年が4で割り切れる年は閏年である */ if(year % 4 == 0) ret = true; /* 但し、西暦年が100で割り切れる場合は閏年ではない */ if(year % 100 == 0) ret = false; /* 但し、西暦年が400で割り切れる場合は閏年である */ if(year % 400 == 0) ret = true; return ret; } //--------------------------------------------------------------------------------- void addYears(int year1, int* year2, int years){ //--------------------------------------------------------------------------------- /* 指定した年から指定した年数が経過した後の年を返す */ *year2 = year1 + years; } //--------------------------------------------------------------------------------- void addMonths(int year1, int month1, int* year2, int* month2, int months){ //--------------------------------------------------------------------------------- /* 指定した年月から指定した月数が経過した後の年月を返す */ int ty1, tm1, ty2, tm2; /* 指定月数から年数を計算する */ ty1 = months / 12; /* 指定月数から月数を計算する */ tm1 = months % 12; /* 指定月数から計算した年数、月数を指定年月に加算する */ ty2 = year1 + ty1; tm2 = month1 + tm1; /* 月の繰り下がり、繰り上がりがあったら加算年月を補正する */ if(tm2 < 1){ tm2 += 12; ty2 += -1; }else if(tm2 > 12){ tm2 += -12; ty2 += 1; } /* 計算した結果年月を返す */ *year2 = ty2; *month2 = tm2; } //--------------------------------------------------------------------------------- void setLocate(int x, int y){ //--------------------------------------------------------------------------------- /* 文字の表示位置を設定する */ #ifdef _VC2010_WIN_ dwPos.X = (short)x; dwPos.Y = (short)y; SetConsoleCursorPosition(hOut, dwPos); #else printf("\x01b[%d;%dH", y, x); #endif } //--------------------------------------------------------------------------------- void setColor(int fore, int back) { //--------------------------------------------------------------------------------- /* 文字の表示色、背景色を設定する */ /* 下位 4 ビットを色番号として使用する */ fore &= 0x0f; back &= 0x0f; #ifdef _VC2010_WIN_ SetConsoleTextAttribute( hOut, (WORD)fore + ((WORD)back << 4) ); #else static const int font_color[] = { 30, 34, 32, 36, 31, 35, 33, 37, 40, 44, 42, 46, 41, 45, 43, 47 }; static const int back_color[] = { RGB15( 0, 0, 0), //30 normal black RGB15( 0, 0, 15), //34 normal blue RGB15( 0, 15, 0), //32 normal green RGB15( 0, 15, 15), //36 normal cyan RGB15(15, 0, 0), //31 normal red RGB15(15, 0, 15), //35 normal magenta RGB15(15, 15, 0), //33 normal yellow RGB15(24, 24, 24), //37 normal white RGB15(15, 15, 15), //40 bright black RGB15( 0, 0, 31), //44 bright blue RGB15( 0, 31, 0), //42 bright green RGB15( 0, 31, 31), //46 bright cyan RGB15(31, 0, 0), //41 bright red RGB15(31, 0, 31), //45 bright magenta RGB15(31, 31, 0), //43 bright yellow RGB15(31, 31, 31) //47 & 39 bright white }; printf("\x1b[%dm", font_color[fore]); BG_PALETTE_SUB[0] = back_color[back]; #endif } //--------------------------------------------------------------------------------- void clearScreen(void){ //--------------------------------------------------------------------------------- /* コンソール画面を消去する */ #ifdef _VC2010_WIN_ dwPos.X = 0; dwPos.Y = 0; if(GetConsoleScreenBufferInfo(hOut, &csbi)) FillConsoleOutputCharacter(hOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, dwPos, &written); #else printf("\x1b[2J"); #endif } //---------------------------------------------------------------------------------