おふとんガレージ

技術的な忘備録とか雑記

OpenGL入門 2日目

前回までの作業内容

  • ウィンドウを表示する
  • 初期状態の盤面生成

今回の作業内容

  • クリックされた座標を読み込む

次回以降の目標

  • オセロのルールに従った石が置けるかどうかの判定
  • 石を置いた後に周囲の石を反転させる。
  • 石が置けない場合、ゲームの終了を判定する。

othello.cpp(10/19時点)

#include <iostream>
#include <GLUT/GLUT.h>

#define BOARD_SIZE 8
#define NONE 0
#define BLACK 1
#define WHITE 2

using namespace std;
int screenWidth = 800, screenHeight = 800, turn = 0;
char board[BOARD_SIZE][BOARD_SIZE];

void showStone(){
    //盤面に配置された石の描画
    glPointSize(60);
    for(int i = 0; i < BOARD_SIZE; i++){
        for(int j = 0; j < BOARD_SIZE; j++){
            if(board[i][j] == BLACK){
                //黒石の描画
                glColor3d(0, 0, 0);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }else if(board[i][j] == WHITE){
                //白石の描画
                glColor3d(1, 1, 1);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }
        }
    }
}


void mouse(int button, int state, int x, int y){
    int i = 0, j = 0;
    cout << "turn : " << turn << endl;
    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
        //ウィンドウ内をクリックしたときの処理
        cout << "(x, y) == (" << x << "," << y << ")" << endl;
        
   //クリックした箇所が盤上でない時→処理終了
        if(x < 80 || x > 720) return;
        if(y < 80 || y > 720) return;
        
        //クリックされた座標(x, y)から盤上の座標(i, j)への変換
        while(x > 80){
            x -= 80;
            i++;
        }
        
        while(y > 80){
            y -= 80;
            j++;
            
        }
        
        cout << i << " " << j << endl;
  
   //クリックされた箇所に新規に石を配置する
   //奇数ターンであれば黒、偶数ターンであれば白
        if(turn % 2 == 1){
            board[i - 1][j - 1] = WHITE;
            cout << "WHITE" << endl;
        }else{
            board[i - 1][j - 1] = BLACK;
            cout << "BLACK" << endl;
        }
        
        turn++;

   //描画実行
        showStone();
        glFlush();
    }
    
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //盤面のマス目作成
    glColor3d(0.0, 0.0, 0.0);
    glLineWidth(3);
    glBegin(GL_LINES);
    
    for(int i = 0; i <= BOARD_SIZE; i++){
        glVertex2i(80 + 80 * i, 720);
        glVertex2i(80 + 80 * i, 80);
        
        glVertex2i(80, 80 + 80 * i);
        glVertex2i(720, 80 + 80 * i);
    }
    glEnd();
    
    //盤面上の4点の描画
    glColor3d(0.0, 0.0, 0.0);
    glPointSize(10);
    glBegin(GL_POINTS);
        glVertex2i(240, 240);
        glVertex2i(240, 560);
        glVertex2i(560, 240);
        glVertex2i(560, 560);
    glEnd();
    
    showStone();
    glFlush(); //描画実行
    
    
}

void initialize(){
    //初期盤面生成
    glClearColor(0, 0.5, 0, 1); //背景色設定
    
    //以下石の初期配置
    for(int i; i < BOARD_SIZE * BOARD_SIZE; i++)
        board[i / BOARD_SIZE][i % BOARD_SIZE] = NONE;
    
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2] = BLACK;
    board[BOARD_SIZE / 2][BOARD_SIZE / 2 - 1] = BLACK;
    
    board[BOARD_SIZE / 2][BOARD_SIZE / 2] = WHITE;
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2 - 1] = WHITE;
}

int main(int argc, char* argv[]) {
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(screenWidth, screenHeight);
    
    glutCreateWindow("Othello");
    gluOrtho2D(0, 800, 800, 0); //座標系指定
    initialize();

	glutMouseFunc(mouse);
    glutDisplayFunc(display);
    glutMainLoop();
    
    return 0;
}

実行結果

turn : 0
(x, y) == (523,435)
6 5
BLACK
turn : 1
turn : 1
(x, y) == (531,503)
6 6
WHITE
turn : 2
turn : 2
(x, y) == (468,521)
5 6
BLACK
turn : 3

f:id:zurvlk:20161019215017p:plainf:id:zurvlk:20161019215028p:plainf:id:zurvlk:20161019215038p:plainf:id:zurvlk:20161019215044p:plain

メモ

  • カウンターとして変数を利用する時に0で初期化することを忘れないようにする。
  • 敵AIを除けば石が置けるかどうかの判定が山場っぽい。がんばる。

OpenGL入門 1日目

だいたい個人用作業メモ

当面の目標

今回までの作業内容

  • ウィンドウを表示する
  • 初期状態のオセロの盤面の生成、配置


othello.cpp(10/18時点)

#include <iostream>
#include <GLUT/GLUT.h>

#define BOARD_SIZE 8
#define NONE 0
#define BLACK 1
#define WHITE 2

using namespace std;
int screenWidth = 800, screenHeight = 800;
char board[BOARD_SIZE][BOARD_SIZE];


void showStone(){
    //盤面に配置された石の描画
    glPointSize(60);
    for(int i = 0; i < BOARD_SIZE; i++){
        for(int j = 0; j < BOARD_SIZE; j++){
            if(board[i][j] == BLACK){
                //黒石の描画
                glColor3d(0, 0, 0);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }else if(board[i][j] == WHITE){
                //白石の描画
                glColor3d(1, 1, 1);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }
        }
    }
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //盤面のマス目作成
    glColor3d(0.0, 0.0, 0.0);
    glLineWidth(3);
    glBegin(GL_LINES);
    
    for(int i = 0; i <= BOARD_SIZE; i++){
        glVertex2i(80 + 80 * i, 720);
        glVertex2i(80 + 80 * i, 80);
        
        glVertex2i(80, 80 + 80 * i);
        glVertex2i(720, 80 + 80 * i);
    }
    glEnd();
    
    //盤面上の4点の描画
    glColor3d(0.0, 0.0, 0.0);
    glPointSize(10);
    glBegin(GL_POINTS);
        glVertex2i(240, 240);
        glVertex2i(240, 560);
        glVertex2i(560, 240);
        glVertex2i(560, 560);
    glEnd();
    
    showStone();
    glFlush();  //描画実行
}

void initialize(){
    //初期盤面生成
    glClearColor(0, 0.5, 0, 1); //背景色設定
    
    //以下石の初期配置
    for(int i; i < BOARD_SIZE * BOARD_SIZE; i++)
        board[i / BOARD_SIZE][i % BOARD_SIZE] = NONE;
    
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2] = BLACK;
    board[BOARD_SIZE / 2][BOARD_SIZE / 2 - 1] = BLACK;
    
    board[BOARD_SIZE / 2][BOARD_SIZE / 2] = WHITE;
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2 - 1] = WHITE;
}

int main(int argc, char* argv[]) {
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(screenWidth, screenHeight);
    
    glutCreateWindow("Othello");
    gluOrtho2D(0, 800, 800, 0); //座標系指定
    initialize();
    
    glutDisplayFunc(display);
    glutMainLoop();
    
    return 0;
}

実行結果

f:id:zurvlk:20161018224753p:plain

メモ

  • 点の描画はGL_POINTじゃなくてGL_POINTS
  • 描きたい図形毎に、色指定、サイズ指定、glBegin(描画したい図形)、具体的な描画内容、glEnd()の流れ
  • display関数の最後にglFlush()関数で発行したOpenGLコマンドを実行

windowsで書かれたopenGLプログラムをxcodeで走らせるときの覚え書き

個人的なメモ用

Windows (Visual Studio)

#include <glut.h> 
#include <math.h>
//省略
int main(int argc, char* argv[]){
    //省略
    _sleep(20); //20ms毎に処理
}

Xcode

#include <GLUT/GLUT.h> //変更
#include <unistd.h> //追加
#include <math.h>
//省略
int main(int argc, char* argv[]){
    //省略
    usleep(20000); //変更
    // 20ms == 20000μs
}

その他

  • brewでインストールしたライブラリを用いる場合
    • TERGET-Build Settings-Search Paths-Header Search Paths
      • /usr/local/includeを追加
  • OpenGLを使えるようにする
    • TERGET-Build Phases-Link Binary With Libraries

Bash on Windowsで遊んでみた

Thinkpad X240に今更ながらWindows 10 Anniversary Updateを適用した。
とりあえずの第一印象はスタートメニューが若干変わったなーくらい。

あと大きな変更点と言えばBash on Ubuntu on WindowsがInsider Programに参加してなくても使えるようになった点。
個人的に惹かれてはいたもののいかんせん面倒くさくて放置してたので今更ながらうちで使ってる環境の紹介と感想をば。

やったこと
下準備

  • ConEmuインストール
  • Xmingインストール
  • Windows10 開発者モードへの変更

Bash on Windows導入

  • 機能追加
  • zsh, git導入
  • oh-my-zsh導入 テーマ変更
  • もろもろ


ConEmuインストール
流石に素のcmd.exeだと色々と味気ないので評価が高いコンソールエミュレータとしてConEmu導入
oh-my-zshのテーマの一つであるagnosterすきすきマンなのでPowerLineフォントを入れる必要があったのだが、いかんせんcmd.exeにしろPowerShellにしろフォントの変更が面倒だったので導入。
PowerLineフォント入れなくても文字化けしないのとタブが使えるのはもっそい便利。
最初お世話になってるterminatorを入れようとしたけど文字化けの対処にコケたのは内緒
bash.exeを起動してると矢印キーが効かない不具合があるので以下の呪文をSettings-Startup-Tasksに追加しておくと捗る

C:\windows\system32\bash.exe -l -i -cur_console:p1 -new_console:p:n 

あとはこれを適当な名前としてタスクとして保存、これでタブを追加する時に矢印キーが正常に使える状態でbash.exeを起動するオプションが追加される。あとはカラースキームをいつものsolarizedにしたりした。

Xming X Server for Windowsインストール
ググれば一発で出てくるので省略、ちゃんとフォントも入れたけど日本語文字化け問題は解消せず。

Windows10 開発者モードへの変更
スタート-設定-更新とセキュリティ-開発者向け

開発者向け機能を使うから開発者モードをオンに
とりあえず下準備は終了。やりました。

機能の追加
コントロールパネル-Windowsの機能の有効化または無効化
Windows Subsystem on Linux (beta)のチェックをonに

とりあえずcmd.exeを起動しbashと入力、色々出てくるので画面に従って進めればおk。

その他
この先は個人の好みなのであっさりと

oh-my-zshのインストールスクリプトを走らせるためにはgitが必要なので導入
同時にGUIも一応使えるようにx11-appsも、あとは肝心のzsh

sudo apt-get install git zsh x11-apps

sudoするといちいちうるさいので/etc/hostsを若干追記
最初の行を

127.0.0.1 localhost (マシン名)

に変更すれば鬱陶しいunable to resolve hostなんちゃらってエラーは消える。

oh-my-zshをインストール

cd
sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

~/.zshrcを編集

変更前
ZSH_THEME="robbyrussell"
変更後
ZSH_THEME="agnoster"

デフォルトシェルの変更が出来ないので~/.profileの適当なとこに一行zshと追加、多分もっと良いやり方があるはず。


その他メモ

  • Çドライブ、Dドライブ等は/mnt以下にマウントされる
  • 起動時のディレクトリは/mnt/(Windowsのインストールドライブ)/Users/[UserName]

ここに.zshrcなり.vimrcなり置いても無意味なので、一回cdコマンドで/home/[UserName]に移動する癖をつけた方がいいかも?

  • だいたいのものはapt-getでなんとかなる、フォントに目を瞑ればGUIも使える

日本語表記が時々乱れるとかもあるけど、なんだかんだで実用性もあるしこれから積極的に使っていきたいところ。
vagrantみたいに見れるディレクトリに制限が無いのはありがたい。ミスったら全部吹っ飛ぶ危険はあるけど。

全くの初心者が遺伝的アルゴリズムについて考えてみた

色々あって勉強する機会があったので忘備録代わりに


そもそも遺伝的アルゴリズムとは

解の候補となる個体を複数用意し、それらを組み合わせ、適合度が高いものを残しながら解を探索するアルゴリズム


今回は巡回セールスマン問題(TSP)を解くことが目的であったため、交叉方法に部分一致交叉、変異には2点の位置をランダムで交換した。
親世代の中で巡回路長が短いもの上位10%をエリートとし、変異や交叉を行わずに次世代へ受け継がせた。

部分一致交叉

  1. 親となる巡回路を2つランダムに選択する
  2. ランダムで交叉開始箇所と終了箇所を選択する
  3. 交叉範囲内にて親の同位置の遺伝子をペアとする
  4. 同一個体内のペアとなってる遺伝子の位置を交換する

巡回路の評価方法は単純に巡回路長を用いた。

選択・淘汰はトーナメント選択を適用。
ランダムに集団から4個体選出し、最も巡回路長が短い物を選択する。

これを個体数分繰り返し、子世代の比率はエリート10%、交叉、淘汰を行ったもの90%としてみた。

値の決め方は基本適当。

結果
案の定うまく行きませんでした。知ってた。
交叉する範囲が広い場合、部分一致交叉を用い、点の排他性を保とうと試みると親の遺伝子情報が大きく破壊され、ランダム探索に近いものとなってしまう。

サブツアー交叉を用いることができればなんとかなったのかもしれないけど実装力がない。つらい。

アルゴリズム自体は比較的単純なのに実装力がなさすぎてしんだ。
現状だと精度は最近傍法で初期順回路を生成して、2-opt、or-opt改善を用いた方が速度的にもはやい。

勿論、遺伝的アルゴリズム自体がダメってわけでなくて、純粋にわたしのコーディング力が無い現実に直面させられた。

つらい。

github.com

node.jsのtwitモジュールを使ってTLをUserStreamで取得してみる

環境

  • Raspberry Pi2 + Raspbian
  • Node v6.3.0 + npm v3.10.3 導入済
  • Consumer Key と Access Token 取得済

twitモジュールのインストール

$ nam install twit

UserStreamを取得させてみる

Consumer Key と Access Token は取得したものをコピペしてください。

userstream.js

var twit = require('twit');

var twitter = new twit({
        consumer_key            : 'consumer_key',
        consumer_secret         : 'consumer_secret',
        access_token            : 'access_token',
        access_token_secret     : 'access_token_secret'
});

var stream = twitter.stream('user');

stream.on('tweet', function(tw){
        var text = tw.text;
        var screen_name = tw.user.screen_name;
        var user_name = tw.user.name;
        var time = tw.created_at;
        console.log(user_name +' ( @' + screen_name + ' ) ' + time + '\n' 
                                + text +'\n');
});

想像よりはるかに簡単でびびった(KONAMI


おまけ

nyan.js

var twit = require('twit');

const MY_TWITTER_ID == user_id;  
var twitter = new twit({
        consumer_key            : 'consumer_key',
        consumer_secret         : 'consumer_secret',
        access_token            : 'access_token',
        access_token_secret     : 'access_token_secret'
});

var stream = twitter.stream('user');


stream.on('tweet', function(tw){
	var text = tw.text;
	var screen_name = tw.user.screen_name;
	var user_name = tw.user.name;
	var time = tw.created_at;

        var isRetweet = tw.retweeted;
        var isRetweet2 = (new RegExp(/(R|Q)T @[^\s ]+/g)).test(text);
        
        if(user_id == MY_TWITTER_ID){ return;}
        if(isRetweet || isRetweet2){ return; }


	if(text.match(/にゃ/)){
		var tweet = '@' + screen_name + ' にゃーんっ'; 
		twitter.post('statuses/update', { status: tweet }, function(err, data, response){
		
			if(!err) {
				console.log('Posted : ' + data.user.screen_name + ' > ' + data.text + ' (' + data.created_at + ')');
			}	
		});
	}	
	//console.log(user_name +' ( @' + screen_name + ' ) ' + time + '\n' + text +'\n');
});

TLにねこさんがいたら鳴き声を返すよ。
RTと自分のツイートに反応しないように書き足したよ
 

centosにruby2.3.1を入れた時のおはなし

rbenvでruby2.3.1を入れた時になかなかバージョンが切り替わらなくて四苦八苦したのでメモ代わりに

 

環境

CentOS 6.8

 

 

手順

1.rbenvをダウンロード、PATH追加

> git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

 

#.zshrc

以下追加

export PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"

 

$HOME/.rbenv/shimsが一番優先されるように一番前に追加する

 

本来なら eval "$(rbenv init -)"と.zshrcに追加すれば動くはず。

うまく動いてくれなかったので対処療法として~/.rbenv/shimsにPATHを通しておく。

ちゃんと原因調べる気力?ないです(小声)

 

とりあえずrbenvが上手く導入できてるか確認

> source .zshrc

> rbenv --version

rbenv 1.0.0-21-g9fdce5d

 

よさげ

 

2.rbenvを使ってrubyをインストールする

 

> rbenv install -l

(略)

2.3.0
2.3.1
2.4.0-dev
2.4.0-preview1

(略)

 

2.3.1がぱっと見て新しそうだから入れてみる。

> rbenv install 2.3.1

待ってればインストールできる。結構かかるのでだらだら待ちます。

 

> ruby -v

ruby 1.8.7 (2013-06-27 patchlevel 374) [x86_64-linux]

 

> rbenv global 2.3.1

> ruby -v

ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]

 

ここでrubyのバージョンがrbenvでインストールしたのに変わってれば成功

$HOME/.rbenv/shimsにPATHを通すとこまでで詰まってたのでメモ代わりに。

 

 

個人用小ネタとか(zsh補完関数の導入、vim &lt;tab&gt;の補完がうまくいかない時の対処法)

個人的忘備録なので詳しいことはgoogle先生

 

zsh補間関数の導入

 

使用環境

  • OSX El Captian
  • zsh 5.2 + oh-my-zsh
  • iTerm2 build 3.0.2

 

1.fpathが通ってるディレクトリの確認

 

> echo $fpath

~/.oh-my-zsh/plugins/git ~/.oh-my-zsh/functions ~/.oh-my-zsh/completions /usr/local/share/zsh/site-functions /usr/local/Cellar/zsh/5.2/share/zsh/functions

 

ぱっと見 ~/.oh-my-zsh/functions に放り込むのが一番手っ取り早そう

 

2.放り込む

> mkdir ~/.oh-my-zsh/functions

>cp _myfunction ~/.oh-my-zsh/functions/

> exec zsh

 

放り込むディレクトリはfpathが通ってるとこか、それか適当にディレクトリ作ってfpath通してあげればよさげ。

 

Vim <tab>でエラー吐く時の対処

 

1.症状

 > vim <tab>

_vim_files: function definition file not found

 

2.対処

.zcomdumpの確認

> ls -la ~ | grep .zcomdump

-rw-r--r--    1 user  staff    37K  9  8  2015 .zcompdump-MacBook-Pro(username)-5.1

-rw-r--r--    1 user  staff    38K  6 15 14:44 .zcompdump-*-5.1

-rw-r--r--    1 user  staff    38K  6 28 10:33 .zcompdump-*-5.2

 

削除

> rm .zcomdump*

> exec zsh