餅屋LGTM

餅つきのあとの静けさ

できごと

何でもないところでこけて後頭部を強く打った
その時はちょっと痛かっただけなのでそのままバイトに向かった

~20分後~

視界がぼやける、手がしびれるなどの症状が出る

~60分後~

言葉が出てこない、言われたことがすぐに理解できなくなる (具体的には「ライチとって」と言われて「ライチってなんでしたっけ」と聞き返すなどがあった)
大事を取って病院へ行くことにする (このとき大学の近くにあるはずの病院の場所も地図からうまく読み取れなかった *1 )

~2時間後~

頭痛と吐き気に襲われる
CTの結果は大したことはないらしいが、頭部打撲後の内出血は時間をかけて起きることもままあり注意が必要とのこと

~翌朝~

頭は少し痛い、あと首がめっちゃ痛いいわゆるむち打ちというやつ

まとめ

頭打つと想像以上に破滅する 思考も身体も
あと、病院代高くてピンチ

お見舞い品は365日受け付けております

amzn.asia

*1:単純に画面を読み取れなかったのと、内容を解釈できなかったのの両方が合わさってこの病院どこにあるんだ状態になっていた

Bash on Ubuntu on Windowsでまぁいい感じのターミナル

備忘録として

完成図

f:id:umaz1051:20170720165419g:plain
タスクバーから1発でgnome-terminalを起動できる。

なんでgnome-terminal

単純に使い慣れてるから。 Ctrl+Shift+vでペーストできたりCtrl+Shift+nで新しいウィンドウが開けたりといつもとほぼ同じショートカットが使える。
PowerShellもそんなに嫌いじゃないけどフォントがつらいので厳しい。

BoWとVcXsrvのインストー

以下がよくまとまっているので参考にやっていく。
qiita.com

gnome-terminalのインストールと日本語環境の設定

bash上で sudo apt-get install gnome-terminal uim uim-xim uim-anthy
7/22追記 日本語表示のためにフォント追加 sudo apt-get install fonts-ipafont
.bashrcに以下を追加

export LC_MESSAGES=ja_JP.UTF-8
export LC_IDENTIFICATION=ja_JP.UTF-8
export LC_COLLATE=ja_JP.UTF-8
export LANG=ja_JP.UTF-8
export LC_MEASUREMENT=ja_JP.UTF-8
export LC_CTYPE=ja_JP.UTF-8
export LC_TIME=ja_JP.UTF-8
export LC_NAME=ja_JP.UTF-8
#
export DISPLAY=localhost:0.0
export XIM=uim
export XMODIFIERS=@im=uim
export UIM_CANDWIN_PROG=uim-candwin-gtk
#export UIM_CANDWIN_PROG=uim-candwin-qt
export GTK_IM_MODULE=uim
export QT_IM_MODULE=uim
export NO_AT_BRIDGE=1

.uimを作成する

.uim

(define default-im-name 'anthy)
(define-key generic-on-key? '("Henkan_Mode" "zenkaku-hankaku" "<Control> " "<Control>\\"))
(define-key generic-off-key? '("Muhenkan" "zenkaku-hankaku" "<Control> " "<Control>\\"))
(define-key anthy-extend-segment-key? '("<Control>o"))
(define-key anthy-shrink-segment-key? '("<Control>i"))

wsl-terminalのインストー

タスクバーからgnome-terminalを起動するためにwsl-terminalをインストールする。
github.com
ここから最新のバージョンをダウンロードし、任意の場所に展開する。
7/22追記 最新版だとうまく動かないのでv0.6.9をダウンロード
open-wsl.exeを起動すると、端末が開くが、カレントディレクトリが展開した場所になってしまうので、/home/usernameがカレントディレクトリになるようopen-wsl.exeのショートカットを作成して、オプションとして-lを付与する。
f:id:umaz1051:20170720191439p:plain
ショートカットをタスクバーに設置すればタスクバーから端末が開く。

gnome-terminalが立ち上がるようにする

wsl-terminalを起動したときシェルの深度が4なので、これを利用してgnome-terminalを立ち上げる。ついでにwsl-terminalは邪魔なので閉じる。
.basrcに以下を追加

if [ $SHLVL -eq 4 ]; then
    gnome-terminal
    exit
fi

このままだとexitでwsl-terminalを閉じたときにgnome-terminalも一緒に閉じるので、バックグラウンドで常にbashを走らせておく必要がある。
そこでbash.vbsを作成する

bash.vbs

Set ws = CreateObject("Wscript.Shell")
ws.run "bash", vbhide

スタートアップの登録

起動時にいちいちbash.vbsやVcXsrvを手動で起動するのは面倒なのでスタートアップに登録する。
f:id:umaz1051:20170720200755p:plain
参考
pc-karuma.net

補足

C:\Users\usernameかC:\Users\username\hogeシンボリックリンクを貼っとくといい
ln -s /mnt/c/Users/username/hoge
7/22追記 ubuntuのバージョンが古い場合うまく動かないようなのでそのときは sudo do-release-upgrade

【就職活動】

大学4年生になって周りの人たちが就活をしていてただ漠然と就活しなきゃなぁなんて思ってみたり、
研究室の同期は大体が大学院進学希望で大学院の先輩も特に就活はしなかったと言っているのを聞いて自分もやらなくていいかぁなんて思ってみたり、
自分のことなのにどこか他人事で明確な意志もなく、友人にもお前は結局院進するのか就職するのかわからないどっちなんだと言われ、それに対して雰囲気と気分で決めるなんて答えちゃう始末。

よくないなぁなんて思ってるんだけど本心だからしょうがない。 でもそろそろ本気で進路を決めないといけないので企業について調べてみたり説明会に行ってみたりしました。

で、実際それをやってみると業界の雰囲気だったり自分のやりたいこと、なりたいものだったりがわかってきて、第1志望と第2志望が決まりました。 それでこの前第2志望の選考に行ってきました。写真はその様子です。手応えとしてはいまいちだったけれども次は5月10日から始まる第1志望の7億円! 気合い入れていきたいと思います。

Rubyでオセロ 〜その4〜

オセロの機能としては最後 待ったの実装

0. ビット・マスクによる裏返し処理の修正

JAVAでオセロを作る本 を読んだところ裏返しの判定にはビット・マスクを利用するとよいとの事だったので実装しなおした 今までは配列に方向を保存して判別していたものをビット演算*1で判別できるようになる

#定数の変更
#ひっくり返せる方向
NONE = 0
UPPER_LEFT = 1
UPPER = 2
UPPER_RIGHT = 4
RIGHT = 8
LOWER_RIGHT = 16
LOWER = 32
LOWER_LEFT = 64
LEFT = 128
...

#ひっくり返せる方向の取得
def turnable_direction (col, row)
  direction = NONE
  #左上
  if @board[col-1][row-1] == -@stone_color #相手の色がある場合
    ...

    if @board[col-i][row-i] == @stone_color #相手の色に続くのが自分の色の場合
      direction |= UPPER_LEFT
    end
  end
  if @board[col-1][row] == -@stone_color #上
    ...

    if @board[col-i][row] == @stone_color
      direction |= UPPER
    end
  end
  if @board[col-1][row+1] == -@stone_color #右上
    ...

    if @board[col-i][row+i] == @stone_color
      direction |= UPPER_RIGHT
    end
  end
  if @board[col][row+1] == -@stone_color #右
    ...

    if @board[col][row+i] == @stone_color
      direction |= RIGHT
    end
  end
  if @board[col+1][row+1] == -@stone_color #右下
    ...

    if @board[col+i][row+i] == @stone_color
      direction |= LOWER_RIGHT
    end
  end
  if @board[col+1][row] == -@stone_color #下
    ...

    if @board[col+i][row] == @stone_color
      direction |= LOWER
    end
  end
  if @board[col+1][row-1] == -@stone_color #左下
    ...

    if @board[col+i][row-i] == @stone_color
      direction |= LOWER_LEFT
    end
  end
  if @board[col][row-1] == -@stone_color #左
    ...

    if @board[col][row-i] == @stone_color
      direction |= LEFT
    end
  end
  return direction
end

#ひっくり返せるマスの一覧を取得
def get_turnable_cells
  turnable_cells = []
  @board.each_with_index do |col, i|
    col.each_with_index do |row, j|
      if row == EMPTY #空きマス
        turnable_direction = turnable_direction (i,j)
    #ここを変更
        if turnable_direction != NONE #ひっくり返せる方向が存在する=石を置けるマス
          turnable_cells.push([i,j]) #座標を格納
        end
      end
    end
  end
  return turnable_cells
end

#石をひっくり返す
def reverse_stone(col, row) #石をおいた位置
  turn_direction = turnable_direction (col, row) #返せる方向を取得
  if turn_direction & UPPER_LEFT != 0
    ...

  end
  if turn_direction & UPPER != 0
    ...

  end
  if turn_direction & UPPER_RIGHT != 0
    ...

  end
  if turn_direction & RIGHT != 0
    ...

  end
  if turn_direction & LOWER_RIGHT != 0
    ...

  end
  if turn_direction & LOWER != 0
    ...

  end
  if turn_direction & LOWER_LEFT != 0
    ...

  end
  if turn_direction & LEFT != 0
    ...

  end
end

1. 実装の方針その1〜盤の状態の保存方法〜

考えたのは3通り

  1. 全部の盤の様子を保存する
  2. 裏返した石の座標を保存する
  3. 裏返した方向と枚数を保存する

1は無駄が多すぎるのでなし、3はひっくり返すメソッドを再利用できないのでなしにして、2の方針でいくことにした。

2. 実装の方針その2〜パスの処理〜

特に何もない展開なら今までと逆にターン数を1戻して石の色を反対にするだけで待ったの実装は完了するはずだけれども、実際にはパスをして2ターン以上連続で同じ色の石が置かれる場合がある。そのときに律儀に色を反転させているとめちゃくちゃになってしまうのでパスの処理をうまく考えてやる必要がある

で考えたのは

  1. パスだったことを記録する
  2. 置いた石の色を記録する

1の方法では実際のターン数との乖離をなくす方法が楽じゃなさそうだったので2でいくことに

3. 座標の保存

裏返した石の座標とその色は棋譜を保存する配列に一緒に入れることにした
1手戻したあとに別の手を打つこともあるので棋譜の保存は配列にpushするのではなくターン番目の要素に追加するようにした

  1. 石を置いた時にその座標と石の色を保存する
  2. 石を返した時にその座標を保存し返し終わったらまとめて棋譜と同じ配列に保存する
...

def put_stone(cell, move)
  ...

  @record[@turn] = [move, @stone_color]
  ...

end

def reverse_stone(col, row) #石をおいた位置
  turn_direction = turnable_direction(col, row) #返せる方向を取得
  turned_cells = [] #返す方向と返した枚数
  if turn_direction & UPPER_LEFT != 0
    i = 1
    while @board[col-i][row-i] == -@stone_color #相手の色が続くまで
      @board[col-i][row-i] = @stone_color
      turned_cells.push([col-i,row-i]) #返した石の座標を保存
      i += 1
    end
  end
  if turn_direction & UPPER != 0
    i = 1
    while @board[col-i][row] == -@stone_color
      @board[col-i][row] = @stone_color
      turned_cells.push([col-i,row])
      i += 1
    end
  end
  if turn_direction & UPPER_RIGHT != 0
    i = 1
    while @board[col-i][row+i] == -@stone_color
      @board[col-i][row+i] = @stone_color
      turned_cells.push([col-i,row+i])
      i += 1
    end
  end
  if turn_direction & RIGHT != 0
    i = 1
    while @board[col][row+i] == -@stone_color
      @board[col][row+i] = @stone_color
      turned_cells.push([col,row+i])
      i += 1
    end
  end
  if turn_direction & LOWER_RIGHT != 0
    i = 1
    while @board[col+i][row+i] == -@stone_color
      @board[col+i][row+i] = @stone_color
      turned_cells.push([col+i,row+i])
      i += 1
    end
  end
  if turn_direction & LOWER != 0
    i = 1
    while @board[col+i][row] == -@stone_color
      @board[col+i][row] = @stone_color
      turned_cells.push([col+i,row])
      i += 1
    end
  end
  if turn_direction & LOWER_LEFT != 0
    i = 1
    while @board[col+i][row-i] == -@stone_color
      @board[col+i][row-i] = @stone_color
        turned_cells.push([col+i,row-i])
      i += 1
    end
  end
  if turn_direction & LEFT != 0
    i = 1
    while @board[col][row-i] == -@stone_color
      @board[col][row-i] = @stone_color
      turned_cells.push([col,row-i])
      i += 1
    end
  end
  @record[@turn].push(turned_cells) #棋譜とともに保存
end

4. 待ったの実装

棋譜を保存している配列@recordの中は

[[指し手, 石の色, [返した石の座標1, 2, 3]], [..], ...]

のようになっているこれを使って待ったを作る

  1. 初手以外のとき(初手の待ったは変化しない)
  2. 棋譜の配列から指し手の座標を取得する
  3. その座標のマスを空きマスにする
  4. 棋譜の配列から石の色を取得する
  5. 棋譜の配列から返した石の座標を取得し、そのマスを取得した色と反対の色にする
  6. 現在の色を取得した色にする
#待った
def undo
  if @turn != 0 #1ターン目でない時
    @pass_count = 0
    @turn -= 1
    cell = cordinate_transformation(@record[@turn][0])
    @board[cell[0]][cell[1]] = EMPTY
    @stone_color = -@record[@turn][1]
    @record[@turn][2].each do |cell|
      @board[cell[0]][cell[1]] = @stone_color
    end
    @stone_color = -@stone_color
  end
end

完成

ここから変更したこと

  1. 60手になったら終了をなくし2連続でパスしたら終了のみに
  2. start_gameメソッドのwhile文の部分をphaseメソッドに移動
  3. start_gameメソッドのwhile文の後の部分をend_gameメソッドに
  4. ゲームの進行をループではなく再帰
  5. パスになった時に次も確認しパスならend_gameメソッドを呼び出す

gist.github.com

とりあえずこれで基本機能は完成オブジェクト指向っぽく直していく

*1:参考qiita.com

Rubyでオセロ 〜その3〜

棋譜の読み込みまで

棋譜については作るひつようもあまりないかなとは思ったのだけれども打てる場所がなくなって終わる試合などの棋譜を残せば後で変更を加えたときのデバッグが楽になるだろうと思って作ることにした

1. 棋譜の形式を考える

例えば エラー - OWiki のページの棋譜

e6f4c3c4d3d6e3c2b3d2 f3c5b4f7b6c6b5f2e7f5e2f6c7e8d1a4a5a6d7a3g3h3b2a1g6c8d8f8g4f1e1b1g1h4g5h5h6h7g7c1g2h8g8h1h2a7b7a2a8b8
e6f4c3c4d3d6e3c2b3d2f3b4f5e2e1f1g1f2g3e7 b1a3c5b5a6g4f6h3f7c6c7g6g5d7h6b6e8c8h5h4h2g8f8d8a5d1c1a4a2h7h8g7b8b7a7a8g2h1a1b2

のように一行にまとめられていて複数記載されていたりするが人間が読むこともあるかもしれないので

c4
c3
f5
b4
b3
...

のような形にする

2. 棋譜を保存する

1. 配列に指し手を保存する
  1. 棋譜を保存する配列の作成
  2. put_stoneメソッドに引数moveを追加
  3. human,comそれぞれからput_stoneを呼び出すときに指す座標を引数として与える
...

def start_game
  ...
  @record = [] #棋譜を保存する配列
  ...
end

def put_stone(cell, move) #引数にmoveを追加
  ...

  @record.push(move)

  ...

end
2. ゲーム終了時にタイムスタンプを取得しその名前で棋譜を保存する
  1. 棋譜を保存するか聞く
  2. 保存する場合recordディレクトリが存在するか確認し存在しなければ作る
  3. yyyyMMddHHmm.recordでファイルを作成し、@recordの中身を書き込む
#ゲームの進行
require "date"
require "fileutils"

...

def start_game

  ...

  save_record
end

#棋譜の保存
def save_record
  print("棋譜を保存しますか?(y/n)\n")
  ans = gets.chomp!
  if ans =~ /(y|n)/
    if ans == "y"
      #recordディレクトリがない場合作成する
      FileUtils.mkdir_p("record") unless FileTest.exist?("record")
      #現在時刻の取得
      time = DateTime.now.strftime('%Y%m%d%H%M')
      File.open("record/#{time}.record", "w") do |f|
        @record.each do |rec|
          f.puts(rec)
        end
      end
      print("#{time}.record で保存しました\n\n")
    end
  else
    print("yかnを入力してください\n")
    save_record
  end
end

3. 棋譜の読み込み

1. 読み込みモードの作成
  1. 読み込みモードを追加する
  2. 棋譜の一覧を表示する
  3. 選択された棋譜を読み込み配列に保存する
...

RECORD = 4
...

def menu
  while true
    ...
    if mode =~ /[1-4]/
      @mode = mode.to_i
      case @mode
      when COM
        ...
      when RECORD
        dir = Dir.glob("record/*.record") #棋譜の一覧の取得
        if dir.size == 0
          print("棋譜が存在しません\n\n")
          menu
        else
          print("棋譜一覧\n")
          dir.sort!
          dir.each_with_index do |name, i|
            print("#{i+1}: #{name}\n")
          end
          print("棋譜ファイル番号を入力してください:")
          num = gets.chomp!.to_i - 1
          file = dir[num]
          @read_record = [] #読み込んだ棋譜を保存する配列
          File.open(file) do |f|
            f.each_line do |line|
              @read_record.push(line)
            end
          end
        end
      end
      start_game
    else
      ...
    end
  end
end
2. 棋譜の再生
  1. 手番の棋譜を読み込む
  2. 石を打つ
  3. 読み込みモードの時は棋譜の保存をしない

手の表現のされ方は

  1. 人の指し手 = rowcol(a1~h8)
  2. comの指し手 = colrow(11~88)
  3. 棋譜 = rowcol(a1~h8)

put_stoneメソッドが受けつける表現は
`cell = [col, row]
1と3が同じ変換なのでメソッドに分割する

#ゲームの進行
def start_game
  ...
 
  if @mode != RECORD
    save_record
  end
end

def phase
  ...

  if turnable_cells.size == 0
    ...

  else
    ...

    case @mode
    when COM #COM戦の場合
      ...

    when HUMAN #対人戦の場合
      ...

    when WATCH #観戦の場合
      ...

    when RECORD #棋譜再生の場合
      read_record(@read_record[@turn])
    end
  end
end

def human(turnable_cells) #人が石を置く操作
  ...

  if move =~ /[a-h][1-8]/
    cell = cordinate_transformation(move) #座標の変換
    ...

  else
    ...

  end
end

def read_record(move) #棋譜の場合
  print(move)
  cell = cordinate_transformation(move)
  put_stone(cell, move)
end

#座標の変換
def cordinate_transformation(move)
  cell = move.split("")
  col = COL_NUM[cell[1]]
  row = ROW_NUM[cell[0]]
  cell = [col, row]
  return cell
end