AutoHotKeyでマインスイーパを自動で解く

マインスイーパを自動で解くっていっても、裏技使ってるからなんともいえない。
しかも、ニコ動でTASさんが解いたほうが断トツで速いと。。。

でも、このAutoHotKeyってソフトWindowsの作業をほとんど自動化してくれるので便利。


日本語対応で文字形式はUTF-8だから注意してね。
あと、色付けはBasicにしてみた。あと、XPで動いてる。

; utf-8
mode := ""
mineHeight := 0
mineWidth := 0

Gui, Add, Radio, vB Checked1, 初級
Gui, Add, Radio, vI, 中級
Gui, Add, Radio, vE, 上級
Gui, Add, Button, , 決定
Gui, Show

Loop
{
  Sleep, 100
}

Button決定:
GUI, Submit

If B = 1
{
  mode := "初級"
  mineHeight := 9
  mineWidth := 9
}
If I = 1
{
  mode := "中級"
  mineHeight := 16
  mineWidth := 16
}
If E = 1
{
  mode := "上級"
  mineHeight := 16
  mineWidth := 30
}

IfWinNotExist マインスイーパ
{
  MsgBox, 4, , マインスイーパを起動しますか?
  IfMsgBox, Yes
  {
    Run, C:\WINDOWS\system32\winmine.exe
  }
  else
  {
    ExitApp
  }
}

WinActivate, マインスイーパ
Send, xyzzy+{Enter}
CoordMode, Pixel, Screen

WinMenuSelectItem, マインスイーパ, , ゲーム, % mode

y := 104
Loop, % mineHeight
{
  x := 24
  Loop, % mineWidth
  {
    MouseMove, % x, % y, 0
    PixelGetColor, color, 0, 0
    If % color = 0xFFFFFF
    {
      MouseClick, Left, % x, % y, 1, 0
    }
    x += 16
  }
  y += 16
}
MsgBox, congratulations!

WinClose, マインスイーパ
Gui, Destroy
GuiClose:
ExitApp

CygwinにODEをインストール

※最初に注意として、既にCygwin版ODEがありますので、そちらをインストールしたほうが早いです。



まず、

$ cygcheck -c cygwin gcc4-g++ opengl
Cygwin Package Information
Package              Version        Status
cygwin               1.7.9-1        OK
gcc4-g++             4.5.3-2        OK
opengl               1.1.0-10       OK

という環境の32bit XPマシンを使用しています。
ode-0.11.1をインストールしていきます。

ODEをダウンロードして適当なディレクトリに解凍して移動します。

cd ~/src/ode-0.11.1
sh ./autogen.sh

ここで、./configureを編集します。
テキストエディタを使用し、DEFS=を検索します。
すると

DEFS=-DHAVE_CONFIG_H

が見つかると思います。

これを

DEFS="-DHAVE_CONFIG_H -D_WIN32 -DUSE_OPENGL32"

に書き換えて保存します。

あとは

./configure
make
make install

という手順でインストールできます。

/ode-0.11.1ode/demoの中にデモがあり、しばらく遊べます。


けれども、Cygwin上からしかテクスチャを読めないので、
Cygwin上でしか動作せず、配布はできそうにありません。

Arduinoを使って1602LCDで高速素数表示をした

素数を数えると精神衛生上によいと聞いたので、
LCDキャラクタディスプレイに素数を表示して冷静になろうと思う。


ミラー-ラビン素数判定法 - Wikipedia

リンク先にあるミラーラビン素数判定法というものを、そのまま実装した。
結果が合っているかの確認はしていないけど、落ち着く可能性はあると思う。


IDEのバージョンは0022で
ボードは"Arduino Pro or Pro Mini (3.3V,8MHz)w/ATmega168"を使用した。


以下ソース

// 高速素数表示、時間付

#include <stdint.h> 
#include <stdio.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

void setup() {
  randomSeed(analogRead(0));
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
}

uintmax_t num = 100000UL; // 最初に判定したい数
uint32_t time;
char str[20];

void loop() {
  if (isPrime(num)) {
    time = millis();

    snprintf(str, sizeof(str), "PrimeNum:%7lu", num);
    lcd.setCursor(0, 0);
    lcd.print(str);

    snprintf(str, sizeof(str), "  %02luh%02lum%02lus%03lums",
      time / 1000UL / 3600UL % 24UL, time / 1000UL / 60UL % 60UL,
      time / 1000UL % 60UL, time % 1000UL);
    lcd.setCursor(0, 1);
    lcd.print(str);
  }
  num++;
}


// ミラー・ラビン素数判定法 wikipediaから引用・改変
bool isPrime(const uintmax_t n) {
  if (n == 2) {
    return true;
  }
  if (n == 1 || (n & 1) == 0) {
    return false;
  }

  uintmax_t d = n - 1;
  while ((d & 1) == 0) {
    d >>= 1;
  }

  uintmax_t a, t, y;
  for (int i = 0; i < 20; i++) {
    a = random(1, n-1);
    t = d;
    y = pow(a, t, n);
    while (t != n-1 && y != 1 && y != n-1) {
      y = (y * y) % n;
      t <<= 1;
    }
    if (y != n-1 && (t & 1) == 0) {
      return false;
    }
  }
  return true;
}

uintmax_t pow(uintmax_t base, uintmax_t power, const uintmax_t mod) {
  uintmax_t result = 1;
  while (power > 0) {
    if ((power & 1) == 1) {
      result = (result * base) % mod;
    }
    base = (base * base) % mod;
    power >>= 1;
  }
  return result;
}


写真か動画取ればよかった。

四次元配列の一次元化

#include <stdio.h>

#define O 2
#define P 3
#define Q 4
#define R 5

int main() {
  int i, j, k, l;
  int nums4[O][P][Q][R];
  int nums1[O*P*Q*R];
  
  for (i = 0; i < O; i++) {
    for (j = 0; j < P; j++) {
      for (k = 0; k < Q; k++) {
        for (l = 0; l < R; l++) {
          nums4[i][j][k][l] = i*P*Q*R + j*Q*R + k*R + l;
          printf("i:%d j:%d k:%d l:%d nums4:%d\n", i, j, k, l,  nums4[i][j][k][l]);
        }
      }
    }
  }
  puts("");
  
  for (i = 0; i < O; i++) {
    for (j = 0; j < P; j++) {
      for (k = 0; k < Q; k++) {
        for (l = 0; l < R; l++) {
          nums1[i*P*Q*R + j*Q*R + k*R + l] = nums4[i][j][k][l];
          printf("i:%d j:%d k:%d l:%d nums1:%d\n", i, j, k, l, nums1[i*P*Q*R + j*Q*R + k*R + l]);
        }
      }
    }
  }
  puts("");
  
  for (i = 0; i < O*P*Q*R; i++) {
    printf("i:%d nums1:%d\n", i, nums1[i]);
  }
  puts("");
  
  printf("sizeof(nums4):%d sizeof(nums1):%d\n", sizeof(nums4)/sizeof(int), sizeof(nums1)/sizeof(int));
  
  return 0;
}

多分、あってる。
ソースコードに全然自信ないし、配列関係は間違いやすいから、扱いには十分注意してね。


世の中には、一次元配列が扱いやすい状況があったりするはず。


ていうか、一次元配列アクセスするときはfor文も一重化すれば見やすくなる。

追記
蛇足だけど、for文一重化してアクセスしたコードを追加した。

cygwinでopenglのコンパイルの仕方

gcc version 4.3.4 20090804 (release) 1 (GCC)で
下記の"GLUTによる「手抜き」OpenGL入門:"様にあるサンプルソース
ちょっと変えてコンパイルしてみた

#define _WIN32
#define USE_OPENGL32
#include <GL/glut.h>

void display(void) {
  glClear(GL_COLOR_BUFFER_BIT);
  glFlush();
}

void init(void) {
  glClearColor(0.0, 0.0, 1.0, 1.0);
}

int main(int argc, char *argv[]) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display);
  init();
  glutMainLoop();
  return 0;
}

コマンドは

gcc test.c -O3 -lglut32 -lglu32 -lopengl32
./a

ヘッダファイル見て、#defineしてみたら動いた
これでgmpライブラリと併用出来る

最初は-mno-cygwinとか試して方向性が違っていてけっこう苦労した