第3講 第2講の魔方陣を高速化しよう!
第3話 1次元gと2次元添え字(i,j)の関係−奇数の場合の解説

奇数の場合の例
(19次)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
0 0 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 19
1  54 1 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 20 86
2 55 87 2 103 104 105 106 107 108 109 110 111 112 113 114 115 21 116 117
3 56 88 118 3 133 134 135 136 137 138 139 140 141 142 143 22 144 145 146
4 57 89 119 147 4 161 162 163 164 165 166 167 168 169 23 170 171 172 173
5 58 90 120 148 174 5 187 188 189 190 191 192 193 24 194 195 196 197 198
6 59 91 121 149 175 199 6 211 212 213 214 215 25 216 217 218 219 220 221
7 60 92 122 150 176 200 222 7 233 234 235 26 236 237 238 239 240 241 242
8 61 93 123 151 177 201 223 243 8 253 27 254 255 256 257 258 259 260 261
9 62 94 124 152 178 202 224 244 262 9 271 272 273 274 275 276 277 278 279
10 63 95 125 153 179 203 225 245 28 280 10 289 290 291 292 293 294 295 296
11 64 96 126 154 180 204 226 29 263 281 297 11 305 306 307 308 309 310 311
12 65 97 127 155 181 205 30 246 264 282 298 312 12 319 320 321 322 323 324
13 66 98 128 156 182 31 227 247 265 283 299 313 325 13 331 332 333 334 335
14 67 99 129 157 32 206 228 248 266 284 300 314 326 336 14 341 342 343 344
15 68 100 130 33 183 207 229 249 267 285 301 315 327 337 345 15 349 350 351
16 69 101 34 158 184 208 230 250 268 286 302 316 328 338 346 352 16 355 356
17 70 35 131 159 185 209 231 251 269 287 303 317 329 339 347 353 357 17 359
18 36 102 132 160 186 210 232 252 270 288 304 318 330 340 348 354 358 360 18

以下の説明では、gは上の表の紺色の数字
iz(g)はi(上の表の赤色の数字)
jz(g)はj(上の表のピンク色の数字)を表していることに注意してください。
また、エクセルのプログラムソースでは
iz(i)=i(座標を作るプロシージャではgがiと表されているため。)などとなっていますが、
混乱を避けるためiz(g)=gなどと表記します。
さらに、n=19(19次を例にしていますので)を前提していることも忘れないでください。

    If g < n Then
      iz(g) = g
      jz(g) = g
    End If

    If g >= n And g < 2 * n - 1 Then
      iz(g) = g - n
      jz(g) = 2 * n - g - 1
      If iz(g) >= jz(g) Then
        iz(g) = iz(g) + 1
        jz(g) = jz(g) - 1
      End If
    End If

青の部分は明らかです。
は一致しているからです。
iz(g) = g - nも自然です。
から19を引けばに一致することは表から明らかであるからです。
jz(g) = 2 * n - g - 1はわかりにくいかもしれませんが、
が増えるたびにが減っていくことに気がつけば、
気がつくのは容易ではないでしょうか。
例えば、g=26なら
jz(26)=2×19ー26−1=11です。
ほかも表と見比べながら一致することをご確認ください。
さて、
      If iz(g) >= jz(g) Then
        iz(g) = iz(g) + 1
        jz(g) = jz(g) - 1
      End If
はどういう意味でしょうか。
iz(g) = jz(g)とはg=28で

  9

の位置を示しています。したがって、
         iz(g) = iz(g) + 1
        jz(g) = jz(g) - 1

がないとg=28がg=9と重なってしまいます。
         iz(g) = iz(g) + 1
        jz(g) = jz(g) - 1

はg=28が1つずれて

 28

の位置に来るようにしているのです。
iz(g) > jz(g)
についても同様です。g=29以降をすべて1つずつずらしているのです。
問題は
    m = Int(n / 2)

    For j = 1 To m

      aj = -j * j + (4 * m + 1) * j + 1
      If g >= aj And g < aj + n - 1 - j Then
        iz(g) = j - 1
        jz(g) = g - aj + j
        If jz(g) >= n - j Then jz(g) = jz(g) + 1
      End If

      bj = -j * j + 4 * m * j + 2 * m + 1
      If g >= bj And g < bj + n - 1 - j Then
        iz(g) = g - bj + j
        jz(g) = j - 1
        If iz(g) >= n - j Then iz(g) = iz(g) + 1
      End If

      cj = -j * j + (2 * m + 3) * j + 3 * m * m + m - 1
      If g >= cj And g < cj + m + 1 - j Then
        iz(g) = m + j - 1
        jz(g) = g - cj + m + j
      End If

      dj = -j * j + (2 * m + 2) * j + 3 * m * m + 2 * m
      If g >= dj And g < dj + m + 1 + j Then
        iz(g) = g - dj + m + j
        jz(g) = m + j - 1
      End If

    Next
の記述でしょう。
aj、bj、cj、djで始まるそれぞれの部分は、
順に水色、黄色、薄紫色、薄紺色に対応しています。
まずajすなわち水色から見ていきましょう。
赤色を付けた37,71,103,133,161,187,211,233,253は
aj = -j * j + (4 * m + 1) * j + 1において、
jが1,2,3,4,5,6,7,8,9の値をとる場合に相当します。
しかも、19次だけでなく奇数次ならすべて当てはまります。
例えば、17次ならm=8(m = Int(n / 2)なので)で
33,63,91,117,141,163,183,201となります。
つまり、aj = -j * j + (4 * m + 1) * j + 1は
次数にかかわらず普遍的(一般的)に成り立つわけです。
つまり、ajは次数に関わらず共通のjの2次関数になっているのです。

したがって、g >= aj And g < aj + n - 1 - jによって、
1行目なら37以上53以下
2行目なら71以上86以下
3行目なら103以上117以下
4行目なら133以上146以下
    ・
    ・
となり、
iz(g) = j - 1
は自然といえます。
for文はjを1から始めていますので1引いているのです。
jz(g) = g - aj + j
のjはjz(g)の始まりが1行進むごと右にずれているので、
それに対応するためです。
ではIf jz(g) >= n - j Then jz(g) = jz(g) + 1
の意味は何でしょうか。
これは逆対角線に重なるか、
それより右にあるときは右に1個ずらすという命令です。

これは例えば86が逆対角線上の20と重ならないようにしています。
逆対角線と重なるかそれより右にあるときは、
1個ずらさないと対角線を飛び越して入れるという原則に反してしまうからです。

ajの部分がわかればbj以降の理解も容易でしょう。
bjにおいては、
54,87,118,147,174,199,222,243,263が
bj = -j * j + 4 * m * j + 2 * m + 1
の式に従っているのです。つまりjの2次関数になっているのです。
If iz(g) >= n - j Then iz(g) = iz(g) + 1
も逆対角線を飛ぶように命令しているのです。

cjとdjでは逆対角線を横切る心配がないので、
if文に相当する部分はありません。

どうですか。
かなり難解に見えたソースの仕掛けが見えてきたのではないでしょうか。

第3講第2話へ
 第3講第4話へ


VB入門講義応用編トップへ

VB入門講義トップへ