読者です 読者をやめる 読者になる 読者になる

Segmentation Fault

デジタル土方の落書き帳

Javascriptでオセロ(その1)

html javascript

HTML+JavaScriptでブラウザで動くオセロを実装してみる。
制限付き(*1)で動いたところまで。

ソースコードはほとんど参考(*2)のまま。


(*1) 機能制限

  • AIなし(人間vs人間だけ)
  • 黒が先行
  • パス不可
  • 勝利判定なし

ソースコード

html

othello.html

<html>
<head>
	<title>Othello</title>
	<link rel="stylesheet" type="text/css" href="css/board.css">
</head>

<body>
	<script type="text/javascript" src="js/othello.js"></script>
	
	<!-- 盤面の要素定義 -->
	<div style="display:none">
		<div id="cell" class="square"><div class="cell"></div></div>
		<div id="black" class="square"><img class="block" src="img/black.png"></img></div>
		<div id="white" class="square"><img class="block" src="img/white.png"></img></div>
	</div>

	<div id="board"></div>


</body>
</html>
javascript

othello.js

(function() {
    // 変数定義
    var BOARD_TYPE = {
        'WIDTH' :8,
        'HEIGHT':8,
    };

    var PIECE_TYPE = {
        'NONE'   : 0,
        'BLACK'  : 1,
        'WHITE'  : 2,
        'MAX'    : 3,
    };

    var stone;
    var board = [];

    var turn = PIECE_TYPE.BLACK;
    var checkTurnOver = function(x, y, flip) {
    
        var ret = 0;
        
        for (var dx = -1; dx <= 1; dx++) {
            for(var dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) {
                    continue;
                }
            
                var nx = x + dx;
                var ny = y + dy;
                var n = 0;
                while(board[nx][ny] == PIECE_TYPE.MAX - turn) {
                    n++;
                    nx += dx;
                    ny += dy;
                }
                
                if (n > 0 && board[nx][ny] == turn) {
                    ret += n;
                    
                    if (flip) {
                        nx = x + dx;
                        ny = y + dy;
                        
                        while(board[nx][ny] == PIECE_TYPE.MAX - turn) {
                            board[nx][ny] = turn;
                            nx += dx;
                            ny += dy;
                        }
                        
                        
                    }
                }
            }
        }
        
        return ret;
    };
    
    var showBoard = function() {
    
        var b = document.getElementById("board");
        
        while(b.firstChild) {
            b.removeChild(b.firstChild);
        }
        
        for(var y = 1; y <= BOARD_TYPE.HEIGHT; y++) {
            for(var x = 1; x <= BOARD_TYPE.WIDTH; x++) {
                var cell = stone[board[x][y]].cloneNode(true);
                
                cell.style.left = ((x - 1) * 31) + "px"; 
                cell.style.top = ((y - 1) * 31) + "px"; 
                b.appendChild(cell);
                
                if (board[x][y] == PIECE_TYPE.NONE) {
                    (function() {
                        var _x = x;
                        var _y = y;
                        //alert("break point")
                        cell.onclick = function() {
                            if (checkTurnOver(_x, _y, true) > 0) {
                                board[_x][_y] = turn;
                                showBoard();
                                turn = PIECE_TYPE.MAX - turn;
                            }
                            
                        };
                    })();
                }
            }
        }
        
    };

    onload = function() {
        
        // 0:石無し, 1:黒, 2:白
        stone = [
            document.getElementById("cell"),
            document.getElementById("black"),
            document.getElementById("white")
        ];
        
        // PIECE種別の凍結(念のため)
        Object.freeze(PIECE_TYPE);
        
        // 盤面を初期化
        for (var i = 0; i < 10; i++) {
            board[i] = [];
            for (var j = 0; j < 10; j++) {
                board[i][j] = PIECE_TYPE.NONE;
            }
        }
        
        // 黒白の初期配置
        board[4][5] = PIECE_TYPE.BLACK;
        board[5][4] = PIECE_TYPE.BLACK;
        board[4][4] = PIECE_TYPE.WHITE;
        board[5][5] = PIECE_TYPE.WHITE;
        
        // 盤面表示
        showBoard();
    };
})();
css
#board{
    position            : relative;
}

.cell
{
    position            : relative;
    top                 : 1px;
    left                : 1px;
    width               : 31px;
    height              : 31px;
    background-color    : #00ff00;
}

.square
{
    position            : absolute;
    width               : 33px;
    height              : 33px;
    background-color    : #000000;
}

.block
{
    display             : block;
    position            : relative;
    top                 : 1px;
    left                : 1px;
    width               : 31px;
    height              : 31px;
}
その他

black.png
f:id:segmentation-fault:20170320225002p:plain

white.png
f:id:segmentation-fault:20170320225005p:plain

実行結果

f:id:segmentation-fault:20170320225855p:plain


次回は下記を目標に作業。


(*2 参考)
【プログラミング】オセロを1時間で作ってみた【実況解説】 by t-kihira ニコニコ技術部/動画 - ニコニコ動画

ソースコードでよく使う英単語

ソースコード書くときによく使う英単語(と対義語)。

動詞系

  • add/del
  • create/destory
  • start/stop
  • allow/deny
  • enqueue/dequeue
  • get/put
  • push/pop
  • write/read
  • send[snd]/recv[rcv]
  • lock/unlock
  • import/export

その他

  • head/tail
  • prev/next
  • old/new


deleteなのかeraseなのか、lastなのかendなのかは曖昧だったりする。
Linuxカーネルソースコードとか、ソフトウェアのコンフィグで使われてる実例から一覧を作ろうかな。

kivyで始めるGUIプログラミング

python kivy

kivyを使ってpythonでサクッと簡単(*1)にGUIプログラミングを試してみる。

(*1)環境構築はあまりサクッとは行かない模様


[実行環境]

いつものLinux側でプログラムを実行してWindows側で表示するスタイル。

事前準備

$ python --version
Python 3.5.1
$ sudo yum install python-pip 
$ pip install cython==0.23
$ pip install pygame
$ pip install kivy

プログラム作成

本家サイトのサンプルそのまま。

test.py

from kivy.app import App
from kivy.uix.button import Button

class TestApp(App):
    def build(self):
        return Button(text='Hello World')

TestApp().run()

実行結果

$ python test.py


f:id:segmentation-fault:20170308215016p:plain

XORで暗号化&複合化

C/C+ 暗号化

最も簡単な暗号化/複合化を試してみる。
任意のデータとある定数値の排他的論理和(XOR)を2回とると元のデータに戻る性質を利用する。

例)

任意のデータ : 10101010
XORをとる定数: 11110000

1回目
    10101010
XOR 11110000
-------------
    01011010

2回目
    01011010
XOR 11110000
-------------
    10101010 ★

ソースコード

1byte単位で暗号/複合キーとのXORをとりファイルへ書き出す。

xor.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#define XOR_KEY 0xE5

int main(int argc, char* argv[])
{

    if (argc != 3) {
        printf("usage : %s <src file> <dst file> \n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE* srcfp = fopen(argv[1], "rb");
    if (NULL == srcfp) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    FILE* dstfp = fopen(argv[2], "w+b");
    if (NULL == dstfp) {
        perror("fopen");
        fclose(srcfp);
        exit(EXIT_FAILURE);
    }

    while(0 == feof(srcfp)) {
        uint8_t dat = 0x00;
        size_t rs = fread(&dat, sizeof(dat), 1, srcfp);
        if (rs == 0) {
            break;
        }

        /* 暗号化 or 複合化 */
        dat ^= XOR_KEY;

        fwrite(&dat, sizeof(dat), 1, dstfp);
    }

    fclose(dstfp);
    fclose(srcfp);

    return 0;
}

暗号化対象のデータ

file1.txt

$ cat file1.txt
abcdefghijklmnopqrstuvwxyz
$
$ hexdump -C file1.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b

実行結果

$ gcc -o xor xor.c
$ ./xor file1.txt file2.txt
$ ./xor file2.txt file3.txt
$
$ hexdump -C file1.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b
$ hexdump -C file2.txt
00000000  84 87 86 81 80 83 82 8d  8c 8f 8e 89 88 8b 8a 95  |................|
00000010  94 97 96 91 90 93 92 9d  9c 9f ef                 |...........|
0000001b
$ hexdump -C file3.txt
00000000  61 62 63 64 65 66 67 68  69 6a 6b 6c 6d 6e 6f 70  |abcdefghijklmnop|
00000010  71 72 73 74 75 76 77 78  79 7a 0a                 |qrstuvwxyz.|
0000001b

エクセルでプログレスバーを表示する

vba

エクセルのマクロ(VBA)で処理の進捗状況を表示する。

プログレスバーのフォーム作成

フォームの追加

f:id:segmentation-fault:20170303233616p:plain


コントロールボックスにプログレスバーを追加

f:id:segmentation-fault:20170303233642p:plain

f:id:segmentation-fault:20170303233749p:plain

f:id:segmentation-fault:20170303233801p:plain


ラベル、ボタン、バーを追加してそれっぽく作成

f:id:segmentation-fault:20170303233846p:plain

ソースコード作成

UserFormに中断ボタン実行を判定するフラグを追加する。

UserForm

'中断ボタン実行フラグ
Public IsCancel As Boolean

Private Sub CommandButton1_Click()
  '中断ボタン実行でフラグをオン
  IsCancel = True

End Sub

Private Sub Label1_Click()

End Sub


Private Sub ProgressBar1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As stdole.OLE_XPOS_PIXELS, ByVal y As stdole.OLE_YPOS_PIXELS)


End Sub

Private Sub UserForm_Click()

End Sub

Moduleにプログレスバー表示処理を追加

Main Module

'Sleepを使うための定義
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If


Sub ProgressBar()
  
  Const MaxCount As Long = 100
  
  UserForm2.Show P_bar
  UserForm2.ProgressBar1.Min = 1
  UserForm2.ProgressBar1.Max = MaxCount
  
  UserForm2.IsCancel = False
  
  Dim index As Long
  Dim progress As Long
  For index = 1 To MaxCount
  
    Sleep (100)
    
    progress = CInt((index / MaxCount) * 100)
    UserForm2.Label1.Caption = index & "%完了"
    UserForm2.ProgressBar1.Value = index
  
    If UserForm2.IsCancel = True Then
      End
    End If
  
    DoEvents
    
  Next
  
  Unload UserForm2

End Sub

実行結果

f:id:segmentation-fault:20170303234347p:plain

socatで装置内通信のデータをのぞき見る

C/C+ Linux ネットワーク

socatを使ってUNIXドメイン通信を中継し通信内容をのぞいてみる。


構成のイメージは下記。

--------------------------------------------------
 ________      ________      ________
|        |    |        |    |        | 
| Client |--->| socat  |--->| Sever  | 
|________|    |________|    |________| 
                  |
                   ---> 標準出力に通信内容を表示。

--------------------------------------------------

プログラム

local.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>

#define MSGID_HELLO_REQUEST (0x0101)

#define MAX_USER (1)

typedef enum {
    MSG_KIND_REQUEST = 0,
    MSG_KIND_MAX
} msgkind_t;

typedef struct {
    uint32_t    id;
    uint16_t    kind;
    uint16_t    seqno;
} msg_header_t;


client.c

#include "local.h"

#define UNIX_SOCKET_FILEPATH "./usocket.client"

int main(void)
{
    int sfd = -1;
    struct sockaddr_un addr = {
        .sun_family = AF_UNIX,
        .sun_path   = UNIX_SOCKET_FILEPATH,
    };

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    int rc = connect(sfd, (struct sockaddr* )&addr, sizeof(addr));
    if (rc < 0) {
        perror("connect");
        close(sfd);
        exit(EXIT_FAILURE);
    }

    uint16_t    seqno = 0;
    while(1) {
        msg_header_t    req = {
            .id     = MSGID_HELLO_REQUEST,
            .kind   = MSG_KIND_REQUEST,
            .seqno  = seqno,
        };

        ssize_t ss = send(sfd, (void*)&req, sizeof(req), 0);
        if (ss < 0) {
            perror("send");
            close(sfd);
            break;
        }

        if (ss == 0 || ss < 0) {
            printf("connection closed.\n");
            unlink(UNIX_SOCKET_FILEPATH);
            break;
        }

        printf("sent request, wait 3 sec (-.-)zzZ\n");
        sleep(3);
        seqno++;
    }

    return 0;
}


server.c

#include "local.h"

#define UNIX_SOCKET_FILEPATH "./usocket.server"

int main(void)
{
    int sfd = -1;
    struct sockaddr_un addr = {
        .sun_family = AF_UNIX,
        .sun_path   = UNIX_SOCKET_FILEPATH,
    };

    sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sfd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    unlink(UNIX_SOCKET_FILEPATH);

    int rc = bind(sfd, (struct sockaddr* )&addr, sizeof(addr));
    if (rc < 0) {
        perror("bind");
        close(sfd);
        exit(EXIT_FAILURE);
    }

    rc = listen(sfd, MAX_USER);
    if (rc < 0) {
        perror("listen");
        close(sfd);
        exit(EXIT_FAILURE);
    }

    socklen_t   addrlen;
    struct sockaddr_un caddr;

    int acsfd = accept(sfd, (struct sockaddr *)&caddr, &addrlen);
    if (acsfd < 0) {
        perror("accept");
        close(sfd);
        exit(EXIT_FAILURE);
    }

    while(1) {
        uint16_t    seqno = 0;
        msg_header_t    req;

        ssize_t rs = recv(acsfd, (void*)&req, sizeof(req), 0);
        if (rs < 0) {
            perror("recv");
            close(sfd);
            break;
        }

        printf("recv size=%d, id=%#x, kind=%#x, seqno=%d\n",
               rs, req.id, req.kind, req.seqno);

        if (rs == 0) {
            printf("connection closed.\n");
            unlink(UNIX_SOCKET_FILEPATH);
            break;
        }
    }

    return 0;
}

実行結果

3つの端末を開き各端末で下記コマンドを実行。

$ sudo yum -y install socat
$ socat -x -v UNIX-LISTEN:./usocket.client, UNIX-CONNECT:./usocket.server
$ gcc -o server server.c
$ ./server
$ gcc -o client client.c
$ ./client


f:id:segmentation-fault:20170301224030p:plain



UNIXドメイン通信に対しtcpdumpライクなキャプチャができている。
単体テストとかで使えそう。

Ncursesでスクリーン制御

C/C+ Linux ncurses

Ncurses(*1)を使ってスクリーン制御してみる。

(*1)
CUIでスクリーン、キー入力、カーソルなどの制御機能を提供するライブラリのこと。
make menuconfig とか実行すると出てくるアレを実現できる。

ソースコード

sample.c

#include <curses.h>
#include <stdlib.h>

#define ESCAPE 27

typedef enum {
    COLOR_TYPE_INVALID = 0,
    COLOR_TYPE_BACK_GROUND = 1
} color_type_t;

void init_curses()
{
    initscr();
    start_color();
    init_pair(COLOR_TYPE_BACK_GROUND, COLOR_RED, COLOR_BLACK);
    curs_set(0);
    noecho();
    keypad(stdscr,TRUE);
}

int main()
{
    init_curses();

    bkgd(COLOR_PAIR(COLOR_TYPE_BACK_GROUND));
    move(2,1);
    printw("Press ESC key, you will exit.");
    refresh();

    int key;
    while(1) {
        int key = getch();
        if (key == ESCAPE) {
            break;
        }
        refresh();
    };

    endwin();

    return 0;
}

実行結果

$ gcc sample.c -o sample -lcurses
$ ./sample


f:id:segmentation-fault:20170228230644p:plain




Ncursesを使ってテトリスぐらいなら作れそう。