クリックした位置に画像が表示される。
ビットマップリソース ID:IDB_BITMAP1 |
#include < windows.h > #include "resource.h" #define MYWNDCLASS "MYWNDCLASS" #define MYWNDTITLE "UNDO" // 外部変数 HINSTANCE g_hInst; HMENU g_hMenu; POINT pt[256]; // ビットマップ表示用のX,Y座標を格納する構造体 int pt_ct = -1; // 最後に表示されるビットマップの番号 int Undo_ct = -1; // [元に戻す(U)],[やり直し(R)]の現在のカウント int flag_Undo_off = 0; // [元に戻す(U)]メニューの状態フラグ 0:有効 1:無効 int flag_Redo_off = 0; // [やり直し(R)]メニューの状態フラグ 0:有効 1:無効 typedef struct{ int ct; int x; int y; }UNDO,*LPUNDO; UNDO Undo[1024]; // [元に戻す(U)],[やり直し(R)]で使用する履歴を格納する構造体 // 関数のプロトタイプ宣言 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void Set_UnDo1(int ct,int x,int y); void Set_UnDo2(int ct,int x,int y); void UnDo(HWND hWnd); void ReDo(HWND hWnd); int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow) { MSG msg; WNDCLASSEX wc; HWND hWnd; g_hInst = hInst; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.lpfnWndProc = (WNDPROC)WndProc; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = MYWNDCLASS; RegisterClassEx(&wc); g_hMenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1)); //メニューのハンドルを取得 hWnd = CreateWindowEx(0, MYWNDCLASS, MYWNDTITLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL, g_hMenu, hInst, NULL); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { static HBITMAP hBMP,hBMPPre; static BITMAP bmp; int i; switch (uMsg) { case WM_CREATE: // [元に戻す]の履歴の初期化 for(i=0;i<1024;i++){ Undo[i].ct = -1; Undo[i].x = -1; Undo[i].y = -1; } // メニュー項目の無効化 EnableMenuItem ( g_hMenu,IDM_UNDO,MF_GRAYED ); EnableMenuItem ( g_hMenu,IDM_REDO,MF_GRAYED ); // ビットマップリソースの読み込み hBMP = LoadBitmap(g_hInst,MAKEINTRESOURCE(IDB_BITMAP1)); // ビットマップの情報を取得 GetObject(hBMP,sizeof(BITMAP),&bmp); break; case WM_PAINT: HDC hDC,hDCCmp; PAINTSTRUCT ps; hDC = BeginPaint(hWnd,&ps); // ビットマップの描画 hDCCmp = CreateCompatibleDC(hDC); hBMPPre = (HBITMAP)SelectObject(hDCCmp,hBMP); for(i=0;i<=pt_ct;i++){ BitBlt(hDC,pt[i].x,pt[i].y,bmp.bmWidth,bmp.bmHeight, hDCCmp,0,0,SRCCOPY); } SelectObject(hDCCmp,hBMPPre); EndPaint(hWnd,&ps); break; case WM_LBUTTONDOWN: // マウスの左ボタンが押されたとき Set_UnDo1(pt_ct,pt[pt_ct].x,pt[pt_ct].y); pt_ct ++; if(pt_ct >= 256){ pt_ct = 255; } pt[pt_ct].x = LOWORD(lParam); pt[pt_ct].y = HIWORD(lParam); RECT rect; SetRect(&rect,pt[pt_ct].x,pt[pt_ct].y,pt[pt_ct].x+bmp.bmWidth, pt[pt_ct].y+bmp.bmHeight); InvalidateRect(hWnd,&rect,FALSE);// 再描画を指示 break; case WM_COMMAND: switch( LOWORD(wParam) ) { case IDM_UNDO:// 元に戻す UnDo(hWnd); break; case IDM_REDO:// やり直し ReDo(hWnd); break; } break; case WM_DESTROY: DeleteObject(hBMP); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } // [元に戻す]の履歴をセットする void Set_UnDo1(int ct,int x,int y) { if(Undo_ct == -1){ EnableMenuItem ( g_hMenu,IDM_UNDO,MF_ENABLED ); flag_Redo_off = 1; } Undo_ct ++; if(Undo_ct >= 1024){ Undo_ct = 1023; MessageBox(NULL,"[元に戻す]の使用回数は上限を超えました。", MYWNDTITLE,MB_OK | MB_ICONSTOP); } Undo[Undo_ct].ct = ct; Undo[Undo_ct].x = x; Undo[Undo_ct].y = y; } // [元に戻す]の履歴をセットする (UnDo(),ReDo()内で使用) void Set_UnDo2(int ct,int x,int y) { Undo[Undo_ct].ct = ct; Undo[Undo_ct].x = x; Undo[Undo_ct].y = y; }// void Set_UnDo2(int ct,int x,int y) // [元に戻す] void UnDo(HWND hWnd) { int ct,x,y; if(Undo_ct > -1){ ct = Undo[Undo_ct].ct; x = Undo[Undo_ct].x; y = Undo[Undo_ct].y; Set_UnDo2(pt_ct,pt[pt_ct].x,pt[pt_ct].y); pt_ct = ct; pt[ct].x = x; pt[ct].y = y; Undo_ct --; if(Undo_ct == -1){ flag_Undo_off = 1; EnableMenuItem ( g_hMenu,IDM_UNDO,MF_GRAYED ); } InvalidateRect(hWnd,NULL,TRUE);// 再描画を指示 if(flag_Redo_off == 1){ flag_Redo_off = 0; EnableMenuItem ( g_hMenu,IDM_REDO,MF_ENABLED ); } } }// void UnDo(HWND hWnd) // [やり直し] void ReDo(HWND hWnd) { int ct,x,y; if( Undo[Undo_ct+1].ct != -1 ){ Undo_ct ++; ct = Undo[Undo_ct].ct; x = Undo[Undo_ct].x; y = Undo[Undo_ct].y; Set_UnDo2(pt_ct,pt[pt_ct].x,pt[pt_ct].y); pt_ct = ct; pt[ct].x = x; pt[ct].y = y; InvalidateRect(hWnd,NULL,TRUE);// 再描画を指示 if(flag_Undo_off == 1){ flag_Undo_off = 0; EnableMenuItem ( g_hMenu,IDM_UNDO,MF_ENABLED ); } if(Undo[Undo_ct+1].ct == -1){ EnableMenuItem ( g_hMenu,IDM_REDO,MF_GRAYED ); flag_Redo_off = 1; } } }// void ReDo(HWND hWnd) |
エディットコントロール内の文字列を文字コードに変換する
|
#include <stdio.h> #include <mbstring.h> // 文字コードで表示 void Char_16() { static unsigned char s1[MAX_LEN/3]; char s2[MAX_LEN] = ""; UINT i,ct,Len; Len = SendMessage(hEdit1, WM_GETTEXTLENGTH, 0, 0) + 1; if(Len > MAX_LEN/3) Len = MAX_LEN/3; SendMessage(hEdit1, WM_GETTEXT, (WPARAM) Len, (LPARAM) s1); ct = 0; for(i=0;i<Len;i++){ if(strlen(s2) >= MAX_LEN - 6){ s1[i] = '\0'; break; } if(s1[i] == '\r' && s1[i+1] == '\n'){ // 改行文字を見つけたら、改行する。 sprintf(&s2[ct],"%02x%02x\r\n",s1[i] & 0xff,s1[i+1] & 0xff); i ++; ct += 6; } else if(_mbclen(&s1[i]) == 2){ // 全角文字の場合 sprintf(&s2[ct],"%02x%02x ",s1[i] & 0xff,s1[i+1] & 0xff); i ++; ct += 5; } else if(s1[i] == '\0'){ // ヌル文字の場合 sprintf(&s2[ct],"%02x",s1[i] & 0xff); ct += 2; } else{ // 半角文字の場合 sprintf(&s2[ct],"%02x ",s1[i] & 0xff); ct += 3; } } SendMessage(hEdit1, WM_SETTEXT, 0, (LPARAM) s2); } |
よく見かける自動生成迷路のサンプル。
壁を1、通路を0、ルートを2とする。
|
#include <windows.h> #include <time.h> #include <malloc.h> #define WDH 35 // 幅 #define HGT 35 // 高さ BYTE Map[HGT][WDH]; // 地図 int dx[4] = {-1, 0, 1, 0}; int dy[4] = { 0,-1, 0, 1}; LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void Labyrinth(); void Labyrinth_Sub(int x, int y); void Root(int x, int y); int RandTo(int max); LRESULT CALLBACK ProcWnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: Labyrinth(); return 0; case WM_PAINT: // 表示 { PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd,&ps); HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); HFONT hFontPre = (HFONT)SelectObject(hDC, hFont); char blk[3][3] = {" ","□","■"}; int x,y; for(y=0;y<HGT;y++){ for(x=0;x<WDH;x++){ TextOut(hDC, x*10, y*10, blk[(int)Map[y][x]], strlen(blk[(int)Map[y][x]])); } } SelectObject(hDC, hFontPre); EndPaint(hWnd,&ps); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); }// ProcWnd // 迷路作成 void Labyrinth() { int x,y,x2,y2,x3,y3,x4,y4,r,i; bool flag,flag2; srand( (unsigned)time( NULL ) ); // マップの初期化(四方を壁で囲まれたセルを(WDH/2)*(HGT/2)個作る) for(y=0;y<HGT;y++){ for(x=0;x<WDH;x++){ if(x % 2 && y % 2) Map[y][x] = 0; else Map[y][x] = 1; } } // 乱数で使用する4つの数字の並び方リスト int rnd_list[24][4] = { {0,1,2,3},{0,1,3,2},{0,2,1,3},{0,2,3,1}, {0,3,1,2},{0,3,2,1},{1,0,2,3},{1,0,3,2}, {1,2,0,3},{1,2,3,0},{1,3,0,2},{1,3,2,0}, {2,0,1,3},{2,0,3,1},{2,1,0,3},{2,1,3,0}, {2,3,0,1},{2,3,1,0},{3,0,1,2},{3,0,2,1}, {3,1,0,2},{3,1,2,0},{3,2,0,1},{3,2,1,0} }; x = y = 1; for(y=1;y<HGT;y+=2){ for(x=1;x<WDH;x+=2){ x4 = x; y4 = y; flag2 = 0; // 各通路の最初のセルを示すフラグ flag = 1; // 袋小路フラグ // 0 のセルが見つかったら、そこから順に壁を壊して袋小路まで通路を作る。 // 通過したセルは、2 に置き換える while(flag && !Map[y4][x4]){ flag = 0; r = RandTo(24); for(i=0;i<4;i++){ x2 = x4 + dx[rnd_list[r][i]]; y2 = y4 + dy[rnd_list[r][i]]; if(Map[y2][x2] && x2 > 0 && x2 < WDH-1 && y2 > 0 && y2 < HGT-1) { x3 = x4 + dx[rnd_list[r][i]] * 2; y3 = y4 + dy[rnd_list[r][i]] * 2; if(!Map[y3][x3]){ Map[y2][x2] = 0; Map[y4][x4] = 2; // 各通路の最初のセルの左か上の壁を壊す if(!flag2 && (x4 != 1 || y4 != 1)){ Labyrinth_Sub(x4, y4); flag2 = 1; } x4 = x3; y4 = y3; flag = 1; break; } } } // 四方を壁に囲まれているセルは壁を壊し損なったのでここで壊す if(!flag && !flag2 && Map[y4-1][x4] && Map[y4][x4-1] && Map[y4+1][x4] && Map[y4][x4+1]) { Labyrinth_Sub(x4, y4); flag2 = 1; } } } } // 壁以外を0にする for(y=1;y<HGT;y+=2){ for(x=1;x<WDH;x+=2){ if(Map[y][x] == 2) Map[y][x] = 0; } } // ゴールまでのルートを求める(ルートは 2) Root(1, 1); // 左上と右下の壁を壊す Map[0][1] = 2; Map[HGT-2][WDH-1] = 2; }// Labyrinth // 壁を壊して、2つの通路をつなげる void Labyrinth_Sub(int x, int y) { if(x == 1){ Map[y-1][x] = 0; } else if(y == 1){ Map[y][x-1] = 0; } else{ int r = RandTo(2); Map[y+dy[r]][x+dx[r]] = 0; } }// Labyrinth_Sub // ゴールまでのルートを求める void Root(int x, int y) { POINT *stack; // 分岐情報を保持するスタック int num = 0; // スタックの現在の位置 int i,x2,y2,idx,ct; size_t size; stack = new POINT [256]; // スタックのメモリを確保する while(num >= 0){ // スタックが空になったら終了 ct = 1; while(ct){ Map[y][x] = 2; // 通った道は 2 を入れる ct = 0; for(i=0;i<4;i++){ // 分岐点は最後の通路から試す x2 = x + dx[i]; y2 = y + dy[i]; if(!Map[y2][x2]){ idx = i; ct ++; // 通路の分岐数を数える } } if(x == WDH-2 && y == HGT-2){ // ゴールに着いたら終了 goto End; } if(ct > 1){ // 分岐点であれば座標をスタックに入れる stack[num].x = x; stack[num].y = y; num ++; // スタック容量が足りなくなったら追加する size = _msize(stack); if(sizeof(stack) >= size){ stack = (POINT*)realloc(stack, size+64*sizeof(POINT)); if(stack){ return; } } } if(ct > 0){ // 通路を先に進む x += dx[idx]; y += dy[idx]; } } num --; if(num >= 0){ // 行き止まりだったとき、分岐点まで消去する(値を 2 から 3 に置き換える) while(x != stack[num].x || y != stack[num].y){ for(i=0;i<4;i++){ x2 = x + dx[i]; y2 = y + dy[i]; if(Map[y2][x2] == 2){ Map[y][x] = 3; x = x2; y = y2; break; } } } x = stack[num].x; // 分岐点の他の通路を試す y = stack[num].y; } } End:delete[] stack; // 終了時にスタックのメモリを解放する stack = NULL; // 行き止まりだった通路を消去する(値を 3 から 0 に置き換える) for(y=1;y<HGT-1;y++){ for(x=1;x<WDH-1;x++){ if(Map[y][x] == 3) Map[y][x] = 0; } } }// Root // 0 〜 max-1 までの乱数を返す int RandTo(int max) { return (int)((float)max * rand() / (RAND_MAX + 1.0f)); }// RandTo |
バーナム暗号は、共通鍵暗号方式の暗号化アルゴリズムである。 DOWNLOAD
暗号化と復号に同じプログラム、同じ暗号キーを使用する。 以下の例では、乱数表にsrand()を使っている。 乱数表にsrand()を使うのは誰でも思いつくので、全てのパターンのキーを試されたら簡単に解読される。 そのため、普通は乱数表を自前で作成する。 「C MAGAZINE 2004/6 SOFTBANK」によると、VC++ の rand() と srand() は以下のようになっているらしい。乱数は、x = a * x + b で求められるから、 a と b の値を別の数字に変えたら、独自の乱数生成関数ができる。 16 ビット右にシフトするから、b は 0 でも良い。また、それは、求められる x の値が 2 進数に変換した時に、17 ビット以上でなくてはならないことも意味するから、a の値は、ある程度、大きくなくてはならない。 他には、NTTの暗号化アルゴリズム Camellia など。 // VC++ の rand() と srand() static long x = 1; int rand(void) { x = 214013 * x + 2531011; return(x >> 16) & 0x7fff; } void srand(unsigned a) { x = s; } |
// rand() を使ったバーナム暗号化プログラム void main() { unsigned int key = 12345; char s[] = "abcdefg"; // char s[] = "mffnjkj"; srand(key); for(int i=0;i<strlen(s);i++){ s[i] ^= rand() % 8; } printf(s); } |
ビットのシフト演算による圧縮。
2値画像やフラグなどの 0 と 1 だけが並ぶデータの圧縮に使われる。 2値画像は、パターン認識などで使われることがある。 例えば、BYTE 型の 0 や 1 は、1 byte の容量を必要とするが、1 byte を二進数に変換すると、8 桁分の 0 や 1 を格納する事が出来る。 そのため容量を最大 8 分の 1 に圧縮できる。 |
||
|
ランレングス符号化(RLE)は、文字のの連続長を書くことで圧縮を行う。
例えば、AAAAA の場合は 5A とする。 RLE は、2値画像など同じ文字が連続しているデータの圧縮に使われる。 DirectShow のコンプレッサ フィルタの1つでもある。 圧縮アルゴリズム 符号化の原理とC言語による実装 p.5〜p.20 SOFTBANK を参照。 |
||||||||||||||||||||||||||||||
7.圧縮(ハフマン符号化)
8.ハッシュを使ったデータ探索
9.フルカラー→256index変換
10.再帰呼び出し
11.
|