Yuki Nakata's Blog

One color just reflects another

実はゲームパッド Elecom F310についてずっと考えていました。笑

マウス同様ジョイパッドをカスタマイズしましょう。

ゲームパッドをマウスみたいにします。できるはずです。たぶんできるはず。

これからプログラムを作ります。

プログラムを作っていたらやっかいなことが判明しました。

マウス移動なのですが、マウスの移動はEV_RELと相対移動です。

ゲームパッドの移動はEV_ABSと絶対移動です。

マウスとゲームパッドでは移動量が根本的に異なります。

うまく変換できるのでしょうか。不安です。

 

windowsの次はlinuxでマウスをカスタマイズします。

プログラムを作って、マウスを乗っ取ります。 

仕組みが分かれば簡単にプログラムで作ることができます。

なぜならlinuxはすべてファイル扱いで、 マウスもキーボードもゲームパッドもファイルだからです。

openして、readしてwriteすればいいわけです。

自由自在にカスタマイズできてしまいます。

たとえば、マウスを左クリックするとキーボードのAと入力させることもできます。

ですからゲームパッドをマウス替わりにカスタマイズすることもでてきしまうわけです。

この仕組みがわかればキーロガーも作れてしまいます。

まずはUSBに接続されているデバイスを調べます。
pi@raspberrypi:~ $ cat /proc/bus/input/devices
 
I: Bus=0003 Vendor=1bcf Product=0005 Version=0110
N: Name="USB Optical Mouse"
P: Phys=usb-3f980000.usb-1.2/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:1BCF:0005.0001/input/input0
U: Uniq=
H: Handlers=mouse0 event0 
B: PROP=0
B: EV=17
B: KEY=1f0000 0 0 0 0 0 0 0 0
B: REL=143
B: MSC=10

I: Bus=0003 Vendor=0d62 Product=8070 Version=0111
N: Name="ELECOM Wired Keyboard"
P: Phys=usb-3f980000.usb-1.4/input0
S: Sysfs=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/0003:0D62:8070.0002/input/input1
U: Uniq=
H: Handlers=sysrq kbd leds event1 
B: PROP=0
B: EV=120013
B: KEY=10000 7 ff9f207a c14057ff febeffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=1f

私の場合はこんなかんじ。

マウスとキーボードが認識されています。重要なのはHandlersのeventです。マウスがevent0, キーボードがevent1です。これを記憶しておきます。先ほどのファイルというのがこれです。

マウスは/dev/input/event0, キーボードは/dev/input/event1に対応しています。

試しにマウスを監視してみましょう。
$hexdump /dev/input/event0

同様にキーボード
$hexdump /dev/input/event1

マウスやキーボードの定義は/usr/include/linux/input.hにされています。ここを開いてみてください。

キーボード系
#define KEY_Q                   16 キーボードのQ
#define KEY_W                   17 キーボードのW
#define KEY_E                   18
#define KEY_R                   19
#define KEY_T                   20

マウス系
#define BTN_LEFT                0x110 マウスの左クリック
#define BTN_RIGHT               0x111 マウスの右クリック 
#define BTN_MIDDLE              0x112 マウスのホイールクリック
こんなかんじでずらっと登録されています。

マウスやキーボードの入力があるとイベントが発生します。その構造体も定義されています。
struct input_event {
        struct timeval time;
        __u16 type;
        __u16 code;
        __s32 value;
};

event.type
  EV_KEY マウスやキーボードがクリックされたとき
  EV_REL マウスの位置移動、ホイールが回転したとき
event.code
  左クリックやらキーボードの入力キー
event.value
 1: キーを押したとき、 0: キーを離したとき
 他の数字 移動量

では早速マウスボタンを調べてみましょう。
input.c
//マウス入力を調べるプログラム
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int keyboardfd;
int mousefd;

int main(void)
{
  mousefd = open("/dev/input/event0", O_RDWR);
  keyboardfd = open("/dev/input/event1", O_RDWR);
  for (;;) {
    struct input_event event;

    if (read(mousefd, &event, sizeof(event)) != sizeof(event)) {
      exit(EXIT_FAILURE);
    }
    switch(event.type) {
      case EV_KEY:
printf("code:%x  value:%x\n", event.code, event.value);
        break;
      case EV_REL:
//printf("rel:%x  ", event.code);
break;
  case EV_ABS:
//printf("abs:%x  ", event.code);
break;
      default:
 
        break;
    }
    fflush(stdout);
  }
  
  close(keyboardfd);
  close(mousefd);
}
$gcc -o input input.c
 
pi@raspberrypi:~/Documents $ sudo ./input
code:110  value:0
code:112  value:1
code:110  value:1
code:112  value:0
code:114  value:1
code:114  value:0
code:113  value:1
code:113  value:0
code:110  value:1
code:110  value:0

110だから左クリックだなとか、value 1は押したとき、value 0は離したとき。
判明したのが次のとおり。カスタマイズの内容も書いておきました。


 で、ここからが少しやっかい。
BTN_EXTRAをCTRL + Wにすると、
BTN_EXTRA + CTRL + Wになってしまいます。 
つまり、BTN_EXTRAとBTN_SIDEの機能を無効にしたいのです。

結論を書くとマウスを無効にし、User Inputという仮想デバイスでマウス機能を再登録します。

ちなみにマウスを無効にするのはたった1行
ioctl(マウスちゃん, EVIOCGRAB, 1);

マウスを元に戻すのも1行
ioctl(マウスちゃん, EVIOCGRAB, 0);

あとはUser Inputでマウス機能を登録すればできあがりです!
コメントを書いておくのでプログラムを読んでください。

5mouse.c
//マウスをchromeブラウザ用にカスタマイズするプログラム
//サイドボタンを
//現在のタブを閉じる Ctrl+w
//開いている次のタブに移動する Ctrl+Tab 
//に設定する
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <string.h>

//ここでマウスとキーボードのイベントを設定してください。
#define MOUSE_EVENT "/dev/input/event0"
#define KEYBOARD_EVENT "/dev/input/event1"


#define die(str, args...) do { perror(str); exit(EXIT_FAILURE); } while(0)

int keyboardfd;
int mousefd;
int virtualfd;

void create_uinput_device (int fd) {
  struct uinput_user_dev uidev;
  memset(&uidev, 0, sizeof(uidev));

  snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "YUKIMOUSE");
  uidev.id.bustype = BUS_USB;
  uidev.id.vendor  = 0xAAAA;
  uidev.id.product = 0xBBBB;
  uidev.id.version = 1;

  if (write(fd, &uidev, sizeof(uidev)) < 0)
    die("create_uinput_device: write");

  if (ioctl(fd, UI_DEV_CREATE) < 0)
    die("create_uinput_device: ioctl");
}

void write_hack_event(int output, int type, int code, int value)
{
  struct input_event key_event;
  
  gettimeofday(&key_event.time, NULL);
  key_event.type = type;
  key_event.code = code;
  key_event.value = value;
  
  if(output == 0) {
write(keyboardfd, &key_event, sizeof(key_event));
} else if (output == 1) {
write(virtualfd, &key_event, sizeof(key_event));
}
}

int main(void)
{
mousefd = open(MOUSE_EVENT, O_RDWR);
keyboardfd = open(KEYBOARD_EVENT, O_RDWR);
virtualfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
//マウス機能を登録し、User Inputデバイスを作成する
//ここで左クリックを有効にするよーとか、マウス動かすよーとか登録
ioctl(virtualfd, UI_SET_EVBIT, EV_REL);
ioctl(virtualfd, UI_SET_RELBIT, REL_X);
ioctl(virtualfd, UI_SET_RELBIT, REL_Y);
ioctl(virtualfd, UI_SET_RELBIT, REL_WHEEL);
ioctl(virtualfd, UI_SET_EVBIT, EV_KEY);
ioctl(virtualfd, UI_SET_KEYBIT, BTN_LEFT);
ioctl(virtualfd, UI_SET_KEYBIT, BTN_RIGHT);
ioctl(virtualfd, UI_SET_KEYBIT, BTN_MIDDLE);
create_uinput_device(virtualfd);
//マウスを無効化
ioctl(mousefd, EVIOCGRAB, 1);
  for (;;) {
    struct input_event event;

    if (read(mousefd, &event, sizeof(event)) != sizeof(event)) {
      exit(EXIT_FAILURE);
    }
    switch(event.type) {
      case EV_KEY:
if(event.code == BTN_EXTRA && event.value == 1) {//EXTRAボタンを押したときCTRL + W
write_hack_event(0, event.type, KEY_LEFTCTRL, 1);
write_hack_event(0, event.type, KEY_W, 1);
write_hack_event(0, EV_SYN, SYN_REPORT, 0);
}else if(event.code == BTN_EXTRA && event.value == 0) {//EXTRAボタンを離したとき
write_hack_event(0, event.type, KEY_W, 0);
write_hack_event(0, event.type, KEY_LEFTCTRL, 0);
write_hack_event(0, EV_SYN, SYN_REPORT, 0);
}else if(event.code == BTN_SIDE && event.value == 1) {//SIDEボタンを押したとき CTRL + TAB
write_hack_event(0, event.type, KEY_LEFTCTRL, 1);
write_hack_event(0, event.type, KEY_TAB, 1);
write_hack_event(0, EV_SYN, SYN_REPORT, 0);
}else if(event.code == BTN_SIDE && event.value == 0) {//SIDEボタンを離したとき
write_hack_event(0, event.type, KEY_TAB, 0);
write_hack_event(0, event.type, KEY_LEFTCTRL, 0);
write_hack_event(0, EV_SYN, SYN_REPORT, 0);
}else {
write_hack_event(1, event.type, event.code, event.value);
}
        break;
      case EV_REL:
//printf("%x  ", event.code);
write_hack_event(1, event.type, event.code, event.value);
break;
case EV_ABS:
write_hack_event(1, event.type, event.code, event.value);
break;
      default:
write_hack_event(1, event.type, event.code, event.value);
//printf("0");
        break;
    }
    fflush(stdout);
  }
  
  //マウスを有効に戻す
  ioctl(mousefd, EVIOCGRAB, 0);
  
  close(keyboardfd);
  close(mousefd);
  close(virtualfd);
}

一応マウスを無効にするので注意が必要かと
$gcc -o 5mouse 5mouse.c 
$sudo ./5mouse

思っていたようにマウスをカスタマイズすることができました。
あとはスクリプトを作るなり、起動時に自動実行すればいいかと思います。

参考サイト 超絶素晴らしいサイトです。
Linux Input Subsystemの使い方

特定のキーボードを ESC 入力のためのフットペダルにする 
サンプルプログラムが分かりやすいです。 


ウィンドウズでマウスボタンをカスタマイズしていきます。

無料ソフトのHUTを利用します。

HUT ベクターからダウンロードしてください。
Hut_editorを実行します。
hut1
追加をクリック。

割り当てたいボタンを押して、キーを設定します。
 hut2
1回クリックで反応させるので、Onceにしておきます。
押しっぱなしとかも設定できるわけですね。
こんな感じ。

 登録した結果がこちら。
 hut3
これをProfileフォルダ内に名前を付けて保存。mouse.hutで保存しました。

次にHut_mainを実行。タスクトレイに表示されます。
hut4
青いお家みたいなのがHUT。右クリックからリストを選択。

hut5
下の初期プロファイルに先ほど保存したmouse.hutを登録。変更ボタンを押すと登録できます。

hut6
最後にオプションのMainタブ。自動起動をオンにします。

これで完成です。

次はリナックス編。プログラムを自作します。
 

最近ずっと5ボタンマウスについて考えていました。

5ボタンマウスについて考えることがあるのです。

その前に私が愛用しているのがバッファローのBSMBU19というマウスです。
 _SL1000_
このマウスです。既に4つ持っています。

マウスクリックが静かな有線マウスです。

写真を見ると分かるとおり、サイドボタンが2つ付いているのです。

サイドボタンはブラウザの「戻る」と「進む」が割り当てられています。

このサイドボタンが役立たずです。役立たず。役立たず。

私はブラウザの戻るや進むをほとんど使わないからです。

タブをどんどん開いていきます。常時4つか5つタブを開いているでしょう。

最近気が付いたのはこのサイドボタンはカスタマイズできる、ということです。

それで考えていたのは、このサイドボタンにどの機能を割り当てるべきか、です。

色々と試行錯誤した結果、ブラウザの「現在のタブを閉じる」と「開いている次のタブに移動する」を割り当てるべきではないかと考えていました。

本当にどうでもいいことなんですがずっと考えていました。笑 

私はchromeブラウザでタブを開きまくるので、タブ関連のキーを割り当てるべきだと思うのです。

ブラウザはタブブラウザが主流です。つまり複数のタブが開いているわけです。

このご時世、タブ1つで進むや戻るボタンを駆使している人などいるのでしょうか。

というわけでせっかく5ボタンマウスを使っているのだから、もっと便利な使い方はないかと試行錯誤していたわけです。

以前同じようなことを考えている人がいて、5ボタンマウスのサイドキーにCtrl割り振らない奴は人生の8割くらい損してる
 
私はCtrlではないように思うのです。

もっと便利な使い方があれば教えていただきたいです。

次回、ウィンドウズとlinuxそれぞれカスタマイズ方法を解説していきます。

ラズベリーパイをスーパーファミコンにしよう


ラズベリーパイ3を持っています。ラズベリーパイをスーパーファミコンにします。

この動画に刺激を受けてやってみたくなりました。

1.pisnesをダウンロード
 pisnes ここからpisnesをダウンロードします。

 解凍するだけです。ラズベリーパイ用にコンパイル済みです。
 snes9xと snes9x.guiが実行ファイルです。
 #snes9x romfile.sfc
 #snes9x.gui こちらはGUIでロムファイルを選択できます。

2. ソフトを用意します。
 自分の持っているソフトを用意してpisnes/romディレクトリの中にください。
 拡張子はsfcとなります。

3. ゲームパッドを接続します。
 ゲームパッドをUSBに接続します。
 logicoolのF310 定番ゲームパッドを使用しています。
  f310-gaming-gamepad-images
 つなぐだけです。pisnesでも自動認識してくれます。
 エミュに良くあるボタンの割り当てが不要です。とにかく接続するだけでOK。素晴らしいです。

4. ラズベリーパイが起動時に自動起動させます。
 せっかくなので自動起動させてみましょう。キーボードやマウスもいらなくなります。

/home/pi/Game/pisnes このディレクトリにpisnesを置いています。

 シェルスクリプトを作ります。
 直接 snes9x.guiを実行するのではなく、間接的にシェルスクリプトから実行させます。
 面倒くさいのですが、これはやっておくべきです。 

#sudo vi /usr/local/bin/snes-run-gui

snes-run-guiの内容
#!/bin/bash

BASEDIR=/home/pi/Game/pisnes

# Wait for the PS3 Game pad to be available
while [ ! -e /dev/input/js0 ]; do sleep 2; done

# The DISPLAY=:0 bit is important for the GUI to work
DISPLAY=:0 $BASEDIR/snes9x.gui
ここまで

スクリプトを実行できるようにします。
#sudo chmod +x /usr/local/bin/snes-run-gui

自動起動に登録
/home/pi/.config/lxsession/LXDE-pi/autostart の最後の行に1行追加します。
もしかしたら古いラズベリーパイの場合、/home/pi/.config/lxsession/LXDE/autostartかもしれません。

@/usr/local/bin/snes-run-gui

これで起動時にpisnesが立ち上がります。やってみましょう。

最後になぜシェルスクリプトから実行する理由は、直接snes9x.guiを実行するとキーボードを認識しなくなり、復帰できなくなるからです。
スーパーファミコンはできるのですが、元に戻せなくなったからです。
リモートからログインして復帰できるようになりましたが、、、汗

参考サイト
Building a SNES emulator with a Raspberry Pi and a PS3 gamepad
 

ラズベリーパイ3を買いました。これでトータル3つ目です。

全体的には早くなっていますが、ブラウザを開くとどうしても遅いです。

デスクトップPCとして使うにはかなりの忍耐が必要です。

設定したので忘れないうちに書きなぐって置きます。

OSのインストールはEnglishでインストールした方が良いでしょう。

日本語でインストールするといきなり文字化けします。あとからでも日本語に設定変更できます。

・まず初めにするのがネットワーク接続。
有線でネットワーク接続しました。

・IPアドレス固定
IPアドレスを固定しておくと後々便利です。

Iaアドレス 192.168.0.102で設定しました。PCやスマホとかと、かぶらなければOK

有線なのでネットワークアダプタがこの場合eth0となります。無線の場合にはwlan0となります。

sudo vi /etc/dhcpcd.conf  の内容
interface eth0
static ip_address=192.168.0.102/24
static routers=192.168.0.1
static domain_name_servers=8.8.8.8

これでラズベリーパイが起動すると自動的にネットにつながります。

・日本語表記
sudo apt-get install jfbterm
参考サイト  RYUS blog
 
・midoriのインストール 軽量ブラウザとしては一番ましでしょう。
#sudo apt-get install midori

・chromeのインストール
#sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5B393194

#sudo vi /etc/apt/sources.list
次の一行を追加
deb http://ppa.launchpad.net/canonical-chromium-builds/stage/ubuntu vivid main

#sudo apt-get update
#sudo apt-get install chromium-browser chromium-browser-l10n
これでchromiumが使えます。youtubeも視聴できます。

・ダウンロードゲッターのインストール
 chromiumで動画ゲッター のサイトから拡張機能をインストールをクリック。


・日本語フォントのインストール
このままではchromeの文字が汚いです。綺麗なフォントをインストールしましょう。
#sudo apt-get install fonts-vlgothic

#sudo apt-get install ttf-kochi-gothic ttf-kochi-mincho fonts-takao fonts-vlgothic fonts-ipafont xfonts-intl-japanese xfonts-intl-japanese-big xfonts-kaname 

インストールするだけでアプリのフォントが綺麗になります。勝手に最適なフォントを選んでくれるようです。

・音サウンド ヘッドホン/スピーカーに切り替える。
デフォルトで音はHDMI出力つまりディスプレイに流れるようになっています。

これをヘッドホン・スピーカー出力へと切り替えましょう。amixerデフォルトでインストール済み
#amixer cset numid=3 1
イヤホンやスピーカーをラズパイにつなげば、音が出ます。

元に戻すには最後を2に設定しなおします。
#amixer cset numid=3 2 
 
・動画を見る
動画プレイヤーはmplayerがおすすめです。軽い。
smplayerはmplayerのフロントエンド、重い。
一応vlcプレイヤーもインストールできますが、重い。
#sudo apt-get install mplayer
#sudo apt-get install smplayer
#sudo apt-get install vlc

・外付けHDD
exfatでフォーマット済みのHDDをラズベリーパイに接続させます。

#sudo fdisk -l
Device      Start        End    Sectors  Size Type
/dev/sda1      40     409639     409600  200M EFI System
/dev/sda2  409640 5860270983 5859861344  2.7T Microsoft basic data
この場合/dev/sda2が外付けHDDとして認識されています。環境によって異なります。
# sudo apt-get install exfat-fuse exfat-utils
再起動すると/media/pi/ 以下に自動マウントされます。


・processing 3.01
なんとprocessingがラズパイで動くようになりました。解凍して実効するだけ
#wget https://github.com/processing/processing/releases/download/processing-0247-3.0.1/processing-3.0.1-linux-armv6hf.tgz
#tar xvzf processing-3.0.1-linux-armv6hf.tgz
#cd processing-3.0.1/
# ./processing


・adobe flash player プラグインインストール
#wget http://mirror.archlinuxarm.org/armv7h/alarm/chromium-pepper-flash-12.0.0.77-1-armv7h.pkg.tar.xz
#tar Jxvf PepperFlash-12.0.0.77-1-armv7h.pkg.tar.xz
#sudo cp libpepflashplayer.so /usr/lib/chromium-browser/plugins/
#sudo vi /etc/chromium-browser/default

以下の記述を追加。
CHROMIUM_FLAGS="--ppapi-flash-path=/usr/lib/chromium-browser/plugins/libpepflashplayer.so --ppapi-flash-version=12.0.0.77 -password-store=detect -user-data-dir"

chromiumのアドレスバーでchrome://plugins にアクセス
adobe flash playerが有効になっていることを確認。
 
参考サイト 『イナムラ総研(仮)の開発レポート的な何か。』
 

・firefox Javajreインストール
firefoxとfirefoxのプラグインをインストールしました。
#sudo apt-get install iceweasel iceweasel-l10n-ja
#sudo apt-get install icedtea-plugin
chromeでもjavaアプレットが動作するようになります。
OpenProcessing も動作します。
 
・マンガビューワ
#sudo apt-get install comix
見開き表示DにしてフルスクーリンF、横幅に合わせるW。
 
新しいラズベリーパイが登場するとどうしても買ってしまいます。次こそはスルーします。
 

素数を渦巻き状に並べて、素数に色を付けていくと対角線や水平線
が現れるようです。
 Ulam_1
これがウラムの螺旋。

こういう視覚情報を伴ったプログラミングはprocessingと相場が決まっていますので、processingでプログラミングしてみましょう。

ウラムの螺旋 wikipedia

wikipediaを見ると左回りですが、右回りでも良さそうです。

プログラミングをすると下の図のように感じになります。数字6000までやってみました。

確かに対角線っぽいものが現れる。
 ulam_spiral

processing 3.01で動作確認しています。

//素数らせんプログラム
final int maxx = 800;
final int maxy = 800;


int i = 0;
int[][] cell = new int[80][80];
int[][] flag = new int[80][80];
int[][] prime = new int[80][80];
int tmpX, tmpY;

int x = 40;
int y = 40;
//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(800, 800);
  //frameRate(20);
  background(255);
  noLoop();
}

boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

void mouseMoved() {
  if(tmpX != (mouseX / 10) || tmpY != (mouseY / 10)) {
    println(cell[mouseX / 10][mouseY / 10] + " " + prime[mouseX / 10][mouseY / 10]);
    tmpX = mouseX / 10;
    tmpY = mouseY / 10;
  }
}
void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / 10); i++) {    
    line( i * 10, 0, i * 10, 800);
  }
   
  for ( i = 0; i < (maxy  / 10); i++) {
    line(0, i * 10, 800, i * 10);
  }
  
  for (i = 0; i < 6000; i++) {
    if(isPrime(i)) { //素数のとき
      
      rect(x * 10, y * 10, 10, 10);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  

}

次はyoutubeで見つけた吉原宏治さんの素数はスパイラル上にきれいに並んでいた、面白そうでなのプログラミングしてみます。


spiral3
このスパイラルを再現してみたいと思います。

ただの素数ではなくて、ここからnを求めるようです。
spiral2
nの求め方 
素数11の場合、n = ((11^2) - 1) / 24   
n = 5となります。 5の数字で色を塗ります。

もう一つ 素数13の場合、 n = ((13^2) - 1) / 24
n = 7 7の数字で色を塗ります。

400までやってみた結果が下の図。
primespiral6


//素数らせんプログラム

// [20, 20]のマスを用意、スタート地点[10, 10]から右回りに進む。

final int maxx = 400;
final int maxy = 400;

int maxnumber = 400;  //最大値
int[] color4 = new int[maxnumber * maxnumber];
int[] primeflag = new int[maxnumber * maxnumber];
int n;

int i = 0;
int[][] cell = new int[40][40];
int[][] flag = new int[40][40];
int[][] prime = new int[40][40];
int tmpX, tmpY;

int x = 10;  //スタート地点x
int y = 10;  //スタート地点y
int cellsize = 20;
//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(400, 400);
  //frameRate(20);
  background(255);
  noLoop();
  
  for (i = 0; i < maxnumber; i++) {
    if(isPrime(i)) {
      n = ((i * i) - 1) / 24;
      primeflag[n] = 1;
      if(i % 10 == 1) {
        color4[n] = 1;
      } else if (i % 10 == 3) {
        color4[n] = 3;
      } else if (i % 10 == 7) {
        color4[n] = 7;
      } else if (i % 10 == 9) {
        color4[n] = 9;
      }
    }
  }
}

boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

void mouseMoved() {
  if(tmpX != (mouseX / cellsize) || tmpY != (mouseY / cellsize)) {
    println(cell[mouseX / cellsize][mouseY / cellsize] + " " + prime[mouseX / cellsize][mouseY / cellsize]);
    tmpX = mouseX / cellsize;
    tmpY = mouseY / cellsize;
  }
}
void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / cellsize); i++) {    
    line( i * cellsize, 0, i * cellsize, 400);
  }
   
  for ( i = 0; i < (maxy  / cellsize); i++) {
    line(0, i * cellsize, 800, i * cellsize);
  }
  
  for (i = 0; i < maxnumber; i++) {
    if(primeflag[i] == 1) { //素数のとき
      //print (i);
      if(color4[i] == 1) {
        fill(255, 0, 0);
      } else if (color4[i] == 3) {
        fill(255, 255, 0);
      } else if (color4[i] == 7) {
        fill(255, 0, 255);
      } else if (color4[i] == 9) {
        fill(0, 255, 255);
      }
      rect(x * cellsize, y * cellsize, cellsize, cellsize);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  
}

数字4600までやってみたのが下の図。 

確かに綺麗にスパイラルになっています。
 primespiral7

//素数らせんプログラム

// [80, 80]のマスを用意、スタート地点[40, 40]から右回りに進む。
//一つ進むごとに右 -> 下 -> 左 -> 上と進行方向を変える。
//既に数字が埋まっている場合には、方向を変えず直進する。これを繰り返す。

final int maxx = 800;
final int maxy = 800;
final int cellsize = 10;

int x = 40;  //スタート地点x
int y = 40;  //スタート地点y

int maxnumber = 4600;  //最大値
int[] color4 = new int[maxnumber * maxnumber];
int[] primeflag = new int[maxnumber * maxnumber];
int n;

int i = 0;
int[][] cell = new int[80][80];
int[][] flag = new int[80][80];
int[][] prime = new int[80][80];
int tmpX, tmpY;

//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(800, 800);
  //frameRate(20);
  background(255);
  noLoop();
  
  //最初に素数からnを求める
  for (i = 0; i < maxnumber; i++) {
    if(isPrime(i)) {
      n = ((i * i) - 1) / 24;
      primeflag[n] = 1;
      if(i % 10 == 1) {
        color4[n] = 1;
      } else if (i % 10 == 3) {
        color4[n] = 3;
      } else if (i % 10 == 7) {
        color4[n] = 7;
      } else if (i % 10 == 9) {
        color4[n] = 9;
      }
    }
  }
}

//素数判定
boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

//マウスが動いたらコンソールに数字を表示
void mouseMoved() {
  if(tmpX != (mouseX / cellsize) || tmpY != (mouseY / cellsize)) {
    println(cell[mouseX / cellsize][mouseY / cellsize] + " " + prime[mouseX / cellsize][mouseY / cellsize]);
    tmpX = mouseX / cellsize;
    tmpY = mouseY / cellsize;
  }
}

void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / cellsize); i++) {    
    line( i * cellsize, 0, i * cellsize, 800);
  }
   
  for ( i = 0; i < (maxy  / cellsize); i++) {
    line(0, i * cellsize, 800, i * cellsize);
  }
  
  for (i = 0; i < maxnumber; i++) {
    
    //nの数字のとき、色でマスを塗る。
    if(primeflag[i] == 1) {
      //print (i);
      if(color4[i] == 1) {//赤
        fill(255, 0, 0);
      } else if (color4[i] == 3) {//黄色
        fill(255, 255, 0);
      } else if (color4[i] == 7) {//紫
        fill(255, 0, 255);
      } else if (color4[i] == 9) {//水色
        fill(0, 255, 255);
      }
      rect(x * cellsize, y * cellsize, cellsize, cellsize);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  
}


   

探偵ナイトスクープで素数をやっていました。これを見たのがきっかけです。

これも簡単にprocessingでできてしまいます。やってみましょう。 

↑このページのトップヘ