奇数の魔方陣を作成する

魔方陣とは1~Nまでの数字を「縦、横の合計が等しくなる」ように並べた行列です。
さらに縦、横だけでなく「斜めの合計も等しくなる」ような魔方陣もあります。
全ての奇数の魔方陣(3方陣、5方陣、7方陣・・・)は共通のアルゴリズムで作成することができます。

前田稔(Maeda Minoru)の超初心者のプログラム入門

魔方陣のアルゴリズム

魔方陣とは1~Nまでの数字を「縦、横、[斜め] の合計がいずれも等しくなる」ように並べた行列です。
3*3の魔方陣は1~9の数を縦、横、[斜め] の合計が15になるように並べます。
5*5の魔方陣は1~25の数を縦、横、[斜め] の合計が65になるように並べます。

奇数の魔方陣(3,5,7,9,11,...)は全て次のアルゴリズムで作成することができます。
  1. 下段の中央に1を格納してここからから始めます。
  2. 1の位置から右下に移動します。
    枠の外に出たときは、その位置に対応する枠の中に移動します。
  3. 2の位置から右下に移動します。
    枠の外に出たときは、その位置に対応する枠の中に移動します。
  4. 3の位置の右下には既に1が格納されています。
    そのときは右下ではなくて上に移動します。
  5. これを全ての箱が埋まるまで繰り返すと魔方陣が完成します。

プログラムの作成

  1. t[15][15] が魔方陣の最大サイズで、15*15の魔方陣まで作成できます。
    NUM が魔方陣のサイズで、3は3*3の魔方陣です。
        #include    "resource.h"
    
        HINSTANCE   g_hInst;
        HWND        g_hWnd;
        USHORT      t[15][15];
        int         NUM= 3;
        
  2. WM_CREATE: では、NUM に設定されている魔方陣を作成します。
            case WM_CREATE:
                SetNumber(NUM);
                break;
        
  3. WM_PAINT: では、現在作成されている NUM の魔方陣を表示します。
            case WM_PAINT:
                hdc= BeginPaint (hWnd, &ps);
                Disp(hdc,NUM);
                EndPaint(hWnd, &ps);
                break;
        
  4. WM_COMMAND: でメニューから選択された奇数の魔方陣を作成して t[15][15] に格納します。
            case WM_COMMAND:
                switch(LOWORD(wParam))
                {   case IDM_3:  NUM= 3;    break;
                    case IDM_5:  NUM= 5;    break;
                    case IDM_7:  NUM= 7;    break;
                    case IDM_9:  NUM= 9;    break;
                    case IDM_11: NUM= 11;   break;
                    case IDM_13: NUM= 13;   break;
                    case IDM_15: NUM= 15;   break;
                    case IDM_EXIT:
                        SendMessage(hWnd,WM_CLOSE,0,0L);
                        return 0L;
                }
                SetNumber(NUM);
                InvalidateRect(hWnd,NULL,TRUE);
                break;
        
  5. 魔方陣を表示する Disp() 関数です。
        void  Disp(HDC hdc, int n)
        {   int     x,y;
            char    str[4];
    
            for(y=0; y<n; y++)
                for(x=0; x<n; x++)
                {   wsprintf(str,"%3d", t[y][x]);
                    TextOut(hdc,x*50+36,y*30+30,str,3);
                }
            for(x=0; x<n+1; x++)
            {   MoveToEx(hdc,x*50+20,20,NULL);
                LineTo(hdc,x*50+20,n*30+20);
                MoveToEx(hdc,20,x*30+20,NULL);
                LineTo(hdc,n*50+20,x*30+20);
            }
        }
        

【演習1】

  1. NUM で指示された奇数の魔方陣を作成する関数 SetNumber(short n) を作成してプログラムを完成させて下さい。
    SetNumber() 関数は、関数の定義も含めて約18行で完成します。
  2. メニュー選択で15までの奇数方陣を表示できるようにプログラムして下さい。

【演習2】

  1. 必要なサイズの領域だけを定義して、SetNumber() にパラメータとして渡すことを考えます。
    例えば魔方陣の領域は、次のように定義します。
        short   t3[3][3];       //3×3の魔方陣
        short   t5[5][5];       //5×5の魔方陣
        
  2. SetNumber() 関数は、次のように呼び出します。
        SetNumber(3,(short*)t3);
        SetNumber(5,(short*)t5);
        
  3. SetNumber() 関数では、パラメータを次のように受け取ります。
    void SetNumber(const short n, short *p)
  4. 例えば SetNumber() 関数で魔方陣の領域をクリアするコードは次のようになります。
        void  SetNumber(const short n, short *p)
        {   int nn,i;
    
            nn= n*n;
            for(i=0; i<nn; i++)     *(p+i)= 0;
        
  5. 魔方陣の領域をパラメータで受け取る SetNumber() 関数を完成させて下さい。

超初心者のプログラム入門(Win32API C++)