YaneuraOuさんの将棋ソフトのUbuntuへのインストール(2020/7 バージョン)

YaneuraOuさんの将棋ソフトのUbuntuへのインストール(2020/7 バージョン)

目次

1 概要

  • ここ数年YaneuraOuさんの将棋ライブラリを利用した将棋ソフトがコンピューター将棋大会で優勝
  • C++とアセンブラベース
  • Stockfishというチェスソフトをかなり取り込んだ作りになってるらしい
  • GitHubにてソース公開されている
  • バージョンによって使い方が相当変化している
    • 昔のバージョンに戻せば、過去の動画の使い方も出来る(今は同じ方法で同じように使えない)
    • スレッド等他のライブラリとの依存関係があり、使う難易度が高い

2 リンク

3 エンジン部分のインストール

3.1 Ubuntuでコンパイル

3.1.1 以下の操作を行っている動画





3.2 手順

3.2.1 依存パッケージのインストール

  • 色々あると思う、私は色々入れていたので、私の環境の場合以下を入れる必要があった
sudo apt install bash vim clang make lldb gdb git libc6-dev wget unar
sudo apt install libomp-dev libopenblas-dev
sudo apt install uci2wb xboard 

3.2.2 利用PCのCPUチェック

  • avx拡張命令の利用可能チェック
grep -i avx /proc/cpuinfo
  • sse拡張命令の利用可能チェック
grep -i sse /proc/cpuinfo

3.2.3 ソースゲット

git clone https://github.com/yaneurao/YaneuraOu.git

3.2.4 ソースバックアップ

tar cvzf YaneuraOu.org.tgz YaneuraOu

3.2.5 コンパイル(トーナメントタイプの場合)

  • CPUがSSE42タイプの場合(私のマシンのCPUはタイプが古くAVX2タイプをサポートしていないため)
  • AVX2タイプのCPU命令可能な場合はSSE42の部分をAVX2にすればOK
  • SSE42もダメな場合はNO_SSEや、OTHER、ZEN2というCPUタイプも選択可能
  • UbuntuなどLinuxの場合は/proc/cpuinfoで利用可能かどうか確認可能 ( grep -i sse4 /proc/cpuinfo, grep -i avx2 /proc/cpuinfo 等)
cd YaneuraOu/source 
make clean tournament TARGET_CPU=SSE42
  • これでコンパイルが実行され、YaneuraOu-by-gcc っていう実行可能なファイルが生成される(必要なライブラリやツールがインストールされていた場合、不足している場合はエラーメッセージから必要なパッケージをインストールしていく)
  • 取得してソースバックアップし、コンパイル後にコンパイル後のファイルも保存するスクリプトが以下
  • 現状はSSE42用(CPUタイプ)
    • それ以外のCPUタイプ希望の場合は他のものを有効にし(行頭の#をとる)、SSE42のところをコメントに(行頭に#をいれる)
#!/bin/bash
#TARGET_CPU=AVX512
#TARGET_CPU=AVX2
TARGET_CPU=SSE42
#TARGET_CPU=SSE41
#TARGET_CPU=SSE2
#TARGET_CPU=NO_SSE
#TARGET_CPU=OTHER
#TARGET_CPU=ZEN2
D=`date +%Y%m%d`
DT=`date +%Y%m%d_%H%M`
mkdir ${DT}
cd ${DT}
git clone https://github.com/yaneurao/YaneuraOu.git
tar cvzf YaneuraOu_${DT}.tgz YaneuraOu/
(cd YaneuraOu/source && make clean tournament TARGET_CPU=${TARGET_CPU}) 2>&1 | tee ./log001.txt
tar cvzf YaneuraOu_${DT}_build.tgz YaneuraOu/
(
mkdir LEARN
cd LEARN
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && make clean evallearn TARGET_CPU=${TARGET_CPU}) 2>&1 | tee ./log002.txt
)

3.2.6 コンパイル(学習タイプの場合、評価関数ファイルを生成できるタイプ)

  • CPUがSSE42タイプの場合(私のマシンのCPUはタイプが古くAVX2タイプをサポートしていないため)
  • AVX2タイプのCPU命令可能な場合はSSE42の部分をAVX2にすればOK
  • SSE42もダメな場合はNO_SSEや、OTHER、ZEN2というCPUタイプも選択可能
  • UbuntuなどLinuxの場合は/proc/cpuinfoで利用可能かどうか確認可能 ( grep -i sse4 /proc/cpuinfo, grep -i avx2 /proc/cpuinfo 等)
make clean evallearn TARGET_CPU=SSE42
  • 同じく YaneuraOu-by-gcc というファイルが生成される
  • コンパイルする前にLEARNディレクトリにソースを解凍してそこで行った
mkdir LEARN
cd LEARN
tar xvzf ../YaneuraOu.org.tgz
cd YaneuraOu/source 

3.3 ゼロの評価関数ファイルの生成

  • 学習タイプの YaneuraOu-by-gcc の起動
./YaneuraOu-by-gcc
  • YaneuraOu/docs/解説.txt にある文書の手順で行う
EvalDir xyz              // 存在しないフォルダを評価関数の読み込みフォルダに指定する
SkipLoadingEval true     // こうしておけば評価関数ファイルの読み込みに失敗してもエラーにならない
isready                  // このタイミングで評価関数が読み込まれるが存在しないフォルダから読み込むのでゼロクリアされた評価関数を読み込んだことになる。
EvalSaveDir eval_zero    // 保存フォルダ名を"eval_zero"に設定(何でも良い)
test evalsave            // メモリ上の評価関数を保存するコマンド
  • 停止
quit                     // 停止
  • これにより eval_zero/nn.bin に評価関数ファイル nn.binが生成される
  • nn.binを競技用YaneuraOu-by-gccのあるディレクトリのevalの中に入れる
cp -i eval_zero/nn.bin ../../../YaneuraOu/source/eval/

3.4 動作確認

  • 以下のコマンドで起動
./YaneuraOu-by-gcc
  • usiコマンドをいれて動作確認(usi,d等)
usi
isready
d
  • quitで停止
quit

3.5 評価関数の準備

  • いくつか有力なものある
  • どれかを選択し、解凍したnn.binを eval ディレクトリにいれる

3.6 KristallweizenさんのKristallweizen_kaiV0.4.zipの場合

wget https://github.com/Tama4649/Kristallweizen/raw/master/Kristallweizen_kaiV0.4.zip
unar Kristallweizen_kaiV0.4.zip

3.7 評価関数 orqha レーティング約4330の評価関数

wget https://www.qhapaq.org/static/media/bin/orqha.7z
unar orqha.7z

3.8 Elmo wcsc29バージョン

unar elmo_wcsc29_eval.zip

3.9 定跡の準備

3.10 YaneuraOuさんの定跡

wget https://github.com/yaneurao/YaneuraOu/releases/download/BOOK-700T-Shock/700T-shock-book.zip https://github.com/yaneurao/YaneuraOu/releases/download/v4.73_book/standard_book.zip https://github.com/yaneurao/YaneuraOu/releases/download/v4.73_book/yaneura_book1_V101.zip https://github.com/yaneurao/YaneuraOu/releases/download/v4.73_book/yaneura_book3.zip 
unar 700T-shock-book.zip 
unar standard_book.zip 
unar yaneura_book1_V101.zip 
unar yaneura_book3.zip 

3.11 解凍したものを book というディレクトリを作成していれる

3.12 起動用のスクリプトファイルを用意

3.13 YaneuraOu-by-gccの起動用スクリプトファイル作成

#!/bin/sh
cd `dirname $0`
./YaneuraOu-by-gcc

3.14 実行権限を与える

chmod +x 作成したスクリプトファイル名
  • 例 startYaneuraOu.shなら
chmod +x startYaneuraOu.sh

3.15 ファイルの再配置

  • YaneuraOu-by-gcc はトーナメント用の実行ファイルを利用
.
├── FEN
├── YaneuraOu-by-gcc
├── book
│   ├── standard_book.db
│   ├── yaneura_book1.db
│   └── yaneura_book3.db
├── eval
│   └── nn.bin
└── startYaneuraOu.sh

3.16 エンジンの動作確認

  • startYaneuraOu.shを起動した後に以下を入れる
  • isready に対して readyok が返ってきたらOK (評価関数や、定跡ファイルとしてどれが利用されているか確認すること)
usi
isready
quit

4 GUIの準備

5 xboardの場合

  • インストールが一番簡単
  • 見た目がイマイチ
xboard -fcp "uci2wb debug -s /opt/shogi/20200707/startYaneuraOu.sh" -scp "uci2wb debug -s  /opt/shogi/20200707/startYaneuraOu.sh" -variant shogi  -coords  -pid /usr/share/games/xboard/themes/shogi/ -highlightSquareColor  "#00FFFF" -clockMode true -tc 5 -mps 30 -showMoveTime true -positionDir /opt/shogi/20200707/FEN -useBoardTexture true -liteBackTextureFile /usr/share/games/xboard/themes/textures/wood_d.png -darkBackTextureFile /usr/share/games/xboard/themes/textures/wood_d.png

6 Android用のYaneuraOuをビルド

  • Android用のバイナリを作るためのファイルも配布物に同梱されているらしいことに気づいたので、コンパイルしてみました。
  • 前準備として、Andrido NDKをインストールする必要があります。https://youtu.be/3U5_330aySk

6.1 以下の操作を行っている動画


6.2 Android用のYaneuraOuをビルド する手順

6.2.1 最新バージョンをコンパイル(2021/01/19時点)

  • 頻繁に更新されるため、これ以下の方法では、今後のバージョンコンパイルできない可能性あり
  • gitのタグだと 9bbd0f38498b22e9f3e6cf9493a7f8849c02e496 のものは以下でコンパイル出来ている(通常モードは作成可だった。能詰将棋エンジンはコンパイル中にエラーになる)
  1. YaneuraOuのソースゲット
    git clone https://github.com/yaneurao/YaneuraOu.git
    
  2. ソースのバックアップ
    • 最初の命令はdateコマンドで日付と時間をバックアップファイル名にする方法
    • 後の方はYaneuraOu_000.tgz というファイル名でバックアップ。別の名前でバックアップとっておいてもよい
    • 別のツールでバックアップもOK
    • バックアップ取らない選択もあり
    tar cvzf YaneuraOu_`date +%Y%m%d_%H%M`.tgz YaneuraOu/
    とか
    tar cvzf YaneuraOu_000.tgz YaneuraOu/
    
  3. コンパイル
    • コンパイルできるディレクトリに移動YaneuraOu/jni/
    cd YaneuraOu/jni/
    
    • 以下は64bit用の設定。
    • TARGET_ARCH_ABI=armeabi-v7a とすれば32bit用を作成可能
    • 他のCPUのタイプも含めて全部コンパイルするには TARGET_ARCH_ABI=なんちゃら を省略すればOK
    ndk-build TARGET_ARCH_ABI=arm64-v8a
    
    • 詰将棋エンジンをコンパイルするには以下(ただし、このバージョンではエラー発生してビルド失敗する)
      • ENGINE_NAME=YaneuraOu_MATE_arm64-v8a をいれてないとコンパイルエラーになる
    ndk-build YANEURAOU_EDITION=MATE_ENGINE TARGET_ARCH_ABI=arm64-v8a ENGINE_NAME=YaneuraOu_MATE_arm64-v8a
    

6.2.2 リリースバージョンをコンパイル(version4.88)

  1. YaneuraOuのソースゲット
    • https://github.com/ai5/YaneuraOuの右のReleasehttps://github.com/ai5/YaneuraOu/releasesに「Android版 やねうら王」となってる最新のところからダウンロード。2019/1/19時点で最新はv4.88https://github.com/ai5/YaneuraOu/releases/tag/android_488。zip版でもtar.gz版でもOK。私はtar.gzバージョンをダウンロードした。
    • もっと新しいバージョンでてるなら、そちらを選択してください。2021/1/19時点では4.88が最新
    • こちらは詰将棋エンジンバージョンもコンパイルは成功する。ただし、詰将棋をAndroidでとかせようとすると、セグメーテーションエラー発生。通常バージョンは正常動作していた。
  2. Android版 やねうら王v4.88のソース解凍
    tar xvzf YaneuraOu-android_488.tar.gz
    
  3. Android版 やねうら王v4.88のコンパイル
    • arm64-v8a (64bitCPU用)の詰将棋エンジンを作成します。
    cd YaneuraOu-android_488/jni/
    ndk-build ENGINE_TARGET=MATE_ENGINE TARGET_ARCH_ABI=arm64-v8a
    
    • ../libs/arm64-v8a/YaneuraOu-mate-arm64-v8a が作成されます。
      • ただ私がUmidigi F1Playで動作確認したところ、go mate infiniteするとセグメンテーションエラーで落ちてしまい、詰将棋とけませんでした。
      • エンジンオプションでなんとかならないか色々試しました(Hash減らすとか)が上手く動作せず
      • デバッガーオプションつけて、デバッガーでそのうち確認してみようと思ってますが。まだやってません。
    • arm64-v8a (64bitCPU用)の通常バージョンを作成します。
    ndk-build TARGET_ARCH_ABI=arm64-v8a
    
    • ../libs/arm64-v8a/YaneuraOu-nnue-halfkp256-arm64-v8aが作成されます。
      • こちらは上手く動作しました。Umidigi F1Playで。評価関数と、定跡ファイルをいれれば

6.3 この章のまとめ

  • Android用のバイナリをクロスコンパイルしてみた。
  • 通常の将棋エンジンは、上手くコンパイル実行できていました。また動作確認結果も良好。
  • 詰将棋エンジンは、最新のソースでは上手くコンパイルできず、リリースバージョンでも、コンパイルは出来るものの、詰将棋をとかせる命令(go mate infinite等))を入れるとセグメンテーションエラーが発生

7 Android用のYaneuraOuをビルド2(2021/05/17)

  • 前からノーマル将棋エンジンはクロスコンパイルに成功していた
  • 詰将棋エンジンはv4.88はコンパイルには成功するものの、動かすとセグメンテーションエラーで動かなかった
  • 詰将棋エンジンは最新バージョンでコンパイルに成功しなかった。(色々エラー出て)
  • 久しぶりにGitHubから最新ソースをゲットして、クロスコンパイルを環境変数の設定色々変更してやってみたら、上手くいった

7.1 以下の操作を行っている動画


7.2 Android用のYaneuraOuをビルド2(2021/05/17)を行う手順

  • 前準備として、Andrido NDKをインストールする必要があります。https://youtu.be/3U5_330aySk
  • sdkmanager –list_installed で確認したインストール済みのAndroid SDK NDK関係は以下の通り
    • コンパイルに利用したndkはndk-bundleを利用した
Installed packages:=====================] 100% Fetch remote repository...       
  Path                   | Version      | Description                             | Location               
  -------                | -------      | -------                                 | -------                
  build-tools;24.0.3     | 24.0.3       | Android SDK Build-Tools 24.0.3          | build-tools/24.0.3/    
  build-tools;29.0.2     | 29.0.2       | Android SDK Build-Tools 29.0.2          | build-tools/29.0.2/    
  build-tools;30.0.2     | 30.0.2       | Android SDK Build-Tools 30.0.2          | build-tools/30.0.2/    
  build-tools;30.0.3     | 30.0.3       | Android SDK Build-Tools 30.0.3          | build-tools/30.0.3/    
  build-tools;31.0.0-rc2 | 31.0.0 rc2   | Android SDK Build-Tools 31-rc2          | build-tools/31.0.0-rc2/
  cmake;3.10.2.4988404   | 3.10.2       | CMake 3.10.2.4988404                    | cmake/3.10.2.4988404/  
  cmake;3.6.4111459      | 3.6.4111459  | CMake 3.6.4111459                       | cmake/3.6.4111459/     
  cmdline-tools;latest   | 4.0          | Android SDK Command-line Tools (latest) | cmdline-tools/latest/  
  emulator               | 30.6.5       | Android Emulator                        | emulator/              
  ndk-bundle             | 22.1.7171670 | NDK                                     | ndk-bundle/            
  ndk;19.2.5345600       | 19.2.5345600 | NDK (Side by side) 19.2.5345600         | ndk/19.2.5345600/      
  patcher;v4             | 1            | SDK Patch Applier v4                    | patcher/v4/            
  platform-tools         | 31.0.2       | Android SDK Platform-Tools              | platform-tools/        
  platforms;android-27   | 3            | Android SDK Platform 27                 | platforms/android-27/  
  platforms;android-29   | 5            | Android SDK Platform 29                 | platforms/android-29/  
  platforms;android-30   | 3            | Android SDK Platform 30                 | platforms/android-30/  
  • 頻繁に更新されるため、これ以下の方法では、今後のバージョンコンパイルできない可能性あり
  • gitのタグだと a866bafb71aae5833be3d34c1227564c6ccb323b のものは以下でコンパイル出来ている。
    • YaneuraOuさんのソースの更新頻度高く、新しいバージョンで同じ手順で成功しなくなるかも。その時は上の git の id に git checkout a866bafb71aae5833be3d34c1227564c6ccb323b で戻して、そこで同じ手順でやれば上手くいくはず
  • 動画では、Docker Image( https://youtu.be/473GGAkxqy8に作成方法ある)を使ってコンパイルしています。
  1. YaneuraOuのソースゲット
    git clone https://github.com/yaneurao/YaneuraOu.git
    
  2. ソースのバックアップ
    • 最初の命令はdateコマンドで日付と時間をバックアップファイル名にする方法
    • 後の方はYaneuraOu_000.tgz というファイル名でバックアップ。別の名前でバックアップとっておいてもよい
    • 別のツールでバックアップもOK
    • バックアップ取らない選択もあり
    tar cvzf YaneuraOu_`date +%Y%m%d_%H%M`.tgz YaneuraOu/
    とか
    tar cvzf YaneuraOu_000.tgz YaneuraOu/
    
  3. コンパイル
    • コンパイルできるディレクトリに移動YaneuraOu/jni/
      • 備考 YaneuraOu/jni/ でなく YaneuraOu/ ディレクトリでもコンパイルできた 
    cd YaneuraOu/jni/
    
    • 以下は64bit用の設定。
      • TARGET_ARCH_ABI=armeabi-v7a とすれば32bit用を作成可能
      • 他のCPUのタイプも含めて全部コンパイルするには TARGET_ARCH_ABI=なんちゃら を省略すればOK
      • 実行ファイルのバックアップと、転送の手順は省略している
      • この実行ファイルの動作確認には、評価関数ファイルが必要
      • 定跡ファイルもあった方が良い
    ndk-build TARGET_ARCH_ABI=arm64-v8a clean #掃除
    ndk-build TARGET_ARCH_ABI=arm64-v8a
    mkdir -p arm64-v8a/ #バックアップ用のディレクトリ作成
    mv ../libs/arm64-v8a/YaneuraOu_NNUE_arm64-v8a arm64-v8a/ # 消さないようにビルドしたバイナリを移動
    
  4. tanuki詰将棋エンジンコンパイル
    • 詰将棋エンジンをコンパイルするには以下
      • ENGINE_NAME に設定必要
      • YANEURAOU_EDITION は MATE_ENGINE だとリンク時にエラー発生
      • YANEURAOU_EDITION は TANUKI_MATE_ENGINE か YANEURAOU_ENGINE_MATERIAL なら ビルド可能
    • YANEURAOU_EDITION=TANUKI_MATE_ENGINE と設定するとtanuki詰将棋エンジンビルド
    ndk-build YANEURAOU_EDITION=TANUKI_MATE_ENGINE TARGET_ARCH_ABI=arm64-v8a ENGINE_NAME=Tanuki_MATE_arm64-v8a  clean # 最初にファイルクリア
    ndk-build YANEURAOU_EDITION=TANUKI_MATE_ENGINE TARGET_ARCH_ABI=arm64-v8a ENGINE_NAME=Tanuki_MATE_arm64-v8a  2>&1 | tee log_tanukimate001.txt # ビルド
    mkdir -p arm64-v8a/
    mv ../libs/arm64-v8a/Tanuki_MATE_arm64-v8a_arm64-v8a arm64-v8a/  # 消さないようにビルドしたバイナリを移動
    
  5. YaneuraOu詰将棋エンジンコンパイル
    • YANEURAOU_EDITION=YANEURAOU_ENGINE_MATERIALと設定するとYaneuraOu詰将棋エンジンビルド
    ndk-build YANEURAOU_EDITION=YANEURAOU_ENGINE_MATERIAL TARGET_ARCH_ABI=arm64-v8a ENGINE_NAME=YaneuraOu_MATE_arm64-v8a clean #  最初にファイルクリア
    ndk-build YANEURAOU_EDITION=YANEURAOU_ENGINE_MATERIAL TARGET_ARCH_ABI=arm64-v8a ENGINE_NAME=YaneuraOu_MATE_arm64-v8a 2>&1 | tee log_yanemate001.txt # ビルド
    mkdir -p arm64-v8a/
    mv ../libs/arm64-v8a/YaneuraOu_MATE_arm64-v8a_arm64-v8a  arm64-v8a/ # 消さないようにビルドしたバイナリを移動
    

7.3 動作確認

7.3.1 ビルドしたファイル転送

  • 動作確認するAndroid端末とUSB接続してから以下を実行
adb push arm64-v8a/* /data/local/tmp
# or
# adb push ./arm64-v8a/YaneuraOu_NNUE_arm64-v8a ./arm64-v8a/Tanuki_MATE_arm64-v8a_arm64-v8a ./arm64-v8a/YaneuraOu_MATE_arm64-v8a_arm64-v8a /data/local/tmp

7.3.2 実行

  1. tanuki詰将棋エンジンの実行
    adb shell /data/local/tmp/Tanuki_MATE_arm64-v8a_arm64-v8a 
    
  2. YaneuraOu詰将棋エンジンの実行
    adb shell /data/local/tmp/YaneuraOu_MATE_arm64-v8a_arm64-v8a 
    
  3. USIコマンド
    • 最初はこれをいれて、エンター
    usi
    
    • 次にこれをいれて、エンター
    isready
    
    • テスト用の盤面設定
    position lnsgkgsnl/1r5b1/ppp1+Ppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b N 1
    
    • 盤面確認(YaneuraOuさんソフト用のUSI拡張コマンド)
    d
    
    • 詰将棋解く (制限時間60秒 秒はmsec単位で与える。無制限の場合は infinite)
    go mate 60000
    
    • 終了
    quit
    

7.4 この章のまとめ

  • Android用のバイナリをクロスコンパイルしてみた。
  • 昔ダメだった、詰将棋エンジンのコンパイルと動作に成功した。(ダメだったのは、コンパイルオプションがまずかったのか、他の原因なのか調べてない)
    • コンパイル時の環境変数の設定を変更したら、最新版のソースで上手くいった
    • リリースバージョンのv4.88では詰将棋エンジン関係は未確認

8 今後

  • 今後も文書追加していきます。

9 この文書のチェンジログ

  • 2020/07/07 初版
  • 2021/01/19 Android用のYaneuraOuをビルド の章追加
  • 2021/05/17 Android用のYaneuraOuをビルド2 の章追加(最新バージョンのソースで、詰将棋エンジンのコンパイルと動作に成功)

著者: NM Max

Created: 2021-05-19 水 06:52

Validate

YaneuraOuさんの将棋ライブラリで楽しむ(2020バージョン)

YaneuraOuさんの将棋ライブラリで楽しむ(2020/7バージョン)

目次

1 概要

  • ここ数年YaneuraOuさんの将棋ライブラリを利用した将棋ソフトがコンピューター将棋大会で優勝
  • C++とアセンブラベース
  • Stockfishというチェスソフトをかなり取り込んだ作りになってるらしい
  • GitHubにてソース公開されている
  • バージョンによって使い方が相当変化している
    • 昔のバージョンに戻せば、過去の動画の使い方も出来る(今は同じ方法で同じように使えない)
    • スレッド等他のライブラリとの依存関係があり、使う難易度が高い
  • YaneuraOuさんの将棋ソフトのUbuntuへのインストール(2020/7 バージョン) という別文書とリンク部分とインストール部分はほぼ同じ

2 リンク

3 Ubuntuでコンパイル

3.1 以下の操作を行っている動画





3.2 easyAIのインストール 手順

3.3 手順

3.3.1 依存パッケージのインストール

  • 色々あると思う、私は色々入れていたので、私の環境の場合以下を入れる必要があった
sudo apt install libomp-dev libopenblas-dev

3.3.2 ソースゲット

git clone https://github.com/yaneurao/YaneuraOu.git

3.3.3 ソースバックアップ

tar cvzf YaneuraOu.org.tgz YaneuraOu

3.3.4 コンパイル(トーナメントタイプの場合)

  • CPUがSSE42タイプの場合(私のマシンのCPUはタイプが古くAVX2タイプをサポートしていないため)
  • AVX2タイプのCPU命令可能な場合はSSE42の部分をAVX2にすればOK
  • SSE42もダメな場合はNO_SSEや、OTHER、ZEN2というCPUタイプも選択可能
  • UbuntuなどLinuxの場合は/proc/cpuinfoで利用可能かどうか確認可能 ( grep -i sse4 /proc/cpuinfo, grep -i avx2 /proc/cpuinfo 等)
cd YaneuraOu/source 
make clean tournament TARGET_CPU=SSE42
  • これでコンパイルが実行され、YaneuraOu-by-gcc っていう実行可能なファイルが生成される(必要なライブラリやツールがインストールされていた場合、不足している場合はエラーメッセージから必要なパッケージをインストールしていく)
  • 取得してソースバックアップし、コンパイル後にコンパイル後のファイルも保存するスクリプトが以下
#!/bin/bash
#TARGET_CPU=AVX512
#TARGET_CPU=AVX2
TARGET_CPU=SSE42
#TARGET_CPU=SSE41
#TARGET_CPU=SSE2
#TARGET_CPU=NO_SSE
#TARGET_CPU=OTHER
#TARGET_CPU=ZEN2
D=`date +%Y%m%d`
DT=`date +%Y%m%d_%H%M`
mkdir ${DT}
cd ${DT}
git clone https://github.com/yaneurao/YaneuraOu.git
tar cvzf YaneuraOu_${DT}.tgz YaneuraOu/
(cd YaneuraOu/source && make clean tournament TARGET_CPU=${TARGET_CPU}) 2>&1 | tee ./log001.txt
tar cvzf YaneuraOu_${DT}_build.tgz YaneuraOu/
(
mkdir LEARN
cd LEARN
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && make clean evallearn TARGET_CPU=${TARGET_CPU}) 2>&1 | tee ./log002.txt
)

3.3.5 コンパイル(学習タイプの場合、評価関数ファイルを生成できるタイプ)

  • CPUがSSE42タイプの場合(私のマシンのCPUはタイプが古くAVX2タイプをサポートしていないため)
  • AVX2タイプのCPU命令可能な場合はSSE42の部分をAVX2にすればOK
  • SSE42もダメな場合はNO_SSEや、OTHER、ZEN2というCPUタイプも選択可能
  • UbuntuなどLinuxの場合は/proc/cpuinfoで利用可能かどうか確認可能 ( grep -i sse4 /proc/cpuinfo, grep -i avx2 /proc/cpuinfo 等)
make clean evallearn TARGET_CPU=SSE42
  • 同じく YaneuraOu-by-gcc というファイルが生成される
  • コンパイルする前にLEARNディレクトリにソースを解凍してそこで行った
mkdir LEARN
cd LEARN
tar xvzf ../YaneuraOu.org.tgz
cd YaneuraOu/source 

3.4 ゼロの評価関数ファイルの生成

3.4.1 以下の操作を行っている動画


3.4.2 手順

  • 学習タイプの YaneuraOu-by-gcc の起動
./YaneuraOu-by-gcc
  • YaneuraOu/docs/解説.txt にある文書の手順で行う
EvalDir xyz              // 存在しないフォルダを評価関数の読み込みフォルダに指定する
SkipLoadingEval true     // こうしておけば評価関数ファイルの読み込みに失敗してもエラーにならない
isready                  // このタイミングで評価関数が読み込まれるが存在しないフォルダから読み込むのでゼロクリアされた評価関数を読み込んだことになる。
EvalSaveDir eval_zero    // 保存フォルダ名を"eval_zero"に設定(何でも良い)
test evalsave            // メモリ上の評価関数を保存するコマンド
  • これにより eval_zero/nn.bin に評価関数ファイル nn.binが生成される
  • nn.binを競技用YaneuraOu-by-gccのあるディレクトリのevalの中に入れる
cp -i eval_zero/nn.bin ../../../YaneuraOu/source/eval/

3.5 動作確認

  • 以下のコマンドで起動
./YaneuraOu-by-gcc
  • usiコマンドをいれて動作確認(usi,d等)
usi
isready
d
  • quitで停止
quit

4 下準備

4.1 以下の操作を行っている動画


4.2 Makefileの修正

  • YaneuraOu/sourceディレクトリで以下の作業を行う

4.2.1 Makefile の バックアップ

cp Makefile Makefile.org

4.2.2 myMain.cpp の 作成

cp main.cpp myMain.cpp

4.3 Makefileの修正

4.3.1 Makefile 修正内容

  • CPUタイプの修正、(各自該当のCPUに変更、私のPCのCPUはSSE42タイプ)
  • デバッグ機能をオン, デバッグ情報追加
  • libYaneuraOu-by-gcc.so という動的ライブラリファイル作成、動的ライブラリにするため、コンパイル時に -fPICオプション追加
  • 独自のmain関数用のmyMain.cppを追加し、これをメイン関数とした myMainを作成、myMainを更新成功したら、myMainを実行

4.3.2 Makefileを修正し、以下のコマンドで、patchファイルを作成した

diff -c Makefile.org Makefile > Makefile.diff
  • CPU SSE42タイプの場合のMakefileが以下
# ビルドターゲット
# normal     : 通常使用用
# evallearn  : 教師局面からの学習用
# tournament : 大会で使う用
# gensfen    : 教師生成用(現状、非公開)


# やねうら王の使いたいエディションを指定する
# YANEURAOU_ENGINE_NNUE       : NNUE型評価関数(halfKP256),標準NNUE型
# YANEURAOU_ENGINE_NNUE_KP256 : NNUE型評価関数(KP256)
# YANEURAOU_ENGINE_KPPT       : KPPT型評価関数
# YANEURAOU_ENGINE_KPP_KKPT   : KPP_KKPT型評価関数
# YANEURAOU_ENGINE_MATERIAL   : 駒得のみの評価関数
# MATE_ENGINE                 : tanuki- 詰将棋エンジン
# USER_ENGINE                 : USER定義エンジン

YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE
#YANEURAOU_EDITION = YANEURAOU_ENGINE_NNUE_KP256
#YANEURAOU_EDITION = YANEURAOU_ENGINE_KPPT
#YANEURAOU_EDITION = YANEURAOU_ENGINE_KPP_KKPT
#YANEURAOU_EDITION = YANEURAOU_ENGINE_MATERIAL
#YANEURAOU_EDITION = MATE_ENGINE
#YANEURAOU_EDITION = USER_ENGINE


# ターゲットCPU
# 利用できるCPU拡張命令を指定する。
# ARM系ならOTHERを指定する。
# 32bit環境用はNO_SSE
# AMDのZen2はZEN2を選択すると良いかも?(clang9以降で対応)

#TARGET_CPU = AVX512
#TARGET_CPU = AVX2
TARGET_CPU = SSE42
#TARGET_CPU = SSE41
#TARGET_CPU = SSE2
#TARGET_CPU = NO_SSE
#TARGET_CPU = OTHER
#TARGET_CPU = ZEN2


# デバッガーを使用するか
#DEBUG = OFF
DEBUG = ON


# clangでコンパイルしたほうがgccより数%速いっぽい。
#COMPILER = g++
COMPILER = clang++


# 標準的なコンパイルオプション
CFLAGS   = -std=c++17 -fno-exceptions -fno-rtti -Wextra -Ofast -MMD -MP -fpermissive
WCFLAGS  =
LDFLAGS  =
LIBS     =
INCLUDE  = # -I../include

# デバッガーを使わないなら、NDEBUGをdefineする。
ifeq ($(DEBUG),OFF)
        CFLAGS += -DNDEBUG
endif

# clang用にCFLAGSなどを変更
ifeq ($(findstring clang++,$(COMPILER)),clang++)
        # stdlib
        CFLAGS += -stdlib=libstdc++

        # C++17のfilesystem
        # LDFLAGS += -lstdc++fs

        # 関数の引数が関数本体で使われていないときに警告出るのうざすぎるので抑制。
        CFLAGS += -Wno-unused-parameter

        # static リンクを行う際に __cxa_guard_acquire __cxa_guard_release の生成を抑止
        #   undefined reference to `__imp___cxa_guard_acquire'
        #   undefined reference to `__imp___cxa_guard_release'
        # static 変数を初期化したかを pthread_mutex_t でロックを取って確認し、
        # 最初の実行なら初期化するスレッドセーフなコードを生成するためのもの。
        # → 本当に消してしまっても大丈夫か?
        WCFLAGS += -fno-threadsafe-statics

else
        ifeq ($(findstring g++,$(COMPILER)),g++)
                # mingw g++ で AVX512 向けビルドを行おうとするとエラーになる問題の回避
                # https://stackoverflow.com/questions/43152633/invalid-register-for-seh-savexmm-in-cygwin
                # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65782
                WCFLAGS += -fno-asynchronous-unwind-tables

                # C++17のfilesystem
                # LDFLAGS += -lstdc++fs

        endif
endif

ifeq ($(OS),Windows_NT)
        CFLAGS += $(WCFLAGS)
        LDFLAGS += -static -Wl,--stack,25000000
        TARGET = YaneuraOu-by-gcc.exe
else
        CFLAGS += -D_LINUX
        TARGET = YaneuraOu-by-gcc
endif

# リンク時最適化。
# CFLAGSとLDFLAGSの両方で-fltoを指定する必要がある。
# cf. https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gcc/Optimize-Options.html#Optimize-Options
LTOFLAGS = -flto

# wstringを使うためにこのシンボル定義が必要。
CFLAGS  += -DUNICODE

# stripの指示。(実行ファイルのサイズを小さく)
LDFLAGS += -Wl,-s

# mingw64では-D_WIN64,-D_WIN32は環境に応じて自動で設定されるので指定すべきではない。
# CFLAGS += -D_WIN64

# これを指定していると、各CPU向けの実行ファイルが生成されないので指定すべきではない。
# CFLAGS   += -march=native

# デバッグ情報を付加
CFLAGS  += -g3 -ggdb
CFLAGS  += -fPIC

# OpenMPを使うときにCFLAGSとして指定するオプション
# ※ 学習部ではOpenMpを用いるので、学習用のビルドではこのオプションを指定する。
# clangでOPENMPを有効にしてビルドする方法については、解説.txtを参照のこと。

# エンジンの表示名("usi"コマンドに対して出力される)
#ENGINE_NAME =

# 開発中のbranchならdevと指定する
#ENGINE_BRANCH = dev

ifeq ($(findstring g++,$(COMPILER)),g++)
        OPENMP   = -fopenmp
        OPENMP_LDFLAGS =
endif
ifeq ($(findstring clang++,$(COMPILER)),clang++)
        ifeq ($(MSYSTEM),MINGW64)
                # MSYS2 MINGW64 env
                # libgompを指定した場合、ビルドは通るがOpenMPは無効化される?
                OPENMP = -fopenmp=libgomp
                OPENMP_LDFLAGS =
        else
                ifeq ($(findstring w64-mingw32,$(COMPILER)),w64-mingw32)
                        # Ubuntu mingw-w64 clang++ env (experimental)
                        OPENMP = -fopenmp=libgomp
                        OPENMP_LDFLAGS =
                else
                        # Other (normal clang++/libomp env)
                        OPENMP = -fopenmp
                        OPENMP_LDFLAGS = -lomp
                endif
        endif
endif

# NNUE評価関数 学習バイナリ用 OpenBLAS
ifeq ($(findstring YANEURAOU_ENGINE_NNUE,$(YANEURAOU_EDITION)),YANEURAOU_ENGINE_NNUE)
        BLAS = -DUSE_BLAS
        BLAS_LDFLAGS = -lopenblas
        ifeq ($(MSYSTEM),MINGW64)
                BLAS += -I$(shell cygpath -aw /mingw64/include/OpenBLAS)
        endif
endif

CFLAGS += -DNO_EXCEPTIONS
LDFLAGS += -lpthread
LDFLAGS += -v

OBJDIR   = ../obj
ifeq "$(strip $(OBJDIR))" ""
        OBJDIR = ..
endif

#SOURCES  = $(wildcard *.cpp)
SOURCES  = \
        main.cpp                                                                   \
        types.cpp                                                                  \
        bitboard.cpp                                                               \
        misc.cpp                                                                   \
        movegen.cpp                                                                \
        position.cpp                                                               \
        usi.cpp                                                                    \
        usi_option.cpp                                                             \
        thread.cpp                                                                 \
        tt.cpp                                                                     \
        movepick.cpp                                                               \
        timeman.cpp                                                                \
        benchmark.cpp                                                              \
        extra/book/apery_book.cpp                                                  \
        extra/book/book.cpp                                                        \
        extra/book/makebook2019.cpp                                                \
        extra/bitop.cpp                                                            \
        extra/long_effect.cpp                                                      \
        extra/mate/mate1ply_with_effect.cpp                                        \
        extra/mate/mate1ply_without_effect.cpp                                     \
        extra/mate/mate_n_ply.cpp                                                  \
        extra/test_cmd.cpp                                                         \
        extra/sfen_packer.cpp                                                      \
        extra/kif_converter/kif_convert_tools.cpp                                  \
        eval/evaluate_bona_piece.cpp                                               \
        eval/evaluate.cpp                                                          \
        eval/evaluate_io.cpp                                                       \
        eval/evaluate_mir_inv_tools.cpp                                            \
        learn/learner.cpp                                                          \
        learn/learning_tools.cpp                                                   \
        learn/multi_think.cpp

ifeq ($(YANEURAOU_EDITION),YANEURAOU_ENGINE_KPPT)
        SOURCES += \
                eval/kppt/evaluate_kppt.cpp                                            \
                eval/kppt/evaluate_kppt_learner.cpp                                    \
                engine/yaneuraou-engine/yaneuraou-search.cpp
endif

ifeq ($(YANEURAOU_EDITION),YANEURAOU_ENGINE_KPP_KKPT)
        SOURCES += \
                eval/kppt/evaluate_kppt.cpp                                            \
                eval/kpp_kkpt/evaluate_kpp_kkpt.cpp                                    \
                eval/kpp_kkpt/evaluate_kpp_kkpt_learner.cpp                            \
                engine/yaneuraou-engine/yaneuraou-search.cpp
endif

ifeq ($(YANEURAOU_EDITION),YANEURAOU_ENGINE_MATERIAL)
        SOURCES += \
                engine/yaneuraou-engine/yaneuraou-search.cpp
endif

ifeq ($(findstring YANEURAOU_ENGINE_NNUE,$(YANEURAOU_EDITION)),YANEURAOU_ENGINE_NNUE)
        ifeq ($(YANEURAOU_EDITION),YANEURAOU_ENGINE_NNUE)
        else
                CFLAGS += -DYANEURAOU_ENGINE_NNUE
        endif
        ifeq ($(YANEURAOU_EDITION),YANEURAOU_ENGINE_NNUE_KP256)
                CFLAGS += -DEVAL_NNUE_KP256
        else
                ifeq ($(NNUE_EVAL_ARCH),KP256)
                        CFLAGS += -DEVAL_NNUE_KP256
                endif
        endif
        SOURCES += \
                eval/nnue/evaluate_nnue.cpp                                            \
                eval/nnue/evaluate_nnue_learner.cpp                                    \
                eval/nnue/nnue_test_command.cpp                                        \
                eval/nnue/features/k.cpp                                               \
                eval/nnue/features/p.cpp                                               \
                eval/nnue/features/half_kp.cpp                                         \
                eval/nnue/features/half_relative_kp.cpp                                \
                engine/yaneuraou-engine/yaneuraou-search.cpp
endif

ifeq ($(YANEURAOU_EDITION),MATE_ENGINE)
        SOURCES += engine/mate-engine/mate-search.cpp
endif

ifeq ($(YANEURAOU_EDITION),USER_ENGINE)
        SOURCES += engine/user-engine/user-search.cpp
endif

ifneq ($(ENGINE_NAME),)
        CFLAGS += -DENGINE_NAME_FROM_MAKEFILE=$(ENGINE_NAME)
endif

# 開発用branch
ifeq ($(findstring dev,$(ENGINE_BRANCH)),dev)
        # SuperSort使ってみよう。
        SOURCES += extra/super_sort.cpp
endif


# CPU判別

# AMDなど特定のCPU
ifeq ($(TARGET_CPU),ZEN2)
        CFLAGS += -DUSE_AVX2 -mbmi -mbmi2 -mavx2 -march=znver2

# それ以外は、AVX512,AVX2,SSE4.2,SSE4.1,SSE2のように利用できるCPU拡張命令で振り分ける。
else ifeq ($(TARGET_CPU),AVX512)
        # skylake     : -DUSE_AVX512 -DUSE_AVX512VLBWDQ -march=skylake-avx512
        # cascadelake : -DUSE_AVX512 -DUSE_AVX512VLBWDQ -DUSE_AVX512VNNI -march=cascadelake
        # icelake     : -DUSE_AVX512 -DUSE_AVX512VLBWDQ -DUSE_AVX512VNNI -DUSE_AVX512VBMI -DUSE_AVX512IFMA -USE_GFNI -march=icelake-client
        CFLAGS += -DUSE_AVX512 -DUSE_AVX512VLBWDQ -march=skylake-avx512

else ifeq ($(TARGET_CPU),AVX2)
        CFLAGS += -DUSE_AVX2 -mbmi -mbmi2 -mavx2 -march=corei7-avx

else ifeq ($(TARGET_CPU),SSE42)
        CFLAGS += -DUSE_SSE42 -msse4.2 -march=corei7

else ifeq ($(TARGET_CPU),SSE41)
        CFLAGS += -DUSE_SSE41 -msse4.1 -march=core2

else ifeq ($(TARGET_CPU),SSE2)
        CFLAGS += -DUSE_SSE2 -msse2 -march=core2

else ifeq ($(TARGET_CPU),NO_SSE)
        # 32bit用。-m32は、MSYS2 MinGW-64だと無視されるので、
        # MinGW-64の32bit環境用でコンパイルする必要がある。
        CFLAGS += -DNO_SSE -m32 -march=pentium3

else ifeq ($(TARGET_CPU),OTHER)
        CFLAGS += -DNO_SSE

endif


CFLAGS += -DUSE_MAKEFILE -D$(YANEURAOU_EDITION)

OBJECTS  = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.o))
DEPENDS  = $(OBJECTS:.o=.d)

$(TARGET): $(OBJECTS) $(LIBS)
        $(COMPILER) -o $@ $^ $(LDFLAGS) $(CFLAGS)

myMain.o : myMain.cpp
        $(COMPILER) $(CFLAGS) $(INCLUDE) -o $@ -c $<

myMain : myMain.o $(OBJECTS) $(LIBS) lib$(TARGET).so
        $(COMPILER) -o $@ myMain.o lib$(TARGET).so $(LDFLAGS) $(CFLAGS) && LD_LIBRARY_PATH=. ./$@

lib$(TARGET).so: $(OBJECTS) $(LIBS)
        $(COMPILER) -shared -o $@ $^ $(LDFLAGS) $(CFLAGS)

$(OBJDIR)/%.o: %.cpp
        @[ -d $(dir $@) ] || mkdir -p $(dir $@)
        $(COMPILER) $(CFLAGS) $(INCLUDE) -o $@ -c $<

all: clean $(TARGET)

# https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html


# ビルドターゲット

# 通常使用。
normal:
        $(MAKE) CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LTOFLAGS)' $(TARGET)

# 学習用。openmp , openblasなどを有効にする。
evallearn:
        $(MAKE) CFLAGS='$(CFLAGS) $(OPENMP) $(BLAS)' LDFLAGS='$(LDFLAGS) $(OPENMP_LDFLAGS) $(BLAS_LDFLAGS) $(LTOFLAGS)' $(TARGET)

# トーナメント用
tournament:
        $(MAKE) CFLAGS='$(CFLAGS) -DFOR_TOURNAMENT' LDFLAGS='$(LDFLAGS) $(LTOFLAGS)' $(TARGET)

# トーナメント用lib
tournamentlib:
        $(MAKE) CFLAGS='$(CFLAGS) -DFOR_TOURNAMENT' LDFLAGS='$(LDFLAGS) $(LTOFLAGS)' lib$(TARGET).so

# 教師棋譜生成用
gensfen:
        $(MAKE) CFLAGS='$(CFLAGS) $(OPENMP) $(BLAS) -DGENSFEN2019' LDFLAGS='$(LDFLAGS) $(OPENMP_LDFLAGS) $(BLAS_LDFLAGS) $(LTOFLAGS)' $(TARGET)


# とりあえずPGOはAVX2とSSE4.2専用
prof:
        $(MAKE) CFLAGS='$(CFLAGS) -pg' tournament

profgen:
        $(MAKE) CFLAGS='$(CFLAGS) -fprofile-generate -lgcov' LDFLAGS='$(LDFLAGS) -fprofile-generate -lgcov'

profuse:
        $(MAKE) CFLAGS='$(CFLAGS) -fprofile-use -lgcov' LDFLAGS='$(LDFLAGS) -fprofile-use -lgcov $(LTOFLAGS)'

pgo:
        $(MAKE) profgen
        @./$(TARGET) EvalDir ../build/eval , bench , quit
        @touch $(SOURCES)
        $(MAKE) profuse

clean:
        rm -f $(OBJECTS) $(DEPENDS) $(TARGET) ${OBJECTS:.o=.gcda}

-include $(DEPENDS)

4.4 libYaneuraOu-by-gcc.soの作成

  • -fPIC オプションをつけてコンパイルしなおさないといけないから、以下で一旦コンパイルしたものを消して再度コンパイルしなおす
make clean tournamentlib
  • ソースを消してやるのが上のコマンドだけど、変更してないのをコンパイルしなおさないのは以下
make tournamentlib

4.5 myMain を作成(myMain.cppをmain関数とした実行ファイルの作成)

  • myMainのコンパイルに成功したら、実行される
make myMain
  • 単体で実行するには以下(libYaneuraOu-by-gcc.soをカレントディレクトリに探しにいくように、LD_LIBRARY_PATHの設定が必要になる)
LD_LIBRARY_PATH=. ./myMain

4.6 この章のまとめ

  • 動的ライブラリの作成
  • 昔の動画では、コンパイルコマンドを自作してたけど、今回はMakefileの改造で対応

5 下準備2

5.1 以下の操作を行っている動画


5.2 myMain.cpp の修正

  • USIのループに行かないようにする
  • 評価関数の読み込み処理部分をusi.cppからもってくる(これを行わないと、セグメンテーションエラーになるようになったようだ、数年前はこれなしでいけてた)
//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み


        // 生成して、待機させていたスレッドの停止

        Threads.set(0);

        return 0;
}

5.3 コンパイル実行

make myMain

5.4 この章のまとめ

  • 数年前にアップしてた動画の方法で、現在はダメ
  • 最新のソースで上手く行く方法の一つを紹介

6 Positionクラス(盤面クラス)の初期化と表示

6.1 以下の操作を行っている動画


6.2 myMain.cpp の修正

  • Posionオブジェクトと、必要なオブジェクト生成
  • 平手の盤面設定コード追加
    • 以下の2つの方法ある。どちらでもOK(posはPosionクラスのオブジェクトがはいっている変数)
pos.set_hirate(&states->back(),Threads.main());
pos.set(SFEN_HIRATE,&states->back(),Threads.main());
  • 平手にしたPosionオブジェクトの表示
//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;

        // 生成して、待機させていたスレッドの停止

        Threads.set(0);

        return 0;
}

6.3 コンパイル実行

make myMain

6.4 この章のまとめ

  • Postionオブジェクトの生成、盤面設定、表示
  • 評価関数を読み込んでからじゃないと、セグメンテーションエラーとなる

7 ある盤面で可能な手をすべて表示

7.1 以下の操作を行っている動画


7.2 myMain.cpp の修正

//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

7.3 コンパイル実行

make myMain

7.4 この章のまとめ

  • ある盤面で可能な手をすべて表示

8 現状の盤面の評価値表示

8.1 以下の操作を行っている動画


8.2 myMain.cpp の修正

//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

  //現状の盤面の評価値を表示
  cout << "eval=" <<  Eval::compute_eval(pos) << endl;
  Eval::print_eval_stat(pos);

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

8.3 コンパイル実行

make myMain

8.4 この章のまとめ

  • 現状の盤面の評価値表示

9 高速1手詰め探索ルーチン利用

9.1 以下の操作を行っている動画


9.2 myMain.cpp の修正

//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

  //現状の盤面の評価値を表示
  cout << "eval=" <<  Eval::compute_eval(pos) << endl;
  Eval::print_eval_stat(pos);

  //世界一早い1手づめチェックルーチン
  // lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L[N] w 0 1
  pos.set("lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b N 1",&states->back(),Threads.main());

  cout << pos << endl;
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

9.3 コンパイル実行

make myMain

9.4 この章のまとめ

  • 高速1手詰め探索ルーチン利用

10 詰みチェック

10.1 以下の操作を行っている動画


10.2 myMain.cpp の修正

  • Positionオブジェクトのis_mated() メソッドで行える
//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

  //現状の盤面の評価値を表示
  cout << "eval=" <<  Eval::compute_eval(pos) << endl;
  Eval::print_eval_stat(pos);

  //世界一早い1手づめチェックルーチン
  // lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L[N] w 0 1
  pos.set("lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b N 1",&states->back(),Threads.main());

  cout << pos << endl;
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

10.3 コンパイル実行

make myMain

10.4 この章のまとめ

  • 詰みチェック

11 指定の一手を行う

11.1 以下の操作を行っている動画


11.2 myMain.cpp の修正

  • Positionオブジェクトのdo_move() メソッドで行える
//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

  //現状の盤面の評価値を表示
  cout << "eval=" <<  Eval::compute_eval(pos) << endl;
  Eval::print_eval_stat(pos);

  //世界一早い1手づめチェックルーチン
  // lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L[N] w 0 1
  pos.set("lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b N 1",&states->back(),Threads.main());

  cout << pos << endl;
  //可能な手を全て表示 (LEGAL_ALL ではなく、 LEGALタイプ)
  MoveList< LEGAL > ml2(pos);
  cout << "ml.size()=" << ml2.size() << endl;
  for(auto m : ml2) {
    //cout << m.move << endl;
    cout << m << endl;
  }
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;
  Move m=pos.mate1ply();
  // 上位bitに駒種を入れておかないとpseudo_legal()で引っかかる。
  //これやっとなかないと、MoveList<LEGAL>(pos).contains(m) で正しいのがかえってこない
  m = pos.move16_to_move(m); 

  cout << "m=" << m << endl;
  cout << "MoveList<LEGAL>(pos).contains(m)=" << MoveList<LEGAL>(pos).contains(m) << endl;
  if (MoveList<LEGAL>(pos).contains(m)) {
    // 1手進めるごとにStateInfoが積まれていく。これは千日手の検出のために必要。
    states->emplace_back();
    if (m == MOVE_NULL) // do_move に MOVE_NULL を与えると死ぬので
    {
      cout << "MOVE_NULL " << m << endl;
      pos.do_null_move(states->back());
    }
    else
    {
      cout << "not MOVE_NULL " << m << endl;
      pos.do_move(m, states->back());
    }
    cout << pos << endl;
    cout << "pos.is_mated()=" << pos.is_mated() << endl;
  }

  Move mymove = USI::to_move("7f7g");

  cout << mymove << endl;

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

/*
  // 指し手のリストをパースする(あるなら)
  while (is >> token && (m = USI::to_move(pos, token)) != MOVE_NONE)
  {
    // 1手進めるごとにStateInfoが積まれていく。これは千日手の検出のために必要。
    states->emplace_back();
    if (m == MOVE_NULL) // do_move に MOVE_NULL を与えると死ぬので
      pos.do_null_move(states->back());
    else
      pos.do_move(m, states->back());
  }

Move USI::to_move(const Position& pos, const std::string& str)
{
  // 全合法手のなかからusi文字列に変換したときにstrと一致する指し手を探してそれを返す
  //for (const ExtMove& ms : MoveList<LEGAL_ALL>(pos))
  //  if (str == move_to_usi(ms.move))
  //    return ms.move;

  // ↑のコードは大変美しいコードではあるが、棋譜を大量に読み込むときに時間がかかるうるのでもっと高速な実装をする。

  if (str == "resign")
    return MOVE_RESIGN;

  if (str == "win")
    return MOVE_WIN;

  // パス(null move)入力への対応 {UCI: "0000", GPSfish: "pass"}
  if (str == "0000" || str == "null" || str == "pass")
    return MOVE_NULL;

  // usi文字列を高速にmoveに変換するやつがいるがな..
  Move move = USI::to_move(str);

  // 上位bitに駒種を入れておかないとpseudo_legal()で引っかかる。
  move = pos.move16_to_move(move);

#if defined(MUST_CAPTURE_SHOGI_ENGINE)
  // 取る一手将棋は合法手かどうかをGUI側でチェックしてくれないから、
  // 合法手かどうかのチェックを入れる。
  if (!MoveList<LEGAL>(pos).contains(move))
    sync_cout << "info string Error!! Illegal Move = " << move << sync_endl;
#endif

  if (pos.pseudo_legal(move) && pos.legal(move))
    return move;

  // いかなる状況であろうとこのような指し手はエラー表示をして弾いていいと思うが…。
  // cout << "\nIlligal Move : " << str << "\n";

  return MOVE_NONE;
}



*/

11.3 コンパイル実行

make myMain

11.4 この章のまとめ

  • 指定の一手を行う

12 指定の一手を行った後、その手の取り消し

12.1 以下の操作を行っている動画


12.2 myMain.cpp の修正

  • Positionオブジェクトのundo_move() メソッドで行える
//#include <iostream>
//#include "bitboard.h"
//#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"
#include "usi.h"
#include "misc.h"

#include "types.h"
#include "usi.h"
#include "position.h"
#include "search.h"
#include "thread.h"
#include "tt.h"

#include <sstream>
#include <queue>

using namespace std;

// ----------------------------------------
//  main()
// ----------------------------------------

int main(int argc, char* argv[])
{
        // --- 全体的な初期化

        Misc::init(argv);
        USI::init(Options);
        Bitboards::init();
        Position::init();
        Search::init();
        Threads.set(Options["Threads"]);
        //Search::clear();
        Eval::init();

        // USIコマンドの応答部

        //USI::loop(argc, argv);


  // ************* 評価関数の読み込み
  Eval::load_eval();

  // チェックサムの計算と保存(その後のメモリ破損のチェックのため)
  u64 eval_sum;
  eval_sum = Eval::calc_check_sum();

  // ソフト名の表示
  Eval::print_softname(eval_sum);

  USI::load_eval_finished = true;
  // ************* 評価関数の読み込み

  Position pos;
  StateListPtr states = StateListPtr(new StateList(1));
  // pos.set_hirate(&states->back(),Threads.main());
  pos.set(SFEN_HIRATE,&states->back(),Threads.main());

  cout << pos << endl;
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;

  //可能な手を全て表示 
  MoveList< LEGAL_ALL > ml(pos);
  cout << "ml.size()=" << ml.size() << endl;
  for(auto m : ml) {
    //cout << m.move << endl;
    cout << m << endl;
  }

  //現状の盤面の評価値を表示
  cout << "eval=" <<  Eval::compute_eval(pos) << endl;
  Eval::print_eval_stat(pos);

  //世界一早い1手づめチェックルーチン
  // lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L[N] w 0 1
  pos.set("lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b N 1",&states->back(),Threads.main());

  cout << pos << endl;
  //可能な手を全て表示 (LEGAL_ALL ではなく、 LEGALタイプ)
  MoveList< LEGAL > ml2(pos);
  cout << "ml.size()=" << ml2.size() << endl;
  for(auto m : ml2) {
    //cout << m.move << endl;
    cout << m << endl;
  }
  // 高速一手詰みチェックルーチン
  cout << "pos.mate1ply()=" << pos.mate1ply() << endl;
  // 詰みか表示
  cout << "pos.is_mated()=" << pos.is_mated() << endl;
  Move m=pos.mate1ply();
  // 上位bitに駒種を入れておかないとpseudo_legal()で引っかかる。
  //これやっとなかないと、MoveList<LEGAL>(pos).contains(m) で正しいのがかえってこない
  m = pos.move16_to_move(m); 

  cout << "m=" << m << endl;
  cout << "MoveList<LEGAL>(pos).contains(m)=" << MoveList<LEGAL>(pos).contains(m) << endl;
  if (MoveList<LEGAL>(pos).contains(m)) {
    // 1手進めるごとにStateInfoが積まれていく。これは千日手の検出のために必要。
    states->emplace_back();
    if (m == MOVE_NULL) // do_move に MOVE_NULL を与えると死ぬので
    {
      cout << "MOVE_NULL " << m << endl;
      pos.do_null_move(states->back());
    }
    else
    {
      cout << "not MOVE_NULL " << m << endl;
      pos.do_move(m, states->back());
    }
    cout << pos << endl;
    cout << "pos.is_mated()=" << pos.is_mated() << endl;
    // cout << "pos.lastMove=" << pos.lastMove  << endl; // ERROR

    // undo_move してみる
    pos.undo_move(m);
    cout << pos << endl;
    cout << "pos.is_mated()=" << pos.is_mated() << endl;
  }

  Move mymove = USI::to_move("7f7g");

  cout << mymove << endl;

        // 生成して、待機させていたスレッドの停止
        Threads.set(0);

        return 0;
}

/*
  // 指し手のリストをパースする(あるなら)
  while (is >> token && (m = USI::to_move(pos, token)) != MOVE_NONE)
  {
    // 1手進めるごとにStateInfoが積まれていく。これは千日手の検出のために必要。
    states->emplace_back();
    if (m == MOVE_NULL) // do_move に MOVE_NULL を与えると死ぬので
      pos.do_null_move(states->back());
    else
      pos.do_move(m, states->back());
  }

Move USI::to_move(const Position& pos, const std::string& str)
{
  // 全合法手のなかからusi文字列に変換したときにstrと一致する指し手を探してそれを返す
  //for (const ExtMove& ms : MoveList<LEGAL_ALL>(pos))
  //  if (str == move_to_usi(ms.move))
  //    return ms.move;

  // ↑のコードは大変美しいコードではあるが、棋譜を大量に読み込むときに時間がかかるうるのでもっと高速な実装をする。

  if (str == "resign")
    return MOVE_RESIGN;

  if (str == "win")
    return MOVE_WIN;

  // パス(null move)入力への対応 {UCI: "0000", GPSfish: "pass"}
  if (str == "0000" || str == "null" || str == "pass")
    return MOVE_NULL;

  // usi文字列を高速にmoveに変換するやつがいるがな..
  Move move = USI::to_move(str);

  // 上位bitに駒種を入れておかないとpseudo_legal()で引っかかる。
  move = pos.move16_to_move(move);

#if defined(MUST_CAPTURE_SHOGI_ENGINE)
  // 取る一手将棋は合法手かどうかをGUI側でチェックしてくれないから、
  // 合法手かどうかのチェックを入れる。
  if (!MoveList<LEGAL>(pos).contains(move))
    sync_cout << "info string Error!! Illegal Move = " << move << sync_endl;
#endif

  if (pos.pseudo_legal(move) && pos.legal(move))
    return move;

  // いかなる状況であろうとこのような指し手はエラー表示をして弾いていいと思うが…。
  // cout << "\nIlligal Move : " << str << "\n";

  return MOVE_NONE;
}



*/

12.3 コンパイル実行

make myMain

12.4 この章のまとめ

  • 指定の一手を行った後、その手の取り消し

13 Python+cppyyを利用して、PythonからYaneuraouのライブラリの直接利用

  • CERNのROOTをいれて数ヶ月前にトライしたが、ヘッダーファイルにC++の新しい規格が使われていて、ROOTでサポートされておらずエラー多発。ソース変更が面倒なので放置
  • PythonにcppyyというCERNのROOTの技術を利用したC++やCの外部ライブラリを利用できるパッケージがあることを知り、試してみたら上手くいった。
    • CERNのROOTで何故上手くいかず、こちらで上手くいったのか、原因は調べてない。(よくわかんない)
  • 関連動画

13.1 以下の操作を行っている動画


13.2 実際の手順

  • 以下のソースを実行すると、盤面を平手に設定して、盤面が表示される
  • 平手の設定をPython側から行おうとしたが、書き方がわからず、cppyy.cppdefを利用して実現した(書き方わかる方はコメント欄で教えてください)
    • 失敗した命令はコメントアウトして残してあります。
import cppyy                                                                                                                                  
from array import array

cppyy.include("search.h")                                                                                                                     
cppyy.include("thread.h")                                                                                                                     
cppyy.include("tt.h")                                                                                                                         
cppyy.include("usi.h")                                                                                                                        
cppyy.include("misc.h")                                                                                                                       
cppyy.include("iostream")                                                                                                                       

cppyy.load_library("./libYaneuraOu-by-gcc.so")      

cppyy.cppdef('char* argv[]={{}};')
cppyy.cppdef('unsigned long tmp01=Options["Threads"];')

cppyy.gbl.Misc.init(cppyy.gbl.argv)
cppyy.gbl.USI.init(cppyy.gbl.Options)
cppyy.gbl.Bitboards.init()
cppyy.gbl.Position.init()
cppyy.gbl.Search.init();
cppyy.gbl.Threads.set(4)
cppyy.gbl.Eval.init()
cppyy.gbl.Eval.load_eval();

cppyy.cppdef('StateListPtr create_states() { return StateListPtr(new StateList(1));};')
cppyy.cppdef('void setMyPosition(Position& pos, std::string sfen, StateListPtr states) { pos.set(sfen,&states->back(),Threads.main()); }; ')
cppyy.cppdef('void myPrintPosition(Position& pos) { std::cout << pos << std::endl; };')

pos=cppyy.gbl.Position()
states=cppyy.gbl.create_states()
print("cppyy.gbl.Threads.size()")
print(cppyy.gbl.Threads.size())
print(pos.sfen())
cppyy.gbl.setMyPosition(pos,cppyy.gbl.SFEN_HIRATE,states)
#pos.set(cppyy.gbl.SFEN_HIRATE,cppyy.addressof(states.back()),cppyy.gbl.Threads.main()) #ERR
#pos.set(cppyy.gbl.SFEN_HIRATE,states.back(),cppyy.gbl.Threads.main()) #Error
cppyy.gbl.myPrintPosition(pos)

13.3 この章のまとめ

  • Python+cppyyを利用することで、インタプリタ環境から、Yaneuraouさんの将棋ライブラリを利用することが可能になった
    • 何故かCERNのROOTでも数ヶ月前に試したがダメだった
      • ヘッダーの読み込みで新しいC++の規格が利用できないというエラーが発生
      • 修正が面倒で放置
    • 何の修正もなく利用可能に
      • 試行錯誤が非常にやりやすくなった
      • 一部cppyyで書き方がわからないものは、cppyy.cppdefで定義した関数を利用して、動作できるものを作成した
      • cppyy.cppdefを利用せずとも、平手に設定出来る方法わかるかたはコメントして教えて下さい

14 最新ソースをダウンロード(2020/11/19)して、トーナメント用、詰将棋用のエンジンコンパイル、それらのライブラリコンパイル用のスクリプトについて の章を作成

  • 2020/07頃の動画や、文書(上の方の章)での手順では、現在(2020/11/19)では上手くいかなくなっていた(ライブラリのコンパイル)
  • 関連動画

14.2 以下の操作を行っている動画


14.3 2020/11/19で、最新のYaneuraOuさんの将棋エンジン、詰将棋エンジン、tanukiさんの詰将棋エンジン、それらのライブラリ作成するスクリプトについて

14.3.1 ソースダウンロードして、コンパイルするスクリプトファイルの作成

  • get というファイルを以下の内容で作成
  • CPUがSSSE42以外を希望する場合は、以下のどれか希望の物にSSR42という文字列を全部置き換える(文字列置換を一括で行えるエディタを利用すると便利)
    • AVX512VNNI
    • AVX512
    • AVX2
    • SSE42
    • SSE41
    • SSSE3
    • SSE2
    • NO_SSE
    • OTHER
    • ZEN1
    • ZEN2
  • 使えるCPUの確認は、 cat /proc/cpuinfo | grep -i sse や cat /proc/cpuinfo | grep -i avx 等で確認可能(Ubuntu等、Linuxマシンの場合)
  • 使えるCPUの種類の確認方法の解説動画は[[]]等があります(Ubuntuで行った動画,他のLinuxでも同じ手順で多分いける)
#!/bin/bash
D=`date +%Y%m%d`
DT=`date +%Y%m%d_%H%M`
mkdir ${DT}
cd ${DT}
git clone https://github.com/yaneurao/YaneuraOu.git
#tar cvzf YaneuraOu_${DT}_000.tgz YaneuraOu/
#(cd YaneuraOu/ ;git checkout 9bbd0f38498b22e9f3e6cf9493a7f8849c02e496)
tar cvzf YaneuraOu_${DT}.tgz YaneuraOu/
git clone https://github.com/nodchip/tanuki-.git
#tar cvzf tanuki-_${DT}_000.tgz tanuki-
#(cd tanuki-/ ;git checkout 258d55331385a9e594ed8e624409ea3bfdd53602)
tar cvzf tanuki-_${DT}.tgz tanuki-
(cd YaneuraOu/source && make clean tournament TARGET_CPU=SSE42) 2>&1 | tee ./log001.txt
tar cvzf YaneuraOu_${DT}_build.tgz YaneuraOu/
(
mkdir MATE2LIB
cd MATE2LIB
tar xvzf ../tanuki-_${DT}.tgz 
(cd tanuki-/source && patch -p2 < ../../../../06makefile_DEBUG_lib_tanuki.patch && make clean tournamentlib TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE ) 2>&1 | tee ./log010.txt
)
(
mkdir MATELIB
cd MATELIB
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && patch -p2 < ../../../../06makefile_DEBUG_lib.patch && make clean tournamentlib TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE ) 2>&1 | tee ./log010.txt
)
# cp main.cpp myMain.cpp
# make myMain TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE
# LD_LIBRARY_PATH=. ./myMain 
(
mkdir MATE2
cd MATE2
tar xvzf ../tanuki-_${DT}.tgz 
(cd tanuki-/source/ && make clean tournament TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE ) 2>&1 | tee ./log004.txt
)
(
mkdir LEARN
cd LEARN
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && make clean evallearn TARGET_CPU=SSE42) 2>&1 | tee ./log002.txt
)
(
mkdir MATE
cd MATE
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && make clean tournament TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE ) 2>&1 | tee ./log003.txt
)
(
mkdir TOURNAMENTLIB
cd TOURNAMENTLIB
tar xvzf ../YaneuraOu_${DT}.tgz
(cd YaneuraOu/source && patch -p2 < ../../../../06makefile_DEBUG_lib.patch && make clean tournamentlib TARGET_CPU=SSE42 ) 2>&1 | tee ./log011.txt
)
# cp main.cpp myMain.cpp
# make myMain TARGET_CPU=SSE42 
# LD_LIBRARY_PATH=. ./myMain 

14.3.2 作ったスクリプトに実行権限を与える

chmod +x get

14.3.3 上のスクリプトで利用するバッチファイルの生成

  1. 06makefile_DEBUG_lib.patch
    • 以下のテキストはbase64でエンコードしてあるので、デコードして 06makefile_DEBUG_lib.patch というファイル名で保存
    LS0tIFlhbmV1cmFPdS5vcmcvc291cmNlL01ha2VmaWxlCTIwMjAtMTEtMTkgMDg6MzY6MzUuMDAw
    MDAwMDAwICswOTAwCisrKyBZYW5ldXJhT3Uvc291cmNlL01ha2VmaWxlCTIwMjAtMTEtMTkgMDg6
    NDc6NDcuMzkyOTU1OTMyICswOTAwCkBAIC01Niw4ICs1Niw4IEBAIFRBUkdFVF9DUFUgPSBBVlgy
    CiAKIAogIyDjg4fjg5Djg4Pjgqzjg7zjgpLkvb/nlKjjgZnjgovjgYsgKGRlYnVnZ2VyKQotREVC
    VUcgPSBPRkYKLSNERUJVRyA9IE9OCisjIERFQlVHID0gT0ZGCitERUJVRyA9IE9OCiAKIAogIyDk
    vb/nlKjjgZnjgovjgrPjg7Pjg5HjgqTjg6kgKGNvbXBpbGVyKQpAQCAtMTUzLDcgKzE1Myw4IEBA
    IExERkxBR1MgKz0gLVdsLC1zCiAjIENQUEZMQUdTICAgKz0gLW1hcmNoPW5hdGl2ZQogCiAjIOOD
    h+ODkOODg+OCsOaDheWgseOCkuS7mOWKoAotIyBDUFBGTEFHUyAgKz0gLWczIC1nZ2RiCitDUFBG
    TEFHUyAgKz0gLWczIC1nZ2RiCitDUFBGTEFHUyAgKz0gLWZQSUMKIAogIyBPcGVuTVDjgpLkvb/j
    gYbjgajjgY3jgatDUFBGTEFHU+OBqOOBl+OBpuaMh+WumuOBmeOCi+OCquODl+OCt+ODp+ODswog
    IyDigLsg5a2m57+S6YOo44Gn44GvT3Blbk1w44KS55So44GE44KL44Gu44Gn44CB5a2m57+S55So
    44Gu44OT44Or44OJ44Gn44Gv44GT44Gu44Kq44OX44K344On44Oz44KS5oyH5a6a44GZ44KL44CC
    CkBAIC0yMDIsOCArMjAzLDkgQEAgaWZlcSAiJChzdHJpcCAkKE9CSkRJUikpIiAiIgogZW5kaWYK
    IAogI1NPVVJDRVMgID0gJCh3aWxkY2FyZCAqLmNwcCkKKyMJbWFpbi5jcHAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAor
    IwogU09VUkNFUyAgPSBcCi0JbWFpbi5jcHAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogCXR5cGVzLmNwcCAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    IFwKIAliaXRib2FyZC5jcHAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICBcCiAJbWlzYy5jcHAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXApAQCAtMzg4LDYg
    KzM5MCwxNSBAQCBhbGw6IGNsZWFuICQoVEFSR0VUKQogJChUQVJHRVQpOiAkKE9CSkVDVFMpICQo
    TElCUykKIAkkKENPTVBJTEVSKSAtbyAkQCAkXiAkKExERkxBR1MpICQoQ1BQRkxBR1MpCiAKK215
    TWFpbi5vIDogbXlNYWluLmNwcAorCSQoQ09NUElMRVIpICQoQ1BQRkxBR1MpICQoSU5DTFVERSkg
    LW8gJEAgLWMgJDwKKworbXlNYWluIDogbXlNYWluLm8gJChMSUJTKSBsaWIkKFRBUkdFVCkuc28K
    KwkkKENPTVBJTEVSKSAtbyAkQCBteU1haW4ubyBsaWIkKFRBUkdFVCkuc28gJChMREZMQUdTKSAk
    KENQUEZMQUdTKQorCitsaWIkKFRBUkdFVCkuc286ICQoT0JKRUNUUykgJChMSUJTKQorCSQoQ09N
    UElMRVIpIC1zaGFyZWQgLW8gJEAgJF4gJChMREZMQUdTKSAkKENQUEZMQUdTKQorCiAkKE9CSkRJ
    UikvJS5vOiAlLmNwcAogCUBbIC1kICQoZGlyICRAKSBdIHx8IG1rZGlyIC1wICQoZGlyICRAKQog
    CSQoQ09NUElMRVIpICQoQ1BQRkxBR1MpICQoSU5DTFVERSkgLW8gJEAgLWMgJDwKQEAgLTQwOSw2
    ICs0MjAsMTAgQEAgZXZhbGxlYXJuOgogdG91cm5hbWVudDoKIAkkKE1BS0UpIENQUEZMQUdTPSck
    KENQUEZMQUdTKSAtREZPUl9UT1VSTkFNRU5UJyBMREZMQUdTPSckKExERkxBR1MpICQoTFRPRkxB
    R1MpJyAkKFRBUkdFVCkKIAorIyDjg4jjg7zjg4rjg6Hjg7Pjg4jnlKhsaWIKK3RvdXJuYW1lbnRs
    aWI6CisJJChNQUtFKSBDUFBGTEFHUz0nJChDUFBGTEFHUykgLURGT1JfVE9VUk5BTUVOVCcgTERG
    TEFHUz0nJChMREZMQUdTKSAkKExUT0ZMQUdTKScgbGliJChUQVJHRVQpLnNvCisKICMg5pWZ5bir
    5qOL6K2c55Sf5oiQ55SoKOmWi+eZuueUqOOBquOBruOBp+mdnuWFrOmWiykgLy8gY3VycmVudGx5
    IHByaXZhdGUKIGdlbnNmZW46CiAJJChNQUtFKSBDUFBGTEFHUz0nJChDUFBGTEFHUykgJChPUEVO
    TVApICQoQkxBUykgLURFVkFMX0xFQVJOIC1ER0VOU0ZFTjIwMTknIExERkxBR1M9JyQoTERGTEFH
    UykgJChPUEVOTVBfTERGTEFHUykgJChCTEFTX0xERkxBR1MpICQoTFRPRkxBR1MpJyAkKFRBUkdF
    VCkK
    
    • 上の内容を 06makefile_DEBUG_lib.patch.base64というファイルに保存して、それをデコードする場合は以下のコマンドでデコード可能
    cat 06makefile_DEBUG_lib.patch.base64 | base64 -d > 06makefile_DEBUG_lib.patch
    
  2. 06makefile_DEBUG_lib_tanuki.patch
    • 以下のテキストはbase64でエンコードしてあるので、デコードして 06makefile_DEBUG_lib_tanuki.patch というファイル名で保存
    • tanukiのMakefileが現在のYanauraOuさんの最新のMakefileと異る為、別ファイルを作成する必要がありました。tanukiのMakefileがYaneuraOuさんの最新Makefileに追いついたら、 06makefile_DEBUG_lib_tanuki.patchは前の 06makefile_DEBUG_lib.patch と同じ内容でいけるはず
    LS0tIHRhbnVraS0ub3JnL3NvdXJjZS9NYWtlZmlsZQkyMDIwLTExLTE5IDA5OjQwOjQxLjU5NzM5
    Njg0OSArMDkwMAorKysgdGFudWtpLS9zb3VyY2UvTWFrZWZpbGUJMjAyMC0xMS0xOSAwOTo0Njow
    Ny4yNTE4OTU5NzcgKzA5MDAKQEAgLTQxLDggKzQxLDggQEAgVEFSR0VUX0NQVSA9IEFWWDIKIAog
    CiAjIOODh+ODkOODg+OCrOODvOOCkuS9v+eUqOOBmeOCi+OBiwotREVCVUcgPSBPRkYKLSNERUJV
    RyA9IE9OCisjREVCVUcgPSBPRkYKK0RFQlVHID0gT04KIAogCiAjIGNsYW5n44Gn44Kz44Oz44OR
    44Kk44Or44GX44Gf44G744GG44GMZ2Nj44KI44KK5pWwJemAn+OBhOOBo+OBveOBhOOAggpAQCAt
    MTIyLDYgKzEyMiw5IEBAIExERkxBR1MgKz0gLVdsLC1zCiAKICMg44OH44OQ44OD44Kw5oOF5aCx
    44KS5LuY5YqgCiAjIENGTEFHUyAgKz0gLWczIC1nZ2RiCitDRkxBR1MgICs9IC1nMyAtZ2dkYgor
    Q0ZMQUdTICArPSAtZlBJQworCiAKICMgT3Blbk1Q44KS5L2/44GG44Go44GN44GrQ0ZMQUdT44Go
    44GX44Gm5oyH5a6a44GZ44KL44Kq44OX44K344On44OzCiAjIOKAuyDlrabnv5Lpg6jjgafjga9P
    cGVuTXDjgpLnlKjjgYTjgovjga7jgafjgIHlrabnv5LnlKjjga7jg5Pjg6vjg4njgafjga/jgZPj
    ga7jgqrjg5fjgrfjg6fjg7PjgpLmjIflrprjgZnjgovjgIIKQEAgLTE3NSw4ICsxNzgsOSBAQCBp
    ZmVxICIkKHN0cmlwICQoT0JKRElSKSkiICIiCiBlbmRpZgogCiAjU09VUkNFUyAgPSAkKHdpbGRj
    YXJkICouY3BwKQorIwltYWluLmNwcCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcCisjCiBTT1VSQ0VTICA9IFwKLQltYWlu
    LmNwcCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICBcCiAJdHlwZXMuY3BwICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXAogCWJpdGJvYXJkLmNwcCAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    IFwKIAltaXNjLmNwcCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
    ICAgICAgICAgICAgICAgICAgICAgICBcCkBAIC0zMTYsNiArMzIwLDE4IEBAIERFUEVORFMgID0g
    JChPQkpFQ1RTOi5vPS5kKQogJChUQVJHRVQpOiAkKE9CSkVDVFMpICQoTElCUykKIAkkKENPTVBJ
    TEVSKSAtbyAkQCAkXiAkKExERkxBR1MpICQoQ0ZMQUdTKQogCitsaWIkKFRBUkdFVCkuc286ICQo
    T0JKRUNUUykgJChMSUJTKQorCSQoQ09NUElMRVIpIC1zaGFyZWQgLW8gJEAgJF4gJChMREZMQUdT
    KSAkKENGTEFHUykKKworbXlNYWluLm8gOiBteU1haW4uY3BwCisJJChDT01QSUxFUikgJChDRkxB
    R1MpICQoSU5DTFVERSkgLW8gJEAgLWMgJDwKKworbXlNYWluIDogbXlNYWluLm8gJChMSUJTKSBs
    aWIkKFRBUkdFVCkuc28KKwkkKENPTVBJTEVSKSAtbyAkQCBteU1haW4ubyBsaWIkKFRBUkdFVCku
    c28gJChMREZMQUdTKSAkKENGTEFHUykKKworbGliJChUQVJHRVQpLnNvOiAkKE9CSkVDVFMpICQo
    TElCUykKKwkkKENPTVBJTEVSKSAtc2hhcmVkIC1vICRAICReICQoTERGTEFHUykgJChDRkxBR1Mp
    CisKICQoT0JKRElSKS8lLm86ICUuY3BwCiAJQFsgLWQgJChkaXIgJEApIF0gfHwgbWtkaXIgLXAg
    JChkaXIgJEApCiAJJChDT01QSUxFUikgJChDRkxBR1MpICQoSU5DTFVERSkgLW8gJEAgLWMgJDwK
    QEAgLTMzOSw2ICszNTUsMTAgQEAgZXZhbGxlYXJuOgogdG91cm5hbWVudDoKIAkkKE1BS0UpIENG
    TEFHUz0nJChDRkxBR1MpIC1ERk9SX1RPVVJOQU1FTlQnIExERkxBR1M9JyQoTERGTEFHUykgJChM
    VE9GTEFHUyknICQoVEFSR0VUKQogCisjIOODiOODvOODiuODoeODs+ODiOeUqGxpYgordG91cm5h
    bWVudGxpYjoKKwkkKE1BS0UpIENGTEFHUz0nJChDRkxBR1MpIC1ERk9SX1RPVVJOQU1FTlQnIExE
    RkxBR1M9JyQoTERGTEFHUykgJChMVE9GTEFHUyknIGxpYiQoVEFSR0VUKS5zbworCiAjIOaVmeW4
    q+aji+itnOeUn+aIkOeUqAogZ2Vuc2ZlbjoKIAkkKE1BS0UpIENGTEFHUz0nJChDRkxBR1MpICQo
    T1BFTk1QKSAkKEJMQVMpIC1ER0VOU0ZFTjIwMTknIExERkxBR1M9JyQoTERGTEFHUykgJChPUEVO
    TVBfTERGTEFHUykgJChCTEFTX0xERkxBR1MpICQoTFRPRkxBR1MpJyAkKFRBUkdFVCkK
    
    • 上の内容を 06makefile_DEBUG_lib_tanuki.patch.base64というファイルに保存して、それをデコードする場合は以下のコマンドでデコード可能
    cat 06makefile_DEBUG_lib_tanuki.patch.base64 | base64 -d > 06makefile_DEBUG_lib_tanuki.patch
    

14.3.4 作ったスクリプトを実行

  • 以下のコマンドでソースゲット、色々コンパイルしてくれる
  • 変化が激しい為、今後修正しないと動かなくなる可能性あり
    • 動作確認した時のgitのバージョンは YaneuraOuが 9bbd0f38498b22e9f3e6cf9493a7f8849c02e496
      • Mon Nov 16 03:16:47 2020 +0900
    • 動作確認した時のgitのバージョンは tanuki が 258d55331385a9e594ed8e624409ea3bfdd53602
      • Tue May 5 00:32:13 2020 +0900
  • コンパイル出来ない時は、git checkout xxxx (xxxはバージョン)として、過去のソースにすることで、コンパイル可能に
    • get の以下の行のコメントを外すと(先頭の#をはずず)、指定のバージョンのソースでコンパイル
      • #tar cvzf YaneuraOu_${DT}_000.tgz YaneuraOu/
      • #(cd YaneuraOu/ ;git checkout 9bbd0f38498b22e9f3e6cf9493a7f8849c02e496)
      • #tar cvzf tanuki-_${DT}_000.tgz tanuki-
      • #(cd tanuki-/ ;git checkout 258d55331385a9e594ed8e624409ea3bfdd53602)
./get
  • 20201119_2000 のような、年月日、時間、分の名前のディレクトリが作成され、その中に、githubからソースをダウンロードしてコンパイルが実行される
    • YaneuraOu/source に通常のものがコンパイルされる YaneuraOu-by-gcc
    • TOURNAMENTLIB/YaneuraOu/source に上のライブラリバージョンが作成される libYaneuraOu-by-gcc.so
      • main.cppをmyMain.cppとコピーして、これをベースに改造したメイン関数を作成
      • make myMain TARGET_CPU=SSE42 でmyMainをコンパイル
        • SSE42は利用しているCPUに
      • LD_LIBRARY_PATH=. ./myMain で実行
    • MATE/YaneuraOu/source に詰将棋エンジンが作成される YaneuraOu-by-gcc
    • MATELIB/YaneuraOu/source 上のライブラリ libYaneuraOu-by-gcc.so
      • main.cppをmyMain.cppとコピーして、これをベースに改造したメイン関数を作成
      • make myMain TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE でmyMainをコンパイル
        • SSE42は利用しているCPUに
      • LD_LIBRARY_PATH=. ./myMain で実行
    • MATE2/tanuki-/source にtanukiさんのgithubのソースから作成した詰将棋エンジンが作成される YaneuraOu-by-gcc
    • MATE2LIB/tanuki-/source にtanukiさんのgithubのソースから作成した詰将棋エンジンが作成される libYaneuraOu-by-gcc.so
      • main.cppをmyMain.cppとコピーして、これをベースに改造したメイン関数を作成
      • make myMain TARGET_CPU=SSE42 YANEURAOU_EDITION=MATE_ENGINE でmyMainをコンパイル
        • SSE42は利用しているCPUに
      • LD_LIBRARY_PATH=. ./myMain で実行

14.4 この章のまとめ

  • 最新ソースでは以前の修正内容では対応出来なくなっていたのを修正
  • パッチファイルとスクリプトファイルを用意して、楽に最新ソースをコンパイル可能にしてみた

15 Ayaneの利用(PythonからYaneuraOuを利用する別の方法)

15.1 関係リンク

15.2 以下の操作を行っている動画


15.3 この章での手順

15.3.1 バーチャル環境作成

cd
virtualenv yaneuraou01

15.3.2 バーチャル環境に入る

cd yaneuraou01/
source bin/activate

15.3.3 python-shogiインストール

pip3 install python-shogi

15.3.4 Ayaneゲットとバックアップ

git clone https://github.com/yaneurao/Ayane.git
tar cvzf Ayane.`date +%Y%m%d`.tgz Ayane/

15.3.5 Ayaneインストール

  • カレントディレクトリで動くように
ln -s Ayane/source/shogi .

15.3.6 前の章で作成したエンジンの実行ファイルのパス確認

  • 実行ファイルが必要です。詰将棋エンジンは評価関数等が不要で楽
  • 通常の将棋エンジンを利用する場合は、評価関数や、定跡ファイルを用意

15.3.7 動作確認

  • 配布サイトの文書のコマンドを試してみる

15.4 この章について

  • Yaneura王さんが作成した、Python用のインターフェイスライブラリを試してみた
  • エンジンを実行ファイルとして、利用するのに便利

16 Ayaneの利用2(PythonからYaneuraOuを利用する別の方法)

  • 前の章の手順だと、Ayaneとpython-shogiの同時利用が不可能であったので、インストール方法を変更することで、同時利用可能に

16.1 関係リンク

16.2 以下の操作を行っている動画


16.2.1 Ayaneインストール

  • カレントディレクトリで動くように以下を行ったが、これ(shogiディレクトリへのリンク)を消して、直接python-shogiのインストール先のディレクトリにAyane.pyをコピーする
  • インストール先のディレクトリ名は、Pythonのバージョンで異るので、異るバージョンの場合は、それにあわせる
cd ~/yaneuraou01/
rm shogi
cp Ayane/source/shogi/Ayane.py lib/python3.8/site-packages/shogi/

16.2.2 Ayaneとpython-shogiを同時に動かせる確認

  • 以下でバーチャル環境に入る
source bin/activate
  • ipythonを起動した後以下を行って、エラーが発生しなければOK
import shogi
import shogi.KIF
import shogi.Ayane as ayane

16.3 この章について

  • 前の章の手順だと、Ayaneとpython-shogiの同時利用が不可能であったので、インストール方法を変更することで、同時利用可能に

17 python-shogiの基本的な使い方

17.1 関係リンク

17.2 以下の操作を行っている動画


17.3 試した手順

  • バーチャル環境のディレクトリに入る
cd ~/yaneuraou01/
  • 以下でバーチャル環境に入る
source bin/activate
  • 必要なものをインポート
import shogi
import shogi.KIF
import shogi.Ayane as ayane
  • kifuファイルの読み込み
  • kifデータを読み込む時、xxxx.kifu の感じで .kifu で終わるファイル名なら utf-8 仮定で読み込まれるようだ(utf-8の場合こういうファイル名に変更)
kif=shogi.KIF.Parser.parse_file("kifu/20201117-02.kif.kifu")[0]
  • 読み込んだ全ての手を表示
for i in kif['moves']:
  print(i)
  • ボード作成
board = shogi.Board()
  • ボード表示
print(board.kif_str())
  • ボードのsfen表示
print(board.sfen())
  • 一手目の内容を表示後、一手目を動かして、盤面とsfen文字を表示
print(kif['moves'][0])
board.push_usi(kif['moves'][0])
print(board.kif_str())
print(board.sfen())

17.4 この章について

  • python-shogiの基本的な使い方を確認した

18 USIを直接使って、内容を確認してみよう1(詰将棋エンジンで、指定の盤面を解いてみる)

18.1 関係リンク

18.2 以下の操作を行っている動画


18.3 試した手順

18.3.1 詰将棋エンジンを起動

  • 詰将棋エンジンを起動する(最近紹介した、githubからダウンロードして、コンパイルするスクリプトを改造し、tournament モードじゃなく normalモードで今日コンパイルしたもの。前の動画のコンパイルの仕方をしたものでも同じ手順で可能)
  • 例えば./20201125_2103/MATE/YaneuraOu/source/ に実行ファイルが有る場合は以下
./20201125_2103/MATE/YaneuraOu/source/YaneuraOu-by-gcc 
  • 将棋エンジンの実行ファイルが入っているディレクトリ名は修正してください。今回はカレントディレクトリに入っているものとします
./YaneuraOu-by-gcc 

18.3.2 USIコマンドを入れていく

  1. 最初はusi
    • 以下を入れてEnterキーを押す
    usi
    
    • 私の環境だと以下がかえってきた
    id name YaneuraOu mate solver Material 5.32 64SSE42
    id author by yaneurao
    option name Threads type spin default 4 min 1 max 512
    option name USI_Hash type spin default 4096 min 1 max 33554432
    option name WriteDebugLog type check default false
    option name NetworkDelay type spin default 120 min 0 max 10000
    option name NetworkDelay2 type spin default 1120 min 0 max 10000
    option name MinimumThinkingTime type spin default 2000 min 1000 max 100000
    option name SlowMover type spin default 100 min 1 max 1000
    option name MaxMovesToDraw type spin default 0 min 0 max 100000
    option name DepthLimit type spin default 0 min 0 max 2147483647
    option name NodesLimit type spin default 0 min 0 max 9223372036854775807
    option name Contempt type spin default 2 min -30000 max 30000
    option name ContemptFromBlack type check default false
    option name EvalDir type string default eval
    option name MorePreciseMatePv type check default true
    usiok
    
  2. 次はisreadyを入れる
    • 以下を入れてEnterキーを押す
    isready
    
    • 私の環境だと以下がかえってきた
    readyok
    
  3. 盤面を設定する
    • 以下を入れてEnterキーを押す
    • positionはsfenでもYaneuraOuさんの詰将棋エンジンは大丈夫なようです
    position lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b Np 0
    
    • 何もかえってきません。
    • デバッグ用に用意されている d コマンドで現状の盤面を確認。(これは他の詰将棋エンジンでは実装されてないかも)
    • 以下を入れてEnter
    d
    
    • 私の環境だと以下がかえってきた
    • 桂馬をと金の横にうてば、詰む状態を作ってある。
    ^香^桂^銀^金^玉^金^銀^桂^香
     口^飛 口 口 口 口 口^角 口
    ^歩^歩^歩^歩 と 口^歩^歩^歩
     口 口 口 口 口 口 口 口 口
     口 口 口 口 口 口 口 口 口
     口 口 口 口 口 口 口 口 口
     歩 歩 歩 歩 歩 歩 歩 歩 歩
     口 角 口 口 口 口 口 飛 口
     香 桂 銀 金 玉 金 銀 口 香
    先手 手駒 :  桂 , 後手 手駒 :  歩
    手番 = 先手
    sfen lnsgkgsnl/1r5b1/pppp+P1ppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGS1L b Np 0
    
  4. 詰将棋を探索させる
    go mate infinite
    
    • 私の環境だと以下がかえってきた
    info string pn 0 dn 100000000 nodes_searched 0
    info  time 1 nodes 0 nps 0 hashfull 0
    checkmate N*4c
    
  5. 平手で探索させて、詰まないことを確認
    • 平手に盤面を設定して、盤面表示
    sfen startpos
    d
    
    • 私の環境だと以下がかえってきた
    ^香^桂^銀^金^玉^金^銀^桂^香
     口^飛 口 口 口 口 口^角 口
    ^歩^歩^歩^歩^歩^歩^歩^歩^歩
     口 口 口 口 口 口 口 口 口
     口 口 口 口 口 口 口 口 口
     口 口 口 口 口 口 口 口 口
     歩 歩 歩 歩 歩 歩 歩 歩 歩
     口 角 口 口 口 口 口 飛 口
     香 桂 銀 金 玉 金 銀 桂 香
    先手 手駒 :  , 後手 手駒 : 
    手番 = 先手
    sfen lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b - 1
    
    • 探索させる
    go mate infinite
    
    • 私の環境だと以下がかえってきた
    info string pn 100000000 dn 0 nodes_searched 0
    checkmate nomate
    

18.4 この章のまとめ

  • USIを取り扱えるGUIを利用せずに直接詰将棋エンジンを操作して、詰将棋を解かせてみた

19 USIを直接使って対戦(GUIを使わず直接エンジンと対話)

19.1 関連リンク

19.2 以下の操作を行っている動画


19.3 試した手順

19.3.1 事前準備

  • YaneuraOuをあからじめコンパイル
  • 評価関数、定跡ファイルを準備
  • ファイル構成は以下で動画で行っている
.
├── YaneuraOu-by-gcc
├── book/
├──── standard_book.db
├──── yaneura_book1.db
├──── yaneura_book3.db
├── eval/
└──── nn.bin

19.3.2 詰将棋エンジンを起動

  • 以下はUbuntu等のLinuxマシンの場合、Windowsなら、将棋エンジンのexeファイルを起動
./YaneuraOu-by-gcc

19.3.3 USIでの操作

  1. 事前準備
    • usiにたいしてはusiokがかえってくればOK
    usi
    
    • isreadyにたいしてはreadyokがかえってくればOK
    • 評価関数ファイル nn.binが必要(デフォルトでは実行ディレクトリにあるevalディレクトリ無いに必要。option等で設定すれば他の場所でもいけるかも)
    • 定跡ファイルも必要かも
    • エラーがでて、readyokが帰ってこなければ、評価関数ファイルと、定跡ファイルを用意しましよう
    isready
    
  2. ゲーム開始
    usinewgame
    
  3. 盤面確認(YaneuraOuの将棋エンジン特有のUSI拡張命令 d を利用
    d
    
  4. 駒の移動1
    • 以下は飛車先の歩をすすめる
    position startpos moves 2g2f
    
  5. 将棋エンジンに手を考えさせる1
    • 動画では以下のgoコマンドで、bestmove 5a4b ponder 2f2eがかえってきてた
    • この時5a4bがベストと将棋エンジンが思考した手で、ponderの後の2f2eが相手の手の予想になります
    go
    
  6. 将棋エンジンに手を考えさせる2(先読みさせる)
    • 思考させた手と予想手を追加したposition命令を入れる
    position startpos moves 2g2f 5a4b 2f2e
    
    • dコマンドで盤面確認するとわかりやすくなる(他の将棋エンジンでは、このUSIコマンドは装備されてないかも)
    d
    
    1. 将棋エンジンの予想手が当たってたとき
      ponderhit
      
    2. 将棋エンジンの予想手が外れてた時
      • stopコマンドで思考を止めて
      stop
      
      • 実際に相手が行った手を入れる(ここでは6i7hとすると)
      position startpos moves 2g2f 5a4b 6i7h
      
      • その後に思考させる(思考させるまえにdコマンドで盤面確認した方がわかりやすい
      go
      
  7. 終了
    • 上の繰り返しを行って最後終わる時は
    quit
    

19.4 この章のまとめ

  • GUIを利用せずに、直接将棋エンジンとUSIプロトコルで対話して、対戦してみた
  • USIの理解をするのに、これをやってみるのは良い感じ

20 検討の時にどのようなUSIコマンドを使うべきか、将棋エンジンの設定について調べてみた

20.2 以下の操作を行っている動画


20.3 説明

20.4 実際にやってみる

  • 最初の定形
usi
setoption name Threads value 2
setoption name ConsiderationMode value true
isready
usinewgame
  • 適当な盤面(最近の私の対戦の1つの局面)
position 4B2Sl/l4g1k1/5pnpp/p2pp1p2/1p7/P2+s2P2/1P3PN1P/3+n2S2/+r1+rPGK2L b Lb2gsn4p 101
go depth 20
  • その時の出力。私のPCでだいたい30秒くらい思考
info depth 1 seldepth 1 score cp -2391 nodes 271 nps 135500 time 2 pv 5a4b+ 6h5i 4i3i
info depth 2 seldepth 3 score cp -2391 nodes 483 nps 241500 time 2 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b
info depth 3 seldepth 4 score cp -513 nodes 676 nps 338000 time 2 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b
info depth 4 seldepth 6 score cp -513 nodes 864 nps 288000 time 3 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b
info depth 5 seldepth 7 score cp -2310 nodes 1554 nps 518000 time 3 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b 3b3c
info depth 6 seldepth 8 score cp -513 nodes 1912 nps 637333 time 3 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b 3b3c 7i6i
info depth 7 seldepth 10 score cp -1207 nodes 3768 nps 753600 time 5 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b 4b3c 5i4i 3i2i
info depth 8 seldepth 9 score cp -1207 nodes 4249 nps 849800 time 5 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b 4b3c 5i4i 3i2i
info depth 9 seldepth 13 score cp -913 nodes 6952 nps 993142 time 7 pv 5a4b+ 6h5i 4i3i 2b2a G*3b 2a1b 4b3c 5i4i 3i2i
info depth 10 seldepth 12 score cp -2164 nodes 13621 nps 1047769 time 13 pv 5a4b+ 6h5i 4i3i G*4h 3i2h 4h3h 2h2g S*1h 1i1h 3h3g 2g3g N*4e 3g2f
info depth 11 seldepth 17 score cp -5278 nodes 65211 nps 869480 time 75 pv 4i3i 4b4a L*4f S*5b 5i6h 4a5a N*2e B*5i 2e3c+ 2b3c N*2e 3c4b 3i2h 5i6h+ 6i6h 7i1i 2h2g
info depth 12 seldepth 19 score cp -5045 nodes 87268 nps 831123 time 105 pv 4i3i 4b4a 5a8d+ 6f5f 5i6h 7i6h N*2e 3c2e 3g2e 9i6i 3i2h
info depth 13 seldepth 16 score cp -4986 nodes 104602 nps 823637 time 127 pv 4i3i 4b4a 5a8d+ 6f5f 8d8e S*5b 5i6h 7i6h 3i2h 2b2a 6i6h
info depth 14 seldepth 15 score cp -4741 nodes 118104 nps 814510 time 145 pv 4i3i 4b4a 5a8d+ 6f5f 8d8e S*5b 5i6h 7i6h 8e5b
info depth 15 seldepth 23 score cp -5741 nodes 1532976 nps 876487 hashfull 592 time 1749 pv 4i3i 4b5b 5i6h 5b5a L*5c 5a4b N*4f 2b2a 4f3d 4b5c 3g2e 3c2e 3h4i 2a3b P*2b G*4a 2b2a+
info depth 16 seldepth 26 score cp -5807 upperbound nodes 2639289 nps 851108 hashfull 820 time 3101 pv 4i3i 4b5b 5i6h 5b5a L*5c 5a4b N*4f 2b2a 4f3d 4b5c 3g2e 3c2e 3h4i 2a3b P*2b G*4a 2b2a+ 3b2a
info depth 16 seldepth 26 score cp -5848 upperbound nodes 3112688 nps 845609 hashfull 890 time 3681 pv 4i3i 4b5b 5i6h 5b5a L*5c 5a4b N*4f 2b2a 4f3d 4b5c 3g2e 3c2e 3h4i 2a3b P*2b G*4a 2b2a+ 3b2a
info depth 16 seldepth 26 score cp -5905 upperbound nodes 3977493 nps 819257 hashfull 951 time 4855 pv 4i3i 4b5b 5i6h
info depth 16 seldepth 26 score cp -5981 upperbound nodes 4851367 nps 828726 hashfull 983 time 5854 pv 4i3i 4b5b 3i2h 6h5i L*1b 1a1b 2a1b+ 2b3b 5a8d+ B*5g 1g1f
info depth 16 seldepth 26 score cp -5920 lowerbound nodes 5580566 nps 835039 hashfull 994 time 6683 pv 4i3i B*5g 3i2i 4b5b L*5c S*3i 2a3b+ 2b3b 5a3c+ 3b3c N*2e 3c4b
info depth 16 seldepth 26 score cp -5927 nodes 5701475 nps 836606 hashfull 996 time 6815 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h N*5f 5h6f 5f6h+ 6i6h 2d6h 3i2i 4d5e
info depth 17 seldepth 24 score cp -5946 upperbound nodes 5867366 nps 838914 hashfull 996 time 6994 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h N*5f 5h6f 5f6h+ 6i6h 2d6h 3i2i 4d5e
info depth 17 seldepth 24 score cp -5965 upperbound nodes 5962177 nps 839979 hashfull 996 time 7098 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h N*5f 5h6f 5f6h+ 6i6h 2d6h 3i2i 4d5e
info depth 17 seldepth 24 score cp -5994 upperbound nodes 6148436 nps 842713 hashfull 997 time 7296 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h N*5f 5h6f 5f6h+ 6i6h 2d6h 3i2i 4d5e
info depth 17 seldepth 24 score cp -6035 upperbound nodes 6667511 nps 846990 hashfull 998 time 7872 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h
info depth 17 seldepth 24 score cp -6092 upperbound nodes 7174905 nps 851317 hashfull 998 time 8428 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h
info depth 17 seldepth 24 score cp -6167 upperbound nodes 8101274 nps 855467 hashfull 1000 time 9470 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h
info depth 17 seldepth 24 score cp -6177 nodes 8583451 nps 858430 hashfull 1000 time 9999 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h 6f6e 3i2h G*2b 4i5g 2b2a 5g6e
info depth 18 seldepth 29 score cp -6196 upperbound nodes 9405168 nps 860569 hashfull 1000 time 10929 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d N*5h
info depth 18 seldepth 29 score cp -6215 upperbound nodes 10363702 nps 862061 hashfull 1000 time 12022 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h N*5f N*1f 2d1d 3g4e 3c4d 2a3b 4d5e 3b4a 5b6b
info depth 18 seldepth 29 score cp -6244 upperbound nodes 11624861 nps 865782 hashfull 1000 time 13427 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h N*5f N*1f
info depth 18 seldepth 29 score cp -6285 upperbound nodes 13213656 nps 870120 hashfull 1000 time 15186 pv 4i3i B*5g L*4h
info depth 18 seldepth 29 score cp -6252 lowerbound nodes 13296528 nps 869850 hashfull 1000 time 15286 pv 4i3i B*5g L*4h
info depth 18 seldepth 29 score cp -6180 nodes 13306369 nps 869867 hashfull 1000 time 15297 pv 4i3i B*5g L*4h 4b5b 5a8d+ 2b2a 8d8e 5b4b 8e4i 6h6i 5i6i 7i6i N*4e 2a2b 3i2h 3c4e 3g4e S*3i 4i3i 6i3i 2h2g
info depth 19 seldepth 25 score cp -6198 upperbound nodes 13474472 nps 870106 hashfull 1000 time 15486 pv 4i3i B*5g L*4h 4b5b 5a8d+ 2b2a 8d8e 5b4b 8e4i 6h6i 5i6i 7i6i N*4e 2a2b 3i2h G*3b
info depth 19 seldepth 25 score cp -6217 upperbound nodes 13947562 nps 870688 hashfull 1000 time 16019 pv 4i3i B*5g L*4h
info depth 19 seldepth 25 score cp -6246 upperbound nodes 14057638 nps 870927 hashfull 1000 time 16141 pv 4i3i B*5g L*4h 4b5b 5a8d+ 2b2a 8d8e 5b4b 8e4i 6h6i 5i6i 7i6i N*4e
info depth 19 seldepth 25 score cp -6222 lowerbound nodes 14619891 nps 871632 hashfull 1000 time 16773 pv 4i3i B*5g L*4h
info depth 19 seldepth 27 score cp -6287 upperbound nodes 15112718 nps 872709 hashfull 1000 time 17317 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h N*5f 3g4e 3c4d 2a3b 4d5e 6h5g
info depth 19 seldepth 29 score cp -6226 lowerbound nodes 17538540 nps 872911 hashfull 1000 time 20092 pv 4i3i B*5g 3i2i 4b5b 3g2e
info depth 19 seldepth 29 score cp -6363 upperbound nodes 18354145 nps 874548 hashfull 1000 time 20987 pv 4i3i B*5g 3i2i 4b5b 3g2e
info depth 19 seldepth 29 score cp -6244 lowerbound nodes 23156655 nps 875322 hashfull 1000 time 26455 pv 4i3i B*5g L*4h
info depth 19 seldepth 29 score cp -6317 nodes 23173727 nps 875272 hashfull 1000 time 26476 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d 2a3b N*5f 3g4e 4d5e N*5h 5f6h+ 5h6f 5e6f 6i6h
info depth 20 seldepth 23 score cp -6336 upperbound nodes 24103006 nps 875199 hashfull 1000 time 27540 pv 4i3i B*5g L*4h
info depth 20 seldepth 23 score cp -6317 lowerbound nodes 24117267 nps 875114 hashfull 1000 time 27559 pv 4i3i B*5g L*4h
info depth 20 seldepth 23 score cp -6288 lowerbound nodes 24122255 nps 875104 hashfull 1000 time 27565 pv 4i3i B*5g L*4h
info depth 20 seldepth 27 score cp -6355 upperbound nodes 24338011 nps 875027 hashfull 1000 time 27814 pv 4i3i B*5g L*4h
info depth 20 seldepth 27 score cp -6301 lowerbound nodes 24353457 nps 874984 hashfull 1000 time 27833 pv 4i3i B*5g L*4h
info depth 20 seldepth 27 score cp -6293 nodes 24694818 nps 875237 hashfull 1000 time 28215 pv 4i3i B*5g L*4h 4b5b 5a3c+ 2b3c N*4i 5g2d+ 5i6h 3c4d 2a3b N*5f 3g4e 4d5e N*5h 5f6h+ 6i6h 2d6h 3i2h S*5i 3b4c 5b4c
bestmove 4i3i ponder B*5g
  • 将棋エンジン停止
quit
  • 次に詰みがある盤面をやってみた。
usi
setoption name Threads value 2
setoption name ConsiderationMode value true
isready
usinewgame
position lnsg3nl/4k1G2/p1pp1pp1p/4p4/7r1/P1P1P1R+B1/1PSPbPP1P/2G6/LN2KGSNL b SP2p 1
go depth 20
  • 一瞬でおわった
  • 詰みがあると 「mate 詰みまでの手数」がエンジンからinfoで送られてくる
info depth 1 seldepth 2 score mate 3 nodes 206 nps 206000 time 1 pv S*5c 5b5a 3b4b
info depth 2 seldepth 4 score mate 3 nodes 479 nps 479000 time 1 pv S*5c 5b5a 3b4b
info depth 3 seldepth 4 score mate 3 nodes 698 nps 349000 time 2 pv S*5c 5b5a 3b4b
info depth 4 seldepth 4 score mate 3 nodes 911 nps 455500 time 2 pv S*5c 5b5a 3b4b
info depth 5 seldepth 4 score mate 3 nodes 1122 nps 561000 time 2 pv S*5c 5b5a 3b4b
info depth 6 seldepth 4 score mate 3 nodes 1345 nps 672500 time 2 pv S*5c 5b5a 3b4b
info depth 7 seldepth 4 score mate 3 nodes 1562 nps 781000 time 2 pv S*5c 5b5a 3b4b

20.5 この章のまとめ

  • 検討したいときに、USIコマンドでどのようなコマンドをYaneuraOuエンジンに送れば良いのかをネット検索した
    • 他の将棋エンジンも、このUSIコマンドをサポートしているか不明。方言あるため
  • 実際に直接USIコマンドで、どの程度時間かかるのかと、どのような情報が将棋エンジンから送られるのかを確認した。
  • ネット対局の棋譜の解析を今は手動で行っているが、今回の調査を元に、自動化したいと考えてます。

21 今後

  • 今後も文書追加していきます。

22 この文書のチェンジログ

  • 2020/07/06 初版
  • 2020/07/08 一括でソースゲットしてコンパイルするプログラム修正、情報URLの修正
  • 2020/07/09 下準備の章追加
  • 2020/07/09 下準備2の章,Positionクラス(盤面クラス)の初期化と表示の章 追加
  • 2020/07/10 詰みチェック,指定の一手を行う,指定の一手を行った後、その手の取り消しの章追加
  • 2020/09/02 Python+cppyyを利用して、PythonからYaneuraouのライブラリの直接利用 の章追加
  • 2020/11/19 最新ソースをダウンロード(2020/11/19)して、トーナメント用、詰将棋用のエンジンコンパイル、それらのライブラリコンパイル用のスクリプトについて の章を作成
  • 2020/11/19 Ayaneの利用(PythonからYaneuraOuを利用する別の方法) の章追加
  • 2020/11/20 Ayaneの利用2(PythonからYaneuraOuを利用する別の方法) の章追加
  • 2020/11/20 python-shogiの基本的な使い方 の章追加
  • 2020/11/25 USIを直接使って、内容を確認してみよう1(詰将棋エンジンで、指定の盤面を解いてみる) の章追加
  • 2020/12/09 USIを直接使って対戦(GUIを使わず直接エンジンと対話) の章追加
  • 2021/01/19 検討の時にどのようなUSIコマンドを使うべきか、将棋エンジンの設定について調べてみた の章追加

著者: NM Max

Created: 2021-01-21 木 06:12

Validate

Umidigi F1 Play充電できない不具合発生

Umidigi F1 Play非常にコスパの良いスマホとして購入したのですが

1年たたずに、充電が接触不良っぽい不具合にて、充電になりにくくなってしまい

接点回復剤

ネットで検索した端子部のはんだ付け再確認を行ったが(はんだごてで再度ハンダ溶かしてみた、半田追加は怖いからおこなわず)復活せず

しょうがないので、今日、Googleが特売しているPixcel3a XLを購入した

届くのは5/4らしいかなり先

もちょっと待って、Pixcel3aにしとけば良かった。

結局高くつくことに

5Gに移行は、かなり先にすることにした

追記)2020/8  アリババの国際バージョンのショップに、F1Play用の充電基盤があったので、購入して交換したら、復活した。コロナ騒ぎもあったため、注文してから届くまで1ヶ月以上かかった。予備も含めて2個購入して、ギフト券割引で1000から2000の間の金額だったと思う。

分解に特殊なネジが必要なのだが、0.9mmのマイナスドライバーでも開けることが可能だった

外したネジの保管には気をつけましょう、私は特殊ネジの1つを紛失してしまった。

easyAI入門

easyAI入門

1 概要

  • Negamax(αβ法の一種 αβ法はMINMAX法(全手検索)と同じ結果を少ない探索で可能なアルゴリズム)のフレームワーク
  • Pythonベース
  • MITライセンス

2 リンク

3 easyAIのインストール

3.1 以下の操作を行っている動画


3.2 easyAIのインストール 手順

3.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

3.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

3.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/

3.2.4 easyAIのインストール

sudo pip3 install easyAI

3.2.5 easyAIのgithubのダウンロード

mkdir easyAI
cd easyAI
git clone https://github.com/Zulko/easyAI.git

3.2.6 easyAIのサンプルプログラムを動かしてみる

python3 easyAI/games/GameOfBones.py

3.3 この章のまとめ

  • easyAIをダウンロードし動かしてみた

4 コネクトX(Xは数字)を作って動かしてみる

4.1 以下の操作を行っている動画


4.2 コネクト4を作って動かしてみる の手順

4.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

4.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

4.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/

4.2.4 easyAIのインストール

  • 起動しなおす毎に消えてるので、再度インストール
sudo pip3 install easyAI

4.2.5 コネクトX用のディレクトリ掘り、ファイルを作成

mkdir -p easyAI/Connectx
cd  easyAI/Connectx

4.2.6 Connectx.pyファイルを以下の内容で作成

  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
  • Connect X の処理を行うクラス
  • BWIDTHで盤の幅
  • BHEIGHTで盤の高さ
  • NEEDLENで勝利条件の長さ(4なら4個以上同じ陣営のコマを縦横あるいは斜めに連続で並べたら勝ち)
BWIDTH=7                    # board width
BHEIGHT=6                   # board height
NEEDLEN=4                    # How many must be arranged to win

class Connectx(object):

    def __init__(self):
	self.color=[[2] * BWIDTH for i in range(BHEIGHT)]
	self.v=[" O "," X "," . "]
	self.turn=0
	self.history=[]
	self.isEnd=False
	self.winner=2

    def clear(self, stone=True):
	self.color=[[2] * BWIDTH for i in range(BHEIGHT)]
	self.turn=0
	self.history.clear()
	self.isEnd=False
	self.winner=2

    def showboard(self):
	print("     ",end="")
	for x in range(BWIDTH):
	    print("{0:2d}".format(x),end=" ")
	print()
	for y in range(BHEIGHT):
	    print("{0:2d}".format(y)+" | ",end="")
	    for x in range(BWIDTH):
		c=self.color[y][x]
		print(self.v[c] ,end="")  
	    print(" | "+"{0:2d}".format(y))
	print("     ",end="")
	for x in range(BWIDTH):
	    print("{0:2d}".format(x),end=" ")
	print()
	print("isEnd : "+str(self.isEnd))
	if self.isEnd:
	    print("game is over winner is "+str(self.winner))
	print(self.history)
	print()

    def legal(self, v):
	ans=False
	if self.color[0][v]==2:
	    ans=True
	return ans

    def isValidXY(self ,xy):
	v,y=xy
	return (v>=0 and v<BWIDTH and y>=0 and y<BHEIGHT)

    def getColor(self,xy):
	ans=3
	if self.isValidXY(xy):
	    v,y=xy
	    ans=self.color[y][v]
	return ans

    def check(self):
	ans=False
	for x in range(BWIDTH):
	    if ans:
		break
	    for y in reversed(range(BHEIGHT)):
		if ans:
		    break
		c=self.color[y][x]
		if c<2:
		    #print(">>>***************",end="")
		    #print((x,y))
		    if self.bcheck((x,y)):
			ans=True
			break
	return ans

    def bcheck(self,xy):
	x,y=xy
	ans=False
	c=self.color[y][x]
	if c<2:
	    for dx in [1,0,-1]:
		for dy in [1,0,-1]:
		    #print("*****(dx,dy)",end=" ")
		    #print((dx,dy))
		    if (not (dx==0 and dy==0))  and (not ans):
			c1=1
			for i in range(1,NEEDLEN):
			    nx=x+dx*i
			    ny=y+dy*i
			    #print("(nx,ny)",end=" ")
			    #print((nx,ny))
			    if self.isValidXY((nx,ny)):
				nc=self.getColor((nx,ny))
				if nc==c:
				    #print((nx,ny),end=" ")
				    c1+=1
				    #print(c1)
				    if c1>=NEEDLEN:
					#print("*** TRUE")
					ans=True
					break
			    else:
				break
	return ans

    def getEnableVs(self):
	ans=[]
	for i in range(BWIDTH):
	    if self.color[0][i]==2:
		ans.append(i)
	return ans

    def checkEnd(self):
	evs=self.getEnableVs()
	ans=len(evs)>0 or self.isEnd
	if ans:
	    self.isEnd=True
	return ans

    def play(self,v):
	ans=False
	if self.legal(v):
	    ans=True
	    for y in reversed(range(BHEIGHT)):
		if self.color[y][v]==2:
		    self.color[y][v]=self.turn
		    self.history.append([v,y])
		    #print(self.check())
		    if not self.isEnd:
			if self.check():
			    self.isEnd=True
			    self.winner=self.turn
			    # print("game is over winner is "+str(self.winner))
			    # print(self.history)
		    self.turn=int(self.turn==0)
		    break
	return ans

    def unmake_move(self, move): # optional method (speeds up the AI)
	if len(self.history)>0:
	    x,y=self.history[-1]
	    self.color[y][x]=2
	    #for i in range(BHEIGHT):
	    #    if self.color[y][i]<2:
	    #        self.color[y][i]=2
	    #        break
	    self.history=self.history[:-1]
	    self.turn=int(self.turn==0)
	    self.isEnd=False
	    self.winner=2

4.2.7 ConnectxEasyAI.py ファイルを以下の内容で作成

  • easyAI用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *

class ConnectxEasyAI( TwoPlayersGame ):
    def __init__(self, players):
	self.board=Connectx()
	self.players = players
	self.nplayer = 1

    def possible_moves(self):
	return self.board.getEnableVs()

    def make_move(self, move):
	self.board.play(move)

    def unmake_move(self, move): # optional method (speeds up the AI)
	self.board.unmake_move(move)

    def lose(self):
	ans=self.board.check()
	enemy=int(self.board.turn==0)
	return self.board.winner==enemy

    def is_over(self):
	self.board.check()
	return self.board.isEnd;

    def show(self):
	self.board.showboard()

    def scoring(self):
	return -100 if self.lose() else 0

if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()

4.2.8 ConnectxEasyAI1.py ファイルを以下の内容で作成

  • 先手人間、後手AI(読み深さ6)戦用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI


if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()

4.2.9 ConnectxEasyAI2.py ファイルを以下の内容で作成

  • 総当りで調べる用(私のマシンで半日動かしたが、8->12手までしか探索できず。時間をかければ先手必勝の結果が得られると思われる)
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI


if __name__ == "__main__":

    from easyAI import id_solve, Human_Player, AI_Player
    from easyAI.AI import TT

    #r, d, m = id_solve(ConnectxEasyAI, range(NEEDLEN*2, BWIDTH*BHEIGHT+1), win_score = 100)
    #r, d, m = id_solve(ConnectxEasyAI, range(13, BWIDTH*BHEIGHT+1,2), win_score = 100)
    r, d, m = id_solve(ConnectxEasyAI, range(13, BWIDTH*BHEIGHT+1), win_score = 100)
    print(r, d, m)  # see the docs.

4.2.10 ConnectxEasyAI3.py ファイルを以下の内容で作成

  • 対人対人戦用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI

if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    #ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()
    ConnectxEasyAI( [Human_Player(),Human_Player()]).play()

4.2.11 対AI戦を行ってみる

  • 以下のコマンドを(docker内)ターミナルで実行
python3 ConnectxEasyAI1.py 

4.2.12 人対人戦を行ってみる

  • 以下のコマンドを(docker内)ターミナルで実行
python3 ConnectxEasyAI3.py 

4.2.13 人対人戦を行ってみる

  • 探索を行ってみる(時間かかりすぎるので、最後まで未調査、調査した方いたら結果を教えてもらえると嬉しい)
  • 半日やって8から12まで終わり、13手の処理中でした
python3 ConnectxEasyAI2.py 

4.3 この章のまとめ

  • easyAIをダウンロードし動かしてみた

5 今後

  • 今後も文書追加していきます。

6 この文書のチェンジログ

  • 2020/04/02 初版

著者: NM Max

Created: 2020-04-04 土 20:52

Validate

Rails6 入門

Rails6 入門

目次

1 概要

2 リンク

3 初めてのプロジェクト作成

3.1 以下の操作を行っている動画


3.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails
# or
./Start.sh

3.3 test01というプロジェクト開始

  • プロジェクトを作成し、test01内に移動
rails new test01
cd test01
bundle install

3.4 railsサーバーを起動して、ブラウザで確認

  • 以下のコマンドを実行し、ブラウザでhttp://localhost:3000を開く。ウエルカムページが表示される。
rails server -b 0.0.0.0

3.5 この章のまとめ

  • 空のプロジェクトを作成し、ブラウザで確認した

4 scaffoldを利用したモデルの作成

4.1 以下の操作を行っている動画


4.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails
# or
./Start.sh

4.3 test02というプロジェクト開始

  • プロジェクトを作成し、test02内に移動
rails new test02
cd test02
bundle install

4.4 test02で、scaffoldコマンドを利用して、モデルを作成

  • unit
rails generate scaffold  Unit name:string strength:decimal hitPoints:decimal agility:decimal

4.5 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0
  • 追加したり、変更したり、削除したりしてみる

4.6 この章のまとめ

  • 楽々自動コマンドscaffoldを利用して、モデルと、それを操作できるインターフェイスを自動生成
  • 生成した物を試してみる

5 scaffoldのカスタマイズ

  • i18n_generatorsを利用した方法の解説ページのとおりにやっても、Railsのバージョンが古いためか、上手く日本語化できなかったので、Rails6でも日本語化できるようにカスタマイズしてみた。
  • 多分もっと良いカスタマイズ方法あるとは思うが、とりあえず日本語化には成功した設定方法になります。

5.1 以下の操作を行っている動画


5.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails
# or
./Start.sh

5.3 test03というプロジェクト開始

  • プロジェクトを作成し、test02内に移動
rails new test03
cd test03
bundle install

5.4 gitの初期化のファイル init_git.sh を用意

  • 以下の内容の ../init_git.sh を準備
#!/bin/sh
git config --global user.name "NM Max"
git config --global user.email xxx@xxx.xx
  • 実行権限を与える
chmod +x ../init_git.sh
  • 実行
../init_git.sh

5.5 gitでバージョン管理する為の準備

  • ワーキングツリー空のコミットを最初に
  • プロジェクト作成直後のコミットを次に
git init
git commit --allow-empty -m "first commit"
git add -A
git commit --allow-empty -m "プロジェクト作成直後"

5.6 scaffold日本語化に関するパッケージをGemfileに追加

  • 以下を追加
gem 'i18n_generators'
gem 'rails-i18n'
  • 以下を実行
bundle install

5.7 日本語関係の設定をconfig/application.rbに

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Test02
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    config.time_zone = 'Asia/Tokyo'
    config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
    config.i18n.default_locale = :ja 

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

5.8 scaffold用のカスタマイズテンプレートを用意

  • rake rails:templates:copy でエラーになるため、ベースのテンプレートファイルをマニュアルでコピー(Rails6でもできるのかな?他のサイトの方法?)して修正

5.8.1 以下のコマンドでscaffoldオリジナルのテンプレートファイルを探す

find /usr/local/bundle/ | grep scaf

5.8.2 scaffoldオリジナルのテンプレートファイルをlib/templates/erb/scaffold/にコピー

mkdir -p lib/templates/erb/scaffold/
cp /usr/local/bundle/gems/railties-6.0.2.1/lib/rails/generators/erb/scaffold/templates/* lib/templates/erb/scaffold/

5.8.3 lib/templates/erb/scaffold/edit.html.erb.tt を以下に修正

<h1><%%= t('usual.edit') %> <%%= <%= class_name %>.model_name.human %></h1>

<%%= render 'form', <%= singular_table_name %>: @<%= singular_table_name %> %>

<%%= link_to t('usual.show'), @<%= singular_table_name %> %> |
<%%= link_to t('usual.back'), <%= index_helper %>_path %>

5.8.4 lib/templates/erb/scaffold/index.html.erb.tt を以下に修正

<p id="notice"><%%= notice %></p>

<h1><%%= <%= class_name %>.model_name.human %></h1>

<table>
  <thead>
    <tr>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
  <th><%%= <%= class_name %>.human_attribute_name( :<%= attribute.name %> ) %></th>
<% end -%>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
      <tr>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
	<td><%%= <%= singular_table_name %>.<%= attribute.column_name %> %></td>
<% end -%>
	<td><%%= link_to t('usual.show'), <%= model_resource_name %> %></td>
	<td><%%= link_to t('usual.edit'), edit_<%= singular_route_name %>_path(<%= singular_table_name %>) %></td>
	<td><%%= link_to t('usual.delete'), <%= model_resource_name %>, method: :delete, data: { confirm: t('usual.confirm.delete') } %></td>
      </tr>
    <%% end %>
  </tbody>
</table>

<br>

<%%= link_to "#{t('usual.new')} <%= singular_table_name.titleize %>", new_<%= singular_route_name %>_path %>

5.8.5 lib/templates/erb/scaffold/new.html.erb.tt を以下に修正

<h1><%%= t('usual.new') %><%%= <%= class_name %>.model_name.human %></h1>

<%%= render 'form', <%= singular_table_name %>: @<%= singular_table_name %> %>

<%%= link_to t('usual.back'), <%= index_helper %>_path %>

5.8.6 lib/templates/erb/scaffold/show.html.erb.tt を以下に修正

<p id="notice"><%%= notice %></p>

<% attributes.reject(&:password_digest?).each do |attribute| -%>
<p>
  <strong>
    <%%= label :<%= singular_table_name %>, :<%= attribute.name %> %>:
  </strong>
<% if attribute.attachment? -%>
  <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
<% elsif attribute.attachments? -%>
  <%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
    <div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
  <%% end %>
<% else -%>
  <%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
<% end -%>
</p>

<% end -%>
<%%= link_to t('usual.edit'), edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
<%%= link_to t('usual.back'), <%= index_helper %>_path %>

5.9 config/locales/usual_ja.yml を以下で作成

ja:
  usual:
    index: 一覧
    show: 詳細
    new: 新規
    edit: 編集
    delete: 削除
    confirm:
      delete: 削除しますが、よろしいですか?
    back: 戻る
    create:
      success: "%{name}を作成しました"
      failed: 作成に失敗しました
    update:
      success: "%{name}を更新しました"
      failed: 更新に失敗しました
    destroy:
      success: "%{name}を削除しました"
      failed: 削除に失敗しました
    form:
      error_explanation:
        title: "%{count}件のエラーがあります"

5.10 config/locales/usual_en.yml を以下で作成

ja:
  usual:
    index: index
    show: show
    new: new
    edit: edit
    delete: delete
    confirm:
      delete: Are you sure?
    back: back
    create:
      success: "%{name} was created successfully"
      failed: Creation failed
    update:
      success: "%{name} was updated successfully"
      failed: Update failed
    destroy:
      success: "%{name} was deleted successfully"
      failed: Delete failed
    form:
      error_explanation:
        title: "There are %{count} errors"

5.11 test03で、scaffoldコマンドを利用して、モデルを作成

  • Unitモデル作成
rails generate scaffold  Unit name:string strength:decimal hitPoints:decimal agility:decimal
rails db:migrate
  • 日本語用ファイル生成
rails g i18n ja
  • コミットしておく
git add -A
git commit --allow-empty -m "Unitモデル作成"

5.12 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0
  • 追加したり、変更したり、削除したりしてみる

5.13 この章のまとめ

  • 楽々自動コマンドscaffoldをカスタマイズして、メニューの日本語化の一例

6 Action Textを試してみる

  • この章から新しいDocker Imageを利用していきます。(改良バージョン 作り方https://www.youtube.com/watch?v=naQWBg6G1wM)
  • 画像とかを複数いれたリッチテキストを扱える新機能Action Textを使ってみました。

6.1 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

6.2 作業手順

6.2.1 起動後、改良バージョンで標準で含まれているtest000プロジェクトに移動

cd test000

6.2.2 Gemfileに以下を追加

gem 'mini_magick'
gem 'image_processing'

6.2.3 bundle install を実行

bundle install 

6.2.4 rails action_text:install を実行

rails action_text:install
rails db:migrate

6.2.5 t0モデルをscaffoldで作成

rails g scaffold t0 name:string

6.2.6 ./app/views/active_storage/blobs/_blob.html.erb を以下に修正

  • 以下が修正後
  • mini_magickの指定の方法がこれらしい
... 省略
  <%= image_tag blob.representation(resize: local_assigns[:in_gallery] ? "800x600" : "1024x768" ) %>
... 省略

6.2.7 ./app/models/t0.rb を以下に修正

class T0 < ApplicationRecord
  has_rich_text :content
end

6.2.8 ./app/controllers/t0s_controller.rb を以下に修正

  • :content を追加
... 省略
    # Only allow a list of trusted parameters through.
    def t0_params
      params.require(:t0).permit(:name,:content)
    end
end

6.2.9 ./app/views/t0s/_form.html.erb を以下に修正

<%= form_with(model: t0, local: true) do |form| %>
  <% if t0.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(t0.errors.count, "error") %> prohibited this t0 from being saved:</h2>

      <ul>
        <% t0.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

6.2.10 ./app/views/t0s/show.html.erb を以下に修正

<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @t0.name %>
</p>
<p>
  <strong>Content:</strong>
  <%= @t0.content %>
</p>

<%= link_to 'Edit', edit_t0_path(@t0) %> |
<%= link_to 'Back', t0s_path %>

6.2.11 migrate

rails db:migrate

6.2.12 動作確認

rails server -b 0.0.0.0

6.3 この章のまとめ

  • Rails 6から標準装備になった、Action Textを試してみた
  • こんなのが非常に簡単に作れちゃうRails凄い!

7 Action Textを試してみる2

  • Docker Imageを利用して動かします。(改良バージョン 作り方https://www.youtube.com/watch?v=naQWBg6G1wM)
  • 画像とかを複数いれたリッチテキストを扱える新機能Action Textを使ってみました。
  • 前章と同じだけど、mini_magickではなく、image_processingをGemfileに、そうするとblobの修正不要でした。

7.1 以下の操作を行っている動画


7.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

7.3 作業手順

7.3.1 起動後、改良バージョンで標準で含まれているtest000プロジェクトに移動

cd test000

7.3.2 Gemfileに以下を追加

  • 前の章と違い、Gemfileにmini_magickをいれません。
  • rails action_text:install も行わない
  • ./app/views/active_storage/blobs/_blob.html.erb も修正しません。
gem 'image_processing'

7.3.3 bundle install を実行

  • 前の章と同じ
bundle install 

7.3.4 t0モデルをscaffoldで作成

  • 前の章と同じ
rails g scaffold t0 name:string

7.3.5 ./app/models/t0.rb を以下に修正

  • 前の章と同じ
class T0 < ApplicationRecord
  has_rich_text :content
end

7.3.6 ./app/controllers/t0s_controller.rb を以下に修正

  • 前の章と同じ
  • :content を追加
... 省略
    # Only allow a list of trusted parameters through.
    def t0_params
      params.require(:t0).permit(:name,:content)
    end
end

7.3.7 ./app/views/t0s/_form.html.erb を以下に修正

  • 前の章と同じ
<%= form_with(model: t0, local: true) do |form| %>
  <% if t0.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(t0.errors.count, "error") %> prohibited this t0 from being saved:</h2>

      <ul>
        <% t0.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

7.3.8 ./app/views/t0s/show.html.erb を以下に修正

  • 前の章と同じ
<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @t0.name %>
</p>
<p>
  <strong>Content:</strong>
  <%= @t0.content %>
</p>

<%= link_to 'Edit', edit_t0_path(@t0) %> |
<%= link_to 'Back', t0s_path %>

7.3.9 migrate

rails db:migrate

7.3.10 動作確認

rails server -b 0.0.0.0

7.4 この章のまとめ

  • mini_magickではなく、image_processingがデフォルトになってた情報をみて、試してみたら、blobsの修正なくいけた
  • 前章より修正部分少なく、より豊富な機能を実現(画像おそらく固定サイズではなくなる)

8 ちゃちゃっと日記を作ってみる

  • Action Textを利用して、ちゃちゃっと日記を作ってみる
  • rails-i18n,i18n_generatorsを使って、日本語化
  • 操作画面はrails_adminを活用して作成

8.1 以下の操作を行っている動画


8.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

8.3 作業手順

8.3.1 起動後、改良バージョンで標準で含まれているtest000プロジェクトに移動

cd test000

8.3.2 Gemfileに以下を追加

  • 前の章と違い、Gemfileにmini_magickをいれません。
  • rails action_text:install も行わない
  • ./app/views/active_storage/blobs/_blob.html.erb も修正しません。
gem 'image_processing'
gem 'rails_admin'
gem 'rails-i18n', '~> 6.0.0' # For 6.0.0 or higher
gem 'i18n_generators'

8.3.3 bundle install を実行

  • 前の章と同じ
bundle install 

8.3.4 dianryモデルを作成

rails g scaffold dialy::post date:datetime title:string

8.3.5 ./app/models/dialy/post.rb を以下に修正

class Dialy::Post < ApplicationRecord
  has_rich_text :content
end

8.3.6 ./app/controllers/dialy/posts_controller.rb を以下に修正

  • :content を追加
... 省略
    # Only allow a list of trusted parameters through.
    def dialy_post_params
      params.require(:dialy_post).permit(:date, :title, :content)
    end
end

8.3.7 app/views/dialy/posts/_form.html.erb を以下に修正

  • scaffoldで作成したものを使わないなら不要
  • 以下に:content用の部分を追加
... 省略
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

8.3.8 app/views/dialy/posts/show.html.erb を以下に修正

  • scaffoldで作成したものを使わないなら不要
  • 以下に:content用の部分を追加
<p id="notice"><%= notice %></p>

<p>
  <strong>Date:</strong>
  <%= @dialy_post.date %>
</p>

<p>
  <strong>Title:</strong>
  <%= @dialy_post.title %>
</p>

<p>
  <strong>Content:</strong>
  <%= @dialy_post.content %>
</p>

<%= link_to 'Edit', edit_dialy_post_path(@dialy_post) %> |
<%= link_to 'Back', dialy_posts_path %>

8.3.9 日本語設定用ファイルをconfig/locales/に入れる

wget https://gist.githubusercontent.com/mshibuya/1662352/raw/3f001f00f440af613d7d307cbf2f07c3babe2068/rails_admin.ja.yml
#wget https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml
mv -i *ja.yml config/locales/

8.3.10 config/application.rbを修正

  • 日本語関係、タイムゾーン設定
...省略
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
  end
end

8.3.11 rails_adminをインストール

  • 途中で聞かれる名前は rails_admin と入力しエンター
rails g rails_admin:install

8.3.12 i18n_generatorsで日本語用ファイル生成

  • config/locales/translation_ja.yml を確認
rails db:migrate
rails g i18n ja
# rails g i18n_locale ja
# rails g i18n_translation ja

8.4 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0

8.5 この章のまとめ

  • 日記を作ってみた
  • 操作画面をrails_adminでも作成してみたが、デフォルト設定だと、画像関係追加のボタンもなく、正常に画像が表示されない(調査継続、上手くいく方法みつけたらまた文書と動画にします)

9 一旦scaffoldで生成したモデルを破壊し、作り直す手順

  • 普通に再度scaffoldしなおすと、The name ‘モデル名’ is either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again と怒られる
  • rails destroy scaffold モデル名してからやり直すと、エラーなく再度生成可能

9.1 以下の操作を行っている動画


9.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

9.3 作業手順

9.3.1 起動後、改良バージョンで標準で含まれているtest000プロジェクトに移動

cd test000

9.3.2 bundle install を実行

bundle install 

9.3.3 dianryモデルを作成

rails g scaffold Dialy::Post date:datetime title:string
  • 再度同じ命令を実行するとエラーになる(以下が例)
Running via Spring preloader in process 1124
      invoke  active_record
The name 'Dialy::Post' is either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again.

9.3.4 dianryモデルを破壊

rails destroy scaffold dialy::post
  • 上を実行してから以下を実行
rails g scaffold dialy::post date:datetime title:string
  • 成功しました!

9.4 この章のまとめ

  • 一旦scaffoldで生成したモデルを破壊し、作り直す手順
    • (rails destroy scaffold モデル名 を実行してから再度生成コマンド実行)

10 mailアドレスでログイン出来る機能をつけてみる(devise)

  • https://github.com/heartcombo/devise
  • rails-i18n,i18n_generatorsを使って、日本語化
  • 最低限の機能のみ(確認メール無し)
  • 前やった日記アプリを改造して行います。
  • 以下の手順は日記アプリを作る手順も含まれています。

10.1 以下の操作を行っている動画


10.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

10.3 作業手順

10.3.1 起動後、改良バージョンで標準で含まれているtest000プロジェクトに移動

cd test000

10.3.2 Gemfileに以下を追加

  • 前の章と違い、Gemfileにmini_magickをいれません。
  • rails action_text:install も行わない
  • ./app/views/active_storage/blobs/_blob.html.erb も修正しません。
gem 'image_processing'
gem 'rails_admin'
gem 'rails-i18n', '~> 6.0.0' # For 6.0.0 or higher
gem 'i18n_generators'
gem 'devise'

10.3.3 bundle install を実行

  • 前の章と同じ
bundle install 

10.3.4 dianryモデルを作成

rails g scaffold dialy::post date:datetime title:string

10.3.5 ./app/models/dialy/post.rb を以下に修正

class Dialy::Post < ApplicationRecord
  has_rich_text :content
end

10.3.6 ./app/controllers/dialy/posts_controller.rb を以下に修正

  • :content を追加
... 省略
    # Only allow a list of trusted parameters through.
    def dialy_post_params
      params.require(:dialy_post).permit(:date, :title, :content)
    end
end

10.3.7 app/views/dialy/posts/_form.html.erb を以下に修正

  • scaffoldで作成したものを使わないなら不要
  • 以下に:content用の部分を追加
... 省略
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

10.3.8 app/views/dialy/posts/show.html.erb を以下に修正

  • scaffoldで作成したものを使わないなら不要
  • 以下に:content用の部分を追加
<p id="notice"><%= notice %></p>

<p>
  <strong>Date:</strong>
  <%= @dialy_post.date %>
</p>

<p>
  <strong>Title:</strong>
  <%= @dialy_post.title %>
</p>

<p>
  <strong>Content:</strong>
  <%= @dialy_post.content %>
</p>

<%= link_to 'Edit', edit_dialy_post_path(@dialy_post) %> |
<%= link_to 'Back', dialy_posts_path %>

10.3.9 日本語設定用ファイルをconfig/locales/に入れる

wget https://gist.githubusercontent.com/mshibuya/1662352/raw/3f001f00f440af613d7d307cbf2f07c3babe2068/rails_admin.ja.yml
#wget https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml
mv -i *ja.yml config/locales/

10.3.10 config/application.rbを修正

  • 日本語関係、タイムゾーン設定
...省略
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
  end
end

10.3.11 i18n_generatorsで日本語用ファイル生成

  • config/locales/translation_ja.yml を確認
rails db:migrate
rails g i18n ja
# rails g i18n_locale ja
# rails g i18n_translation ja

10.4 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0

10.4.1 deviseのインストール


  1. rails generate devise:install
    bundle exec rails g devise:views
    rails generate devise User
    rails db:migrate
    
  2. app/controllers/application_controller.rb に以下に
    class ApplicationController < ActionController::Base
      before_action :authenticate_user!
    end
    
  3. config/routes.rbに以下を追加
    devise_scope :user do
      get 'sign_in', to: 'devise/sessions#new'
      get 'sign_out', to: 'devise/sessions#destroy'
    end
    

10.5 railsサーバーを起動して、ブラウザで確認2

rails server -b 0.0.0.0

10.6 この章のまとめ

  • deviseパッケージを利用してメールアドレスでログイン出来る機能を追加
  • 確認メールを行う設定等は今後にやってみたいと考えてます

11 Rails6 + Administrate(管理画面生成)+ Action Text

11.1 以下の操作を行っている動画


11.2 以前作成したDocker imageを動かす

docker run -it --rm -p 22:22 -p 3000:3000 -v /work/myrails:/home/user/C myrails3
# or
./Start.sh

11.3 作業手順

11.3.1 起動後、前の章のプロジェクトディレクトリを作業用のディレクトリにコピーし、作成したディレクトリ内にはいる

  • 前の章のプロジェクトディレクトリをtest000-2-adminstrateにコピー
  • 使い慣れたホスト側のツールを使ってもOK
  • プロジェクト内部に移動し、必用なパッケージインストール
mkdir -p C/Youtube/000
cd C/Youtube/000
cp -r ~/test000 test000-2-adminstrate
cd test000-2-adminstrate
bundle install

11.3.2 Gitの初期設定

  • Gitの初期設定、名前を NM Max ,メールを架空の xxx@xxx.xx にしている、適切な名前とメールアドレスに
git config --global user.name "NM Max"
git config --global user.email xxx@xxx.xx
  • 最初のコミット(空)
git init
git commit --allow-empty -m "first commit"
  • 最初のコミット
git add -A
git commit -m "プロジェクト生成直後"

11.3.3 MyPostモデル追加

rails g scaffold MyPost title:string
rails db:migrate
  • gitでコミットしておく
git add -A
git commit -m "MyPost生成直後"

11.3.4 ./app/models/my_post.rb を以下に修正

class MyPost < ApplicationRecord
  has_rich_text :content
end

11.3.5 ./app/controllers/my_posts_controller.rb を以下に修正

  • :content を追加
... 省略
    # Only allow a list of trusted parameters through.
    def my_post_params
      params.require(:my_post).permit(:title, :content)
    end
end

11.3.6 ./app/views/my_posts/show.html.erb を以下に修正

<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @my_post.title %>
</p>

<p>
  <strong>Content:</strong>
  <%= @my_post.content %>
</p>

<%= link_to 'Edit', edit_my_post_path(@my_post) %> |
<%= link_to 'Back', my_posts_path %>

11.3.7 app/views/my_posts/_form.html.erb を以下に変更

<%= form_with(model: my_post, local: true) do |form| %>
  <% if my_post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(my_post.errors.count, "error") %> prohibited this my_post from being saved:</h2>

      <ul>
	<% my_post.errors.full_messages.each do |message| %>
	  <li><%= message %></li>
	<% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

11.3.8 Gemfileに 以下を追加

gem 'image_processing'
  • 以下を実行
bundle install
  • gitでコミットしておく
git add -A
git commit -m "MyPost設定"

11.4 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0

11.4.1 Administrateを入れる

  1. Gemfileに 以下を追加
    # gem 'image_processing'
    # gem 'rails_admin'
    gem 'rails-i18n', '~> 6.0.0' # For 6.0.0 or higher
    gem 'i18n_generators'
    gem 'devise'
    
    gem "administrate" 
    gem 'administrate-field-active_storage'
    gem 'mini_magick'
    gem 'administrate-field-trix'
    gem 'trix-rails', require: 'trix'
    
    bundle install
    rails generate administrate:install
    rails g administrate:field rich_text_area
    #rails generate administrate:assets
    

11.4.2 ./app/views/fields/rich_text_area_field/_form.html.erb を以下に変更

<div class="field-unit__label">
  <%= f.label field.attribute %>
</div>
<div class="field-unit__field">
  <%= f.rich_text_area(field.attribute) %>
</div>

11.4.3 app/assets/config/manifest.js に以下を追加

//= link administrate/application.css
//= link administrate/application.js
//= link administrate-field-trix/application.css

11.4.4 https://github.com/thoughtbot/administrate/wiki/Rails-6-&-Webpacker に従い修正

  1. yarn add flatpickr を実行
    yarn add flatpickr
    
  2. app/javascript/packs/administrate.js を作成
    // This file is automatically compiled by Webpack, along with any other files
    // present in this directory. You're encouraged to place your actual application logic in
    // a relevant structure within app/javascript and only use these pack files to reference
    // that code so it'll be compiled.
    
    require("@rails/ujs").start()
    require("turbolinks").start()
    
    // The next line you only need if you want ActiveStorage support
    require("@rails/activestorage").start()
    
    // The next line you only need if you need channels in administrate
    require("channels")
    
    // The next two lines you only need if you want ActionText support
    require("trix")
    require("@rails/actiontext")
    
    require("../administrate/index")
    
  3. app/javascript/administrate/index.js を作成
    • デイレクトリ作成
    mkdir -p app/javascript/administrate
    
    • app/javascript/administrate/index.js を以下で作成
    import '../components/table'
    import '../components/date_time_picker'
    
  4. app/javascript/components/date_time_picker.js を作成
    mkdir -p app/javascript/components
    
    • 以下の内容の app/javascript/components/date_time_picker.js を作成
    import flatpickr from 'flatpickr'
    
    function bindDateTimePickers() {
      [...document.querySelectorAll('[data-type="time"]')].forEach((time) => {
        flatpickr(time, {
          enableTime: true,
          enableSeconds: true,
          noCalendar: true,
          altInput: true,
          altFormat: ' h:i:S K',
          dateFormat: 'H:i:S' // H:i
        })
      });
    
      [...document.querySelectorAll('[data-type="datetime"]')].forEach((time) => {
        flatpickr(time, {
          enableTime: true,
          altInput: true,
          altFormat: 'F J (D), Y - h:i:S K',
          dateFormat: 'Z' // Y-m-d H:i
        })
      })
    }
    
    document.addEventListener("turbolinks:load", function () {
      bindDateTimePickers()
    })
    
  5. app/javascript/components/table.js を作成
    mkdir -p app/javascript/components
    
    • 以下の内容の app/javascript/components/table.js を作成
    function bindTableLinks() {
      const keycodes = { space: 32, enter: 13 }
    
      function visitDataUrl(event) {
        /** @type {HTMLTableRowElement} */
        const target = event.target.classList.contains("js-table-row")
          ? event.target
          : event.target.closest('.js-table-row')
    
        if (!target) {
          return
        }
    
        if (event.type === "click" ||
            event.keyCode === keycodes.space ||
            event.keyCode === keycodes.enter) {
    
          if (event.target.href) {
            return
          }
    
          const dataUrl = target.getAttribute("data-url")
          const selection = window.getSelection().toString()
          if (selection.length === 0 && dataUrl) {
            const delegate = target.querySelector(`[href="${dataUrl}"]`)
            if (delegate) {
              delegate.click()
            } else {
              window.location = dataUrl
            }
          }
        }
      }
    
      const tables = [...document.getElementsByTagName("table")]
      tables.forEach(
        /** @type {HTMLTableElement} */ (table) => {
        table.addEventListener("click", visitDataUrl)
        table.addEventListener("keydown", visitDataUrl)
      })
    }
    
    document.addEventListener("turbolinks:load", function() {
      bindTableLinks()
    })
    
  6. app/views/layouts/admin/application.html.erb を作成
    mkdir -p app/views/layouts/admin/
    
    • 以下の内容の app/views/layouts/admin/application.html.erb を作成
    <%#
    # Application Layout
    
    This view template is used as the layout
    for every page that Administrate generates.
    
    By default, it renders:
    - Navigation
    - Content for a search bar
      (if provided by a `content_for` block in a nested page)
    - Flashes
    - Links to stylesheets and JavaScripts
    %>
    
    <!DOCTYPE html>
    <html lang="<%= I18n.locale %>">
      <head>
        <meta charset="utf-8">
        <meta name="robots" content="noodp, noydir, index, follow">
        <meta name="viewport" content="initial-scale=1">
        <title>
          <%= content_for(:title) || 'Dashboard' %> - <%= Rails.application.class.module_parent_name.titlecase %>
        </title>
        <%= javascript_pack_tag 'administrate', 'data-turbolinks-track': 'reload' %>
    
        <%= render "stylesheet" %>
        <%= csrf_meta_tags %>
    
    
        <meta name="turbolinks-root" content="/admin">
      </head>
      <body>
        <div class="app-container">
          <%= render "navigation" -%>
    
          <main class="main-content" role="main">
    	<%= render "flashes" -%>
    	<%= yield %>
          </main>
        </div>
    
        <div style="display: none; width: 0; height: 0; overflow: hidden; position: absolute">
          <%= render "icons" %>
        </div>
        <%= render "javascript" %>
      </body>
    </html>
    
  7. app/views/admin/application/_javascript.html.erb を作成
    mkdir -p app/views/admin/application/
    
    • 以下の内容の app/views/admin/application/_javascript.html.erb を作成
    <%#
    # Javascript Partial
    
    This partial imports the necessary javascript on each page.
    By default, it includes the application JS,
    but each page can define additional JS sources
    by providing a `content_for(:javascript)` block.
    
    Administrate::Engine.javascripts.each do |js_path|
     <= echo javascript_include_tag js_path
    <% end
    %>
    
    <%= yield :javascript %>
    
    <% if Rails.env.test? %>
      <%= javascript_tag do %>
        $.fx.off = true;
        $.ajaxSetup({ async: false });
      <% end %>
    <% end %>
    
  8. app/assets/stylesheets/administrate/application.scss を作成
    mkdir -p app/assets/stylesheets/administrate/
    
    • 以下の内容の app/assets/stylesheets/administrate/application.scss を作成
    @charset "utf-8";
    
    @import "administrate/reset/normalize";
    
    @import "administrate/library/clearfix";
    @import "administrate/library/data-label";
    @import "administrate/library/variables";
    
    @import "administrate/base/forms";
    @import "administrate/base/layout";
    @import "administrate/base/lists";
    @import "administrate/base/tables";
    @import "administrate/base/typography";
    
    @import "administrate/components/app-container";
    @import "administrate/components/attributes";
    @import "administrate/components/buttons";
    @import "administrate/components/cells";
    @import "administrate/components/field-unit";
    @import "administrate/components/flashes";
    @import "administrate/components/form-actions";
    @import "administrate/components/main-content";
    @import "administrate/components/navigation";
    @import "administrate/components/pagination";
    @import "administrate/components/search";
    
    @import "administrate/utilities/text-color";
    
    @import "trix/dist/trix";
    
    // We need to override trix.css’s image gallery styles to accommodate the
    // <action-text-attachment> element we wrap around attachments. Otherwise,
    // images in galleries will be squished by the max-width: 33%; rule.
    .trix-content {
      .attachment-gallery {
        > action-text-attachment,
        > .attachment {
          flex: 1 0 33%;
          padding: 0 0.5em;
          max-width: 33%;
        }
    
        &.attachment-gallery--2,
        &.attachment-gallery--4 {
          > action-text-attachment,
          > .attachment {
            flex-basis: 50%;
            max-width: 50%;
          }
        }
      }
    
      action-text-attachment {
        .attachment {
          padding: 0 !important;
          max-width: 100% !important;
        }
      }
    }
    
    .field-unit--rich-text-area-field {
      .field-unit__field {
        width: 80%;
      }
    }
    
    @import "flatpickr/dist/flatpickr.min";
    
    • gitでコミットしておく
    git add -A
    git commit -m "Administrateインストール+設定"
    

11.4.5 app/dashboards/my_post_dashboard.rb を以下に修正

  • rich_text_content を content に変更(数箇所)し、Typeを RichTextAreaField に修正
require "administrate/base_dashboard"

class MyPostDashboard < Administrate::BaseDashboard
  # ATTRIBUTE_TYPES
  # a hash that describes the type of each of the model's fields.
  #
  # Each different type represents an Administrate::Field object,
  # which determines how the attribute is displayed
  # on pages throughout the dashboard.
  #  rich_text_content: Field::HasOne,
  #  content: RichTextAreaField,
  #  content: Field::Trix,
  #  content: Field::ActiveStorage,
  ATTRIBUTE_TYPES = {
    id: Field::Number,
    title: Field::String,
    content: RichTextAreaField,
    #content:  Field::String,
    created_at: Field::DateTime,
    updated_at: Field::DateTime,
  }.freeze

  # COLLECTION_ATTRIBUTES
  # an array of attributes that will be displayed on the model's index page.
  #
  # By default, it's limited to four items to reduce clutter on index pages.
  # Feel free to add, remove, or rearrange items.
  # rich_text_content
  COLLECTION_ATTRIBUTES = %i[
  id
  title
  content
  created_at
  ].freeze

  # SHOW_PAGE_ATTRIBUTES
  # an array of attributes that will be displayed on the model's show page.
  # rich_text_content
  SHOW_PAGE_ATTRIBUTES = %i[
  id
  title
  content
  created_at
  updated_at
  ].freeze

  # FORM_ATTRIBUTES
  # an array of attributes that will be displayed
  # on the model's form (`new` and `edit`) pages.
  # rich_text_content
  FORM_ATTRIBUTES = %i[
  title
  content 
  ].freeze

  # COLLECTION_FILTERS
  # a hash that defines filters that can be used while searching via the search
  # field of the dashboard.
  #
  # For example to add an option to search for open resources by typing "open:"
  # in the search field:
  #
  #   COLLECTION_FILTERS = {
  #     open: ->(resources) { where(open: true) }
  #   }.freeze
  COLLECTION_FILTERS = {}.freeze

  # Overwrite this method to customize how my posts are displayed
  # across all pages of the admin dashboard.
  #
  # def display_resource(my_post)
  #   "MyPost ##{my_post.id}"
  # end
end
  • gitでコミットしておく
git add -A
git commit -m "MyPost用Administrate設定修正"

11.4.6 config/application.rbを修正

  • 日本語関係、タイムゾーン設定
...省略
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
  end
end

11.4.7 i18n_generatorsで日本語用ファイル生成

  • config/locales/translation_ja.yml を確認
  1. app/dashboards/my_post_dashboard.rb を以下に修正
    ... 省略
        #content: RichTextAreaField,
        content:  Field::String,
    ... 省略
    
  2. i18n_generatorsで日本語用ファイル生成
    rails db:migrate
    rails g i18n ja
    # rails g i18n_locale ja
    # rails g i18n_translation ja
    
  3. app/dashboards/my_post_dashboard.rb を以下に修正
    ... 省略
        content: RichTextAreaField,
        #content:  Field::String,
    ... 省略
    
    • gitでコミットしておく
    git add -A
    git commit -m "日本語関係設定修正"
    

11.5 railsサーバーを起動して、ブラウザで確認

rails server -b 0.0.0.0

11.6 この章のまとめ

  • 前はrails_adminを使ってみたが、今回はAdministrateというgemを利用して、Rails6でAction Textを含むクラスの管理画面を作ってみた
  • rails_adminでやった時には、画像添付ボタンが表示されてなかった(私の設定方法が悪かったのかもしれんが)が、Administrateの方は、公式サイトに記述されてる方法で、ACTION TEXTの編集で画像追加ボタンが使えた
  • 相当沢山設定変更しないと動かなかった
  • モデルをディレクトリ以下に作成する名前だとエラーになる、モデル名に::が含まれないように(まとめディレクトリ以下にモデルを作成)した方が良いようだ(ダメな例 Dialy::Post, これを改善するとすると モデル名は DialyPost)

11.7 追記

  • 以下でも動くようです
  • //= link administrate-field-trix/application.css があるために、Gemfileに gem ‘administrate-field-trix’ がないとダメだったようです。

11.7.1 app/assets/config/manifest.js が以下

  • http://localhost:3000/adminにアクセスした時に出るエラーより
  • //= link administrate-field-trix/application.css を削除
... 省略
//= link administrate/application.css
//= link administrate/application.js
  1. Gemfileが 以下
    • gem “administrate” 以下をコメントアウト
    # gem 'image_processing'
    # gem 'rails_admin'
    gem 'rails-i18n', '~> 6.0.0' # For 6.0.0 or higher
    gem 'i18n_generators'
    gem 'devise'
    
    gem "administrate" 
    # gem 'administrate-field-active_storage'
    # gem 'mini_magick'
    # gem 'administrate-field-trix'
    # gem 'trix-rails', require: 'trix'
    

12 後も文書追加していきます。

13 この文書のチェンジログ

  • 2020/02/25 初版
  • 2020/02/25 初めてのプロジェクト作成 の章追加
  • 2020/02/25 scaffoldを利用したモデルの作成 の章追加
  • 2020/02/25 scaffoldのカスタマイズ の章追加
  • 2020/03/01 Action Textを試してみる の章追加
  • 2020/03/04 Action Textを試してみる2 の章追加, Action Textを試してみる の章の動画リンク削除
  • 2020/03/05 ちゃちゃっと日記を作ってみる の章追加
  • 2020/03/05 一旦scaffoldで生成したモデルを破壊し、作り直す手順 の章追加
  • 2020/03/09 mailアドレスでログイン出来る機能をつけてみる(diverse) の章追加
  • 2020/03/09 Rails6 + Administrate + Action Text の章追加
  • 2020/03/11 Rails6 + Administrate + Action Text の最後に情報追加

著者: NM Max

Created: 2020-03-11 水 12:53

Validate

Pyaq(囲碁ソフト)の調査

Pyaq(囲碁ソフト)の調査

目次

1 概要

  • Deep Learningで学習できる、囲碁ソフト
  • Pythonベース
  • MITライセンス

2 リンク

3 Boardクラスをちょっと試してみる

  • Dockerイメージで構築します。
  • Docker Hub の tensorflow/tensorflowイメージをベースに行います。
  • tensorflow/tensorflowのイメージを拡張その2(GNU GLobal入り)https://www.youtube.com/watch?v=FFWRbgJjekoを利用します。

3.1 以下の操作を行っている動画


3.2 GNU Globalでソースを読みやすくなるようにする

  • terminalを起動し以下を実行
  • 作業用のディレクトリを作成し、ソースをゲット、GNU Globalで処理して、よみやすくなったHTMLを生成し、w3mで開く
sudo su - user
cd /tf/notebooks/
mkdir -p Pyaq
cd Pyaq
git clone https://github.com/ymgaq/Pyaq.git
cd Pyaq
# gtags --gtagslabel=pygments
htags -afFIsngov --gtagslabel=pygments
w3m HTML/index.html
  • w3mでみたら、Shift+Fで、より読みやすくなる

3.3 他の端末を開いて、board.pyの中にはいっている、関数やBoardクラスを使ってみる

3.3.1 以下でipython3を起動

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq/
ipython3

3.3.2 ipython3内部で以下を実行

  • ボードを生成して、いろいろやってみる
import board
b=board.Board()  # ボードを作成
b.random_play()  # ランダムに1手
b.showboard()    # ボードを表示
b.clear()        # ボードをクリア
b.showboard()
board.ev2str(81) # 内部で81が何か? => 'D7'
board.ev2xy(81)  # 内部で81が何か? => (4, 7)
board.ev2rv(81)  # 内部で81が何か? => 57
board.str2ev("D7") # => 81
b.place_stone(board.str2ev("D7")) # D7に石を置く
b.showboard()                     # ボードを表示
b.place_stone(board.str2ev("E7")) # E7に石を置く
b.showboard()                     # ボードを表示
b.place_stone(board.str2ev("F8")) # F8に石を置く
b.showboard()                     # ボードを表示
b.place_stone(board.str2ev("E9")) # E9に石を置く
b.showboard()                     # ボードを表示
b.place_stone(board.str2ev("D8")) # D8に石を置く
b.showboard()                     # ボードを表示
b.play(board.str2ev("F7"))        # playとしてF7に石を置く
b.showboard()                     # ボードを表示
b.legal(board.str2ev("E8"))       # E8に石を置けるかチェック => False
b.legal(board.str2ev("F6"))       # F6に石を置けるかチェック => True
b.play(board.str2ev("F6"))        # playとしてF6に石を置く
b.showboard()                     # ボードを表示
b.play(board.str2ev("F5"))        # playとしてF5に石を置く
b.showboard()                     # ボードを表示
b.feature()                       # 評価関数(search.py evaluate)に渡されているものをみてみる
type(b.feature())                 # タイプ確認
b.feature().ndim                  # 次元数確認 => 2
b.feature().shape                 # 次元数確認 => (81, 7)
b.feature().size                  # 次元数確認 => 567
len(b.feature())                  # len => 81

3.4 この章のまとめ

  • Pyaqのソースをゲットしてきて、GNU Globalで読みやすく加工
  • IPythonを利用して、board.pyにはいっている関数や、Boardクラスを試してみた

4 Boardクラスをちょっと試してみる2

  • ボードの指定座標の状態を知る(白か黒か空か)
  • 一つ前の手を確認
  • 1つ前のボードの状態を確認
  • どちらの手番か確認
  • tensorflow/tensorflowのイメージを拡張その2(GNU GLobal入り)https://www.youtube.com/watch?v=FFWRbgJjekoを利用します。

4.1 以下の操作を行っている動画


4.2 今回の操作をやるために調べたソースの部分

4.2.1 Boardクラスのshowboadメソッド

  • ループまわして、それぞれの座標の状態を表示している
  • 330行に調べる部分がある
  • このソースから、指定座標の状態を知る方法が簡単に調べられる
  • 333行目から、一つ前の手がどれかを調べる方法が確認可能
315     def showboard(self):
316
317         def pirnt_xlabel():
318             line_str = "  "
319             for x in range(BSIZE):
320                 line_str += " " + x_labels[x] + " "
321             stderr.write(line_str + "\n")
322
323         pirnt_xlabel()
324
325         for y in range(1, BSIZE + 1)[::-1]:  # 9, 8, ..., 1
326             line_str = str(y) if y >= 10 else " " + str(y)
327             for x in range(1, BSIZE + 1):
328                 v = xy2ev(x, y)
329                 x_str = " . "
330                 color = self.color[v]
331                 if color <= 1:
332                     stone_str = "O" if color == 0 else "X"
333                     if v == self.prev_move:
334                         x_str = "[" + stone_str + "]"
335                     else:
336                         x_str = " " + stone_str + " "
337                 line_str += x_str
338             line_str += str(y) if y >= 10 else " " + str(y)
339             stderr.write(line_str + "\n")
340
341         pirnt_xlabel()
342         stderr.write("\n")

4.2.2 Boardクラスの clearメソッド

  • 116行目に、prev_colorへの代入文がある。これから、KEEP_PREV_CNTの数の分前の盤の状態を保持することがわかる
110     def clear(self):
111         self.color[rv_list] = 2  # empty
112         self.id = np.arange(EBVCNT)  # id of stone group
113         self.next = np.arange(EBVCNT)  # next position in the same group
114         for i in range(EBVCNT):
115             self.sg[i].clear(stone=False)
116         self.prev_color = [np.copy(self.color) for _ in range(KEEP_PREV_CNT)]
117
118         self.ko = VNULL  # illegal position due to Ko
119         self.turn = 1  # black
120         self.move_cnt = 0  # move count
121         self.prev_move = VNULL  # previous move
122         self.remove_cnt = 0  # removed stones count
123         self.history = []

4.3 手順

  • 前の章のやり方でDocker imageを起動
  • 他の端末を開いて、IPythonを起動

4.3.1 以下でipython3を起動

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq/
ipython3
  • IPython内で以下を実行しボードクラスを使ってみる2
import board
b=board.Board()                   # ボードを作成
b.showboard()                     # ボードを表示
b.turn                            # => 1
b.prev_color                      
b.prev_color[0]==b.prev_color[1]  
b.color.reshape(11,11)            # ボード情報を格納しているcolorをreshapeして表示 0:O 1:X 2:空 3:壁
b.play(board.str2ev("F7"))        # playとしてF7に石を置く
b.showboard()                     # ボードを表示
b.color.reshape(11,11)
b.prev_color                      
b.prev_color[0]==b.prev_color[1]  
b.turn                            # => 0
b.play(board.str2ev("A1"))        # playとしてA1に石を置く
b.showboard()                     # ボードを表示
b.color.reshape(11,11)
b.color[board.str2ev("F7")]       # F7 の状態 => 1
b.color[board.str2ev("A1")]       # A1 の状態 => 0
b.color[board.str2ev("A2")]       # A2 の状態 => 2
b.color[1]                        # 壁 の状態 => 3
type(b.prev_color)                # => list
b.prev_move
board.ev2str(b.prev_move)         # => A1

import numpy as np
b.prev_color                      
b.prev_color[0]==b.prev_color[1]  
x=(b.prev_color[0]==b.prev_color[1])
np.where( x == False )            # どこが変化したか確認 => (arrya[83])
board.ev2str(83)                  # => F7

board.KEEP_PREV_CNT=3             # KEEP_PREV_CNTを変更してみる
b=board.Board()                   # Boardを再度生成
b.prev_color                      # prev_colorを確認、要素数が増えている
len(b.prev_color)                 # => 3

4.4 この章のまとめ

  • Boardクラスで、指定座標の状態の調べ方がわかった
  • 手番、一つ前のコマの状態、一つ前の盤の状態の調べ方がわかった
  • 一つ前の手の調べ方がわかった
  • 何手前まで、盤の状態を保持させるかの設定を変更してみた

5 評価関数で、好きな盤の状態を評価させてみた

  • 今までの章でボードクラスの扱いはだいたいわかったので、その盤の状態を現在の評価関数で評価させてみた
  • TensorFlow 2.1.0 で動かすと AttributeError: module ‘tensorflow’ has no attribute ‘get_default_graph’ というエラーが
  • 上の2.1.0で動かした時にエラー、これを使えば解決できそうだが? tf.compat.v1.get_default_graph https://www.tensorflow.org/api_docs/python/tf/compat/v1/get_default_graph
  • tensorflow/tensorflowのイメージを拡張その2(GNU GLobal入り)https://www.youtube.com/watch?v=FFWRbgJjekoを利用します。

5.1 以下の操作を行っている動画


5.2 評価関数を直接使ってみる操作手順

5.2.1 イメージ起動

  • 以下を実行して表示される一番下のhttp://127.0.0.1 …. をコピペしてブラウザで開く
docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

5.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

5.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
ipython3                      #  ipython3起動

5.2.4 IPython内で以下を実行

from collections import Counter
import sys
from board import *
import gtp
import learn
import search
use_gpu = False

b = Board()                  #ボード生成

tree = search.Tree("model.ckpt", use_gpu) 
tree.evaluate(b)             # bのボードを評価
(a1,a2)=tree.evaluate(b)     # bのボードを評価を(a1,a2)に保存
a1.shape                     # a1 shape確認 => (1, 82)
a2.shape                     # a2 shape確認 => (1,)
type(a1)                     # a1 type確認  => numpy.ndarray
type(a2)                     # a2 type確認  => numpy.ndarray
a1                           # a1 確認      => 大きいので省略
a2                           # a2 確認      => array([0.02216651], dtype=float32)

5.3 この章でのまとめ

  • 評価関数に、作成した盤の状態をわたして、評価してみた
  • 返ってくるのは要素数82個の配列と、要素数1個の配列のタプル
  • この評価部分を差し替えれば、好きな評価関数での囲碁ソフトエンジン作成可能であろう(多分)
  • 9×9の盤なのに、なぜ82個なのか?調査継続

6 任意の盤を与えてお勧めの手をゲット

  • 前の章では、任意の盤を評価関数かけて、返り値をゲット出来た
  • この章では、任意の盤を与えて、一番お勧めの手をゲットしてみる
  • なぜ9×9=81の盤なのに、評価関数の返り値の配列の要素が82で1個多いのかも、理由判明(passがあるためでした)
  • search.pyの中を調べた
  • tensorflow/tensorflowのイメージを拡張その2(GNU GLobal入り)https://www.youtube.com/watch?v=FFWRbgJjekoを利用します。

6.1 以下の操作を行っている動画


6.2 任意の盤を与えてお勧めの手をゲットする手順

6.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

6.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

6.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
ipython3                      #  ipython3起動

6.2.4 IPython内で以下を実行

from collections import Counter
import sys
from board import *
import gtp
import learn
import search
use_gpu = False

b = Board()                  #ボード生成

tree = search.Tree("model.ckpt", use_gpu) 
tree.evaluate(b)             # bのボードを評価
(a1,a2)=tree.evaluate(b)     # bのボードを評価を(a1,a2)に保存

rv2ev(np.argmax(tree.evaluate(b)[0][0])) # お勧めの手のev値ゲット
np.argmax(tree.evaluate(b)[0][0])        # np.argmax(tree.evaluate(b)[0][0]) の確認 => 40
tree.evaluate(b)[0][0]                   # tree.evaluate(b)[0][0] の確認 
ev2str(rv2ev(np.argmax(tree.evaluate(b)[0][0]))) # strでお勧めの手を確認 => 'E5'
b.showboard()                            # ボード表示
ev2str(rv2ev(0))                         #  0の場合のstr確認 => 'A1'
ev2str(rv2ev(1))                         #  1の場合のstr確認 => 'B1'
ev2str(rv2ev(81))                        # 81の場合のstr確認 => 'pass'
ev2str(rv2ev(82))                        # 82の場合のstr確認 => 'B10' 0->81で82個だから、この値にはならない

6.3 この章でのまとめ

  • 任意の盤でのお勧めの手を得る手順を確認
  • 9×9=81個のおける場所にたいして82個の配列がかえってくる理由を確認(passがあるからでした)

7 StoneGroupクラスの調査

7.1 以下の操作を行っている動画


7.2 任意の盤を与えてお勧めの手をゲットする手順

7.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

7.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

7.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
ipython3                      #  ipython3起動

7.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
    ipython3                      #  ipython3起動
    

7.2.5 IPython内で以下を実行

  • StoneGroup のメンバ変数 lib_cnt が 隣接の空いているあるいは、味方の石の数
  • StoneGroup のメンバ変数 size が縦横で接続されている石の数の場合もあるし、他の数値になっているケースも(追加調査必用)
  • StoneGroup のメンバ変数 v_atr が当たりになっているケースあり
  • StoneGroup のメンバ変数 libs が隣接の空座標や、先に存在している仲間の石の座標の場合も
from collections import Counter
import sys
from board import *
import gtp
import learn
import search
use_gpu = False

# ある座標のStoneGroupのメンバ変数の中身表示用関数
def myShowSg(x):
  print(">>>>>>>: "+x)
  print("lib_cnt: ", end=" ")
  print(b.sg[str2ev(x)].lib_cnt)
  print("size   : ", end=" ")
  print(b.sg[str2ev(x)].size)
  print("v_atr  : ", end=" ")
  print(str(b.sg[str2ev(x)].v_atr)+" : "+ev2str(b.sg[str2ev(x)].v_atr))
  print("libs   : ", end=" ")
  print(b.sg[str2ev(x)].libs)
  for i in b.sg[str2ev(x)].libs:
    print(ev2str(i), end=", ")
  print("")

b = Board()                  #ボード生成

b.place_stone(str2ev("E7")) # E7に石を置く
b.showboard()               # ボードを表示
b.place_stone(str2ev("F8")) # F8に石を置く
b.showboard()               # ボードを表示
b.place_stone(str2ev("E9")) # E9に石を置く
b.showboard()               # ボードを表示
b.place_stone(str2ev("D8")) # D8に石を置く
b.showboard()               # ボードを表示
b.turn=0
b.place_stone(str2ev("F9")) # F9に石を置く
b.showboard()               # ボードを表示
b.place_stone(str2ev("F7")) # F7に石を置く
b.showboard()               # ボードを表示
b.place_stone(str2ev("G8")) # G8に石を置く
b.showboard()               # ボードを表示
b.legal(str2ev("E8"))       # E8に石を置ける? => True


b.sg                        # ボードのsgメンバーの内容
type(b.sg)                  # b.sgのタイプは? => list
len(b.sg)                   # b.sgの長さは? => 121
b.color.shape               # b.colorのshapeは? => (121,) b.sgの長さと同じつまり、"b.sgは、evで希望のStoneGroupeにアクセス可能"

b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  .  .  .  9
#  8 .  .  .  X  .  X  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
myShowSg("E9")
myShowSg("E7")
myShowSg("D8")
myShowSg("F8")
# >>>>>>>: E9
# lib_cnt:  2
# size   :  1
# v_atr  :  93 : E8
# libs   :  {93, 103}
# E8, D9,
# >>>>>>>: E7
# lib_cnt:  3
# size   :  1
# v_atr  :  71 : E6
# libs   :  {81, 93, 71}
# D7, E8, E6,
# >>>>>>>: D8
# lib_cnt:  4
# size   :  1
# v_atr  :  81 : D7
# libs   :  {81, 91, 93, 103}
# D7, C8, E8, D9,
# >>>>>>>: F8
# lib_cnt:  1
# size   :  1
# v_atr  :  83 : F7
# libs   :  {93}
# E8,

b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  .  .  .  9
#  8 .  .  .  X  .  X  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
myShowSg("F9")
myShowSg("F7")
myShowSg("G8")
# >>>>>>>: F9
# lib_cnt:  1
# size   :  1
# v_atr  :  106 : G9
# libs   :  {106}
# G9,
# >>>>>>>: F7
# lib_cnt:  2
# size   :  1
# v_atr  :  72 : F6
# libs   :  {72, 84}
# F6, G7,
# >>>>>>>: G8
# lib_cnt:  3
# size   :  1
# v_atr  :  84 : G7
# libs   :  {96, 106, 84}
# H8, G9, G7,

b.place_stone(str2ev("G9")) # G9に石を置く
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  O  .  .  9
#  8 .  .  .  X  .  X  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
myShowSg("F9")
myShowSg("F7")
myShowSg("G8")
myShowSg("G9")
# >>>>>>>: F9
# lib_cnt:  0
# size   :  1
# v_atr  :  106 : G9
# libs   :  set()
# 
# >>>>>>>: F7
# lib_cnt:  2
# size   :  1
# v_atr  :  72 : F6
# libs   :  {72, 84}
# F6, G7,
# >>>>>>>: G8
# lib_cnt:  2
# size   :  1
# v_atr  :  84 : G7
# libs   :  {96, 84}
# H8, G7,
# >>>>>>>: G9
# lib_cnt:  3
# size   :  3
# v_atr  :  107 : H9
# libs   :  {96, 107, 84}
# H8, H9, G7,

b.play(str2ev("E8"))        # E8に石を置く(playモード) F8の石取れた!
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  O  .  .  9
#  8 .  .  .  X [O] .  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J

myShowSg("F9")
myShowSg("F7")
myShowSg("G8")
myShowSg("G9")
myShowSg("E8")
# >>>>>>>: F9
# lib_cnt:  0
# size   :  1
# v_atr  :  106 : G9
# libs   :  set()
# 
# >>>>>>>: F7
# lib_cnt:  3
# size   :  1
# v_atr  :  94 : F8
# libs   :  {72, 84, 94}
# F6, G7, F8,
# >>>>>>>: G8
# lib_cnt:  2
# size   :  1
# v_atr  :  84 : G7
# libs   :  {96, 84}
# H8, G7,
# >>>>>>>: G9
# lib_cnt:  4
# size   :  3
# v_atr  :  94 : F8
# libs   :  {96, 107, 84, 94}
# H8, H9, G7, F8,
# >>>>>>>: E8
# lib_cnt:  1
# size   :  1
# v_atr  :  94 : F8
# libs   :  {94}
# F8,

b.turn = 0
b.play(str2ev("H9"))        # E9に石を置く(playモード)
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  O [O] .  9
#  8 .  .  .  X  O  .  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J

myShowSg("F9")
myShowSg("F7")
myShowSg("G8")
myShowSg("G9")
myShowSg("E8")
myShowSg("H9")
# >>>>>>>: F9
# lib_cnt:  0
# size   :  1
# v_atr  :  106 : G9
# libs   :  set()
# >>>>>>>: F7
# lib_cnt:  3
# size   :  1
# v_atr  :  94 : F8
# libs   :  {72, 84, 94}
# F6, G7, F8,
# >>>>>>>: G8
# lib_cnt:  2
# size   :  1
# v_atr  :  84 : G7
# libs   :  {96, 84}
# H8, G7,
# >>>>>>>: G9
# lib_cnt:  4
# size   :  4
# v_atr  :  94 : F8
# libs   :  {96, 84, 108, 94}
# H8, G7, J9, F8,
# >>>>>>>: E8
# lib_cnt:  1
# size   :  1
# v_atr  :  94 : F8
# libs   :  {94}
# F8,
# >>>>>>>: H9
# lib_cnt:  2
# size   :  1
# v_atr  :  96 : H8
# libs   :  {96, 108}
# H8, J9,

b.turn = 0
b.play(str2ev("J9"))        # J9に石を置く(playモード) F8の石取れた!
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  X  O  O  O [O] 9
#  8 .  .  .  X  O  .  O  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J

myShowSg("F9")
myShowSg("F7")
myShowSg("G8")
myShowSg("G9")
myShowSg("E8")
myShowSg("H9")
myShowSg("J9")

# >>>>>>>: F9
# lib_cnt:  0
# size   :  1
# v_atr  :  106 : G9
# libs   :  set()
# 
# >>>>>>>: F7
# lib_cnt:  3
# size   :  1
# v_atr  :  94 : F8
# libs   :  {72, 84, 94}
# F6, G7, F8,
# >>>>>>>: G8
# lib_cnt:  2
# size   :  1
# v_atr  :  84 : G7
# libs   :  {96, 84}
# H8, G7,
# >>>>>>>: G9
# lib_cnt:  4
# size   :  5
# v_atr  :  94 : F8
# libs   :  {96, 97, 84, 94}
# H8, J8, G7, F8,
# >>>>>>>: E8
# lib_cnt:  1
# size   :  1
# v_atr  :  94 : F8
# libs   :  {94}
# F8,
# >>>>>>>: H9
# lib_cnt:  2
# size   :  1
# v_atr  :  96 : H8
# libs   :  {96, 108}
# H8, J9,
# >>>>>>>: J9
# lib_cnt:  1
# size   :  1
# v_atr  :  97 : J8
# libs   :  {97}
# J8,

7.3 この章でのまとめ

  • StoneGroupeのメンバ変数の内容を調べてみた
  • 取れるか否かのチェックに利用されているはず
  • 石のグループ全部が同じlibsになっておらず、グループの1つの座標が、そのグループの全体の情報を持っているようであった
  • StoneGroupeは取れる石の判定に利用されていると推測

8 Boardクラスのscore関数の調査

8.1 以下の操作を行っている動画


8.2 任意の盤を与えてお勧めの手をゲットする手順

8.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

8.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

8.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
ipython3                      #  ipython3起動

8.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
    ipython3                      #  ipython3起動
    

8.2.5 board.pyのBoardクラスに以下の関数を追加

  • scoreの内容を確認するための補助メソッド
  • score クラスの下あたりに追加がお勧め(Boardクラスのメソッドとして定義できてればOK)
  • 4つの要素をかえし、[Xの石の数、Oの石の数、空きの目でXのみ隣接している目の数, 空きの目でOのみ隣接している目の数, score関数と同じ答]を返す。
def bscore(self):
    stone_cnt = [0, 0, 0, 0, 0]
    for rv in range(BVCNT):
        v = rv2ev(rv)
        c = self.color[v]
        if c <= 1:
            stone_cnt[c] += 1
        else:
            nbr_cnt = [0, 0, 0, 0]
            for d in dir4:
                nbr_cnt[self.color[v + d]] += 1
            if nbr_cnt[0] > 0 and nbr_cnt[1] == 0:
                stone_cnt[0+2] += 1
            elif nbr_cnt[1] > 0 and nbr_cnt[0] == 0:
                stone_cnt[1+2] += 1
    stone_cnt[4]= stone_cnt[1] - stone_cnt[0] - KOMI + stone_cnt[1+2] - stone_cnt[0+2]
    return stone_cnt

8.2.6 IPython内で以下を実行

  • 色々な盤面でscore関数、bscore関数を呼び出す
  • 下からすると、石がある目は、その石の陣営に+1, 石がない目は、周囲4方向に一方の陣営の石のみある場合その陣営に+1
  • 空き目で、周囲(上下4方向)に両方の陣営の石がある場合は、足さない
  • ハンデとして、board.py内のKOMIで設定(初期値-7.0)
from collections import Counter
import sys
from board import *
import gtp
import learn
import search
use_gpu = False

# ある座標のStoneGroupのメンバ変数の中身表示用関数
def myShowSg(x):
  print(">>>>>>>: "+x)
  print("lib_cnt: ", end=" ")
  print(b.sg[str2ev(x)].lib_cnt)
  print("size   : ", end=" ")
  print(b.sg[str2ev(x)].size)
  print("v_atr  : ", end=" ")
  print(str(b.sg[str2ev(x)].v_atr)+" : "+ev2str(b.sg[str2ev(x)].v_atr))
  print("libs   : ", end=" ")
  print(b.sg[str2ev(x)].libs)
  for i in b.sg[str2ev(x)].libs:
    print(ev2str(i), end=", ")
  print("")

b = Board()                 #ボード生成
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      # ([0, 0, 0, 0, -7.0], -7.0)

b.place_stone(str2ev("E7")) # E7に石を置く
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      # ([0, 1, 0, 4, -2.0], -2.0)

b.score()
b.place_stone(str2ev("F8")) # F8に石を置く
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  X  .  .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      # ([0, 2, 0, 6, 1.0], 1.0)

b.play(str2ev("D6"))        # D6に石を置く
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  X  .  .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  . [X] .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      # ([0, 3, 0, 8, 4.0], 4.0)

b.play(str2ev("G8"))        # G8に石を置
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  X [O] .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  X  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      #  ([1, 3, 3, 7, -1.0], -1.0)

b.play(str2ev("J8"))        # J8に石を置
b.showboard()               # ボードを表示
# この時点での盤の状態
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  X  O  . [X] 8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  X  .  .  .  .  .  6
#  5 .  .  .  .  .  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
(b.bscore(),b.score())      #  ([1, 4, 2, 9, 3.0], 3.0)

8.3 この章のまとめ

  • 点数計算方法の確認を、複数の盤面を作ってみて確認

9 Boardクラスのコピー

9.1 以下の操作を行っている動画


9.2 Boardクラスオブジェクトのコピーをする手順

9.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

9.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

9.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
ipython3                      #  ipython3起動

9.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    pip3 install tensorflow==1.4  #  古いバージョンに下げて、問題回避
    ipython3                      #  ipython3起動
    

9.2.5 IPython内で以下を実行

  • Boardオブジェクトb を Boardオブジェクトc にコピーするには、b.copy(c)で可能
from board import *

b=Board()
c=Board()

b.place_stone(str2ev("E7")) # E7に石を置く
b.copy(c)
b.showboard()               # ボードを表示

9.3 この章でのまとめ

  • ボードクラスのコピー方法について( bをcにコピーするなら、b.copy(c) で可能 )

10 幾つかの調査関数をBoardクラスのメンバ関数に組み込み

10.1 以下の操作を行っている動画


10.2 幾つかの調査関数をBoardクラスのメンバ関数に組み込む手順

10.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

10.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

10.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
# pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
# ipython3                      #  ipython3起動

10.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    # pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
    # ipython3                      #  ipython3起動
    

10.2.5 board.pyを編集

  • ホスト側なら~/notebooks/Pyaq/Pyaq/board.py を編集
  • Dockerイメージ内部なら /tf/notebooks/Pyaq/Pyaq/board.py を編集
  1. Boardクラスのメンバ関数を追加
    • score関数の後に以下を追加する
    • bscore関数は前の章で追加したものと同じ、score関数内部の計算集計の詳細をゲットできる
    • myShowSg関数は指定した座標(strタイプ ex. “A1″)のStoneGroupeのメンバ変数の状態表示
    • myShowSgAll関数は、全ての石が置かれている目に対して、myShowSg関数を実行
    • listUpStoneEv関数は石が置かれているev値を配列にして返す(白石、黒石それぞれ)
    • listUpAtr関数は全ての盤面の石がおかれている所をチェックし、その目のStoneGroupのAtr値(あたり目かもしれない)をリストアップ。(その目が空の場合のみ集める)
    • listUpNeedCheckEvs関数は全ての盤面の石がおかれている所をチェックし、その目のStoneGroupのAtr値(あたり目かもしれない)をリストアップ。(StoneGroupeのlibsの数が1でその目が空の場合のみ集める)
    .....省略
        def bscore(self):
    .....省略
    	return stone_cnt[1] - stone_cnt[0] - KOMI
    
        def bscore(self):
    	stone_cnt = [0, 0, 0, 0, 0]
    	for rv in range(BVCNT):
    	    v = rv2ev(rv)
    	    c = self.color[v]
    	    if c <= 1:
    		stone_cnt[c] += 1
    	    else:
    		nbr_cnt = [0, 0, 0, 0]
    		for d in dir4:
    		    nbr_cnt[self.color[v + d]] += 1
    		if nbr_cnt[0] > 0 and nbr_cnt[1] == 0:
    		    stone_cnt[0+2] += 1
    		elif nbr_cnt[1] > 0 and nbr_cnt[0] == 0:
    		    stone_cnt[1+2] += 1
    	stone_cnt[4]= stone_cnt[1] - stone_cnt[0] - KOMI + stone_cnt[1+2] - stone_cnt[0+2]
    	return stone_cnt
    
        def myShowSg(self, x):
    	print(">>>>>>>: "+x)
    	print("lib_cnt: ", end=" ")
    	print(self.sg[str2ev(x)].lib_cnt)
    	print("size   : ", end=" ")
    	print(self.sg[str2ev(x)].size)
    	print("v_atr  : ", end=" ")
    	print(str(self.sg[str2ev(x)].v_atr)+" : "+ev2str(self.sg[str2ev(x)].v_atr))
    	print("libs   : ", end=" ")
    	print(self.sg[str2ev(x)].libs)
    	for i in self.sg[str2ev(x)].libs:
    	  print(ev2str(i), end=", ")
    	print("")
    
        def myShowSgAll(self):
    	ans = [[],[]]
    	print("************ X ")
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 1:
    	    self.myShowSg(ev2str(v))
    	print("************ O ")
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 0:
    	    self.myShowSg(ev2str(v))
    
        def listUpStoneEv(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 0:
    	    ans[0].append(v)
    	  else:
    	    if c == 1:
    	      ans[1].append(v)
    	return ans
    
        def listUpAtr(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  v2 = self.sg[v].v_atr
    	  if self.color[v2]==2 :
    	    if c == 0:
    		ans[0].append(v2)
    	    else:
    	      if c == 1:
    		ans[1].append(v2)
    	return ans
    
        def listUpNeedCheckEvs(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  c2 = self.sg[v].lib_cnt
    	  if c2 == 1 :
    	    v2 = list(self.sg[v].libs)[0]
    	    if c == 0:
    		ans[0].append(v2)
    	    else:
    	      if c == 1:
    		ans[1].append(v2)
    	return ans
    .....省略
    

10.2.6 IPythonを起動

ipython3

10.2.7 IPython内で以下を実行

from board import *

b=Board()                   # ボードを作成

b.place_stone(str2ev("E5")) # E5に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [0, 1, 0, 4, -2.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# ************ O
# [[], [60]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.place_stone(str2ev("D6")) # D6に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [0, 2, 0, 6, 1.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# ************ O
# [[], [60, 70]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  X  .  .  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.place_stone(str2ev("F6")) # F6に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [0, 3, 0, 8, 4.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# >>>>>>>: F6
# lib_cnt:  4
# size   :  1
# v_atr  :  61 : F5
# libs   :  {73, 83, 61, 71}
# G6, F7, F5, E6,
# ************ O
# [[], [60, 70, 72]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  X  .  X  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.place_stone(str2ev("E7")) # E7に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [0, 4, 0, 9, 6.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# >>>>>>>: F6
# lib_cnt:  4
# size   :  1
# v_atr  :  61 : F5
# libs   :  {73, 83, 61, 71}
# G6, F7, F5, E6,
# >>>>>>>: E7
# lib_cnt:  4
# size   :  1
# v_atr  :  71 : E6
# libs   :  {81, 83, 93, 71}
# D7, F7, E8, E6,
# ************ O
# [[], [60, 70, 72, 82]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  X  .  X  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.turn=0
b.place_stone(str2ev("F7")) # E7に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [1, 4, 2, 8, 2.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# >>>>>>>: F6
# lib_cnt:  3
# size   :  1
# v_atr  :  61 : F5
# libs   :  {73, 61, 71}
# G6, F5, E6,
# >>>>>>>: E7
# lib_cnt:  3
# size   :  1
# v_atr  :  71 : E6
# libs   :  {81, 93, 71}
# D7, E8, E6,
# ************ O
# >>>>>>>: F7
# lib_cnt:  2
# size   :  1
# v_atr  :  94 : F8
# libs   :  {84, 94}
# G7, F8,
# [[83], [60, 70, 72, 82]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  X  .  X  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.place_stone(str2ev("G6")) # E7に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [2, 4, 4, 7, -2.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  4
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 61, 71}
# E4, D5, F5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# >>>>>>>: F6
# lib_cnt:  2
# size   :  1
# v_atr  :  61 : F5
# libs   :  {61, 71}
# F5, E6,
# >>>>>>>: E7
# lib_cnt:  3
# size   :  1
# v_atr  :  71 : E6
# libs   :  {81, 93, 71}
# D7, E8, E6,
# ************ O
# >>>>>>>: G6
# lib_cnt:  3
# size   :  1
# v_atr  :  62 : G5
# libs   :  {74, 84, 62}
# H6, G7, G5,
# >>>>>>>: F7
# lib_cnt:  2
# size   :  1
# v_atr  :  94 : F8
# libs   :  {84, 94}
# G7, F8,
# [[73, 83], [60, 70, 72, 82]]
# [[], []]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  X  .  X  O  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.place_stone(str2ev("F5")) # E7に石を置く
print(b.bscore())
b.myShowSgAll()
print(b.listUpStoneEv())
print(b.listUpNeedCheckEvs())
b.showboard()
# [3, 4, 5, 6, -5.0]
# ************ X
# >>>>>>>: E5
# lib_cnt:  3
# size   :  1
# v_atr  :  49 : E4
# libs   :  {49, 59, 71}
# E4, D5, E6,
# >>>>>>>: D6
# lib_cnt:  4
# size   :  1
# v_atr  :  59 : D5
# libs   :  {81, 59, 69, 71}
# D7, D5, C6, E6,
# >>>>>>>: F6
# lib_cnt:  1
# size   :  1
# v_atr  :  61 : F5
# libs   :  {71}
# E6,
# >>>>>>>: E7
# lib_cnt:  3
# size   :  1
# v_atr  :  71 : E6
# libs   :  {81, 93, 71}
# D7, E8, E6,
# ************ O
# >>>>>>>: F5
# lib_cnt:  2
# size   :  1
# v_atr  :  50 : F4
# libs   :  {50, 62}
# F4, G5,
# >>>>>>>: G6
# lib_cnt:  3
# size   :  1
# v_atr  :  62 : G5
# libs   :  {74, 84, 62}
# H6, G7, G5,
# >>>>>>>: F7
# lib_cnt:  2
# size   :  1
# v_atr  :  94 : F8
# libs   :  {84, 94}
# G7, F8,
# [[61, 73, 83], [60, 70, 72, 82]]
# [[], [71]]
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  X  .  X  O  .  .  6
#  5 .  .  .  .  X  O  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
print(ev2str(71))
# E6 
# E6に石を置けば取れる可能性があることをチェックできている 

10.3 この章でのまとめ

  • 幾つかの調査関数をBoardクラスの中に組み込んで使ってみた
  • StoneGroupの中身が調べやすくなった
  • アタリになっている可能性のあるev値のリストアップが出来た

11 playした時に取り除いた石のev値を保持するように改造

11.1 以下の操作を行っている動画


11.2 playした時に取り除いた石のev値を保持するように改造 する手順

11.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

11.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

11.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
# pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
# ipython3                      #  ipython3起動

11.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    # pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
    # ipython3                      #  ipython3起動
    

11.2.5 board.pyを編集

  • ホスト側なら~/notebooks/Pyaq/Pyaq/board.py を編集
  • Dockerイメージ内部なら /tf/notebooks/Pyaq/Pyaq/board.py を編集
  1. Boardクラスに remove_ev_list を追加
    • self.remove_ev_list=[] を追加
    .....省略
    class Board(object):
    
        def __init__(self):
    	# 1-d array ([EBVCNT]) of stones or empty or exterior
    	# 0: white 1: black
    	# 2: empty 3: exterior
    	self.color = np.full(EBVCNT, 3)
    	self.sg = [StoneGroup() for _ in range(EBVCNT)]  # stone groups
    	self.clear()
    	self.remove_ev_list=[]
    
  2. Boardクラスの remove メソッドを以下に改造
    • print(“remove call:”str(v)“=”+ev2str(v)) 追加
    • print(“remove:”str(v_tmp)“=”+ev2str(v_tmp)) 追加
    • self.remove_ev_list.append(v_tmp) 追加
    .....省略
        def remove(self, v):
    	print("remove call:"+str(v)+"="+ev2str(v))
    	# remove stone group including stone at v
    	v_tmp = v
    	while 1:
    	    self.remove_cnt += 1
    	    self.color[v_tmp] = 2  # empty
    	    print("remove:"+str(v_tmp)+"="+ev2str(v_tmp))
    	    self.remove_ev_list.append(v_tmp)
    	    self.id[v_tmp] = v_tmp  # reset id
    	    for d in dir4:
    		nv = v_tmp + d
    		# add liberty to neighbor groups
    		self.sg[self.id[nv]].add(v_tmp)
    	    v_next = self.next[v_tmp]
    	    self.next[v_tmp] = v_tmp
    	    v_tmp = v_next
    	    if v_tmp == v:
    		break  # finish when all stones are removed
    
    

11.2.6 IPythonを起動

python3

11.2.7 IPython内で以下を実行

from board import *

b=Board()                   # ボードを作成

b.place_stone(str2ev("E5")) # E5に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("D6")) # D6に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("F6")) # F6に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("E7")) # E7に石を置く
print(b.remove_ev_list)
b.showboard()               # ボードを表示
# []
# []
# []
# []
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  .  .  .  .  7
#  6 .  .  .  X  .  X  .  .  .  6
#  5 .  .  .  .  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.turn=0
b.place_stone(str2ev("F7")) # E7に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("G6")) # G6に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("F5")) # F5に石を置く
print(b.remove_ev_list)
b.showboard()               # ボードを表示
# []
# []
# []
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  X  O  .  .  .  7
#  6 .  .  .  X  .  X  O  .  .  6
#  5 .  .  .  .  X  O  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.play(str2ev("E6"))        # F5に石を置く
print(b.remove_ev_list)     # 取り除いた石のEV値表示
print(ev2str(72))           # ev値72のstr形式は => F6

#####################
from board import *
b=Board()                   # ボードを作成
b.clear()                   # 盤の初期化
b.remove_ev_list.clear()    # b.remove_ev_listをクリア
print(b.remove_ev_list)
b.place_stone(str2ev("E5")) # E5に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("D5")) # D5に石を置く
b.showboard()               # ボードを表示
# []
# []
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  .  .  .  .  .  .  6
#  5 .  .  .  X  X  .  .  .  .  5
#  4 .  .  .  .  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.turn=0
b.place_stone(str2ev("C5")) # C5に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("D6")) # D6に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("E6")) # E6に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("F5")) # F5に石を置く
print(b.remove_ev_list)
b.place_stone(str2ev("D4")) # F5に石を置く
print(b.remove_ev_list)
b.showboard()               # ボードを表示
# []
# []
# []
# []
# []
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  .  .  .  .  .  7
#  6 .  .  .  O  O  .  .  .  .  6
#  5 .  .  O  X  X  O  .  .  .  5
#  4 .  .  .  O  .  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.play(str2ev("E4"))        # E4に石を置いてXを取る
print(b.remove_ev_list)     # 取った石のev値のリストゲット
# [59, 60]
for i in b.remove_ev_list:  #ev値はわかりにくいから、ループまわしてstr型に変換
  print(str(i)+":"+ev2str(i))
# 59:D5
# 60:E5

11.3 この章でのまとめ

  • 取り除いた石のev値のリストをゲットできるように改造してみた
  • 取る石が複数個でも上手く動いていることを確認

12 Boardクラスのメンバ関数拡張

12.1 以下の操作を行っている動画


12.2 Boardクラスのメンバ関数拡張 手順

12.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

12.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

12.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/Pyaq/Pyaq
cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
# pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
# ipython3                      #  ipython3起動

12.2.4 以前の章でPyaqのソースをゲットしてないなら

  1. ディレクトリ作成
    cd /tf/notebooks/
    sudo mkdir Pyaq
    
  2. 作成したPyaqディレクトリの所有権変更
    sudo chown user.user Pyaq
    cd Pyaq
    
  3. Pyaq ソースゲット
    git clone https://github.com/ymgaq/Pyaq.git
    
  4. Pyaq ソースゲット
    • GNU GLobalでソースを読みやすくしたHTMLファイル作成
    • ホスト側でホームディレクトリのnotebooks/Pyaq/Pyaq/HTML/index.htmlをブラウザで開く
    cd Pyaq
    htags -afFIsngov --gtagslabel=pygments
    
    • 以下を実行し、IPython3を起動
    cd /tf/notebooks/Pyaq/Pyaq
    cp pre_train/model.ckpt .     # 学習済みモデルを利用できるように
    # pip3 install tensorflow==1.4  #  AVX拡張命令の使えないCPUの場合, 古いバージョンに下げて、問題回避
    # ipython3                      #  ipython3起動
    

12.2.5 board.pyを編集

  • ホスト側なら~/notebooks/Pyaq/Pyaq/board.py を編集
  • Dockerイメージ内部なら /tf/notebooks/Pyaq/Pyaq/board.py を編集
  1. Boardクラスのメンバ関数を追加
    • 前の章の石を取り除いたものをremove_ev_listにいれる修正もした方が良いhttps://www.youtube.com/embed/CbW21FVp_yc
    • Boardクラスのscore関数の定義の後に以下を追加
    • 昔の章で追加した関数も含まれているので、昔のboardクラスにメンバ関数を追加された方は def listUpLibsEvs(self): 以下を追加してください。
    • listUpLibsEvsは石のある目のStoneGroupeのlibsを集めて返す関数
    • filterEmpty(self,listorset) は listorset のev値が空の時(2)のものだけフィルターしてリストでかえす
    • getDeadStonesEv(self,ev) は ev値に石を置いた時に取れる石のev値を返す
    • place_stones(self,evs) は、evsにstr形式で与えた目に石を置く関数(ルール上置けない場所には置けない)
    • place_stones10(self,evs1,evs0) は X(先手)の目をevs1に O(後手)の目をevs0に置く
    • place_stones01(self,evs0,evs1) は O(後手)の目をevs0に置く は X(先手)の目をevs1に置く(置く順番が異なる)
    • evs2strs(self,evs) は evの配列等を、str形式の配列で返す
    .....省略
        def bscore(self):
    	stone_cnt = [0, 0, 0, 0, 0]
    	for rv in range(BVCNT):
    	    v = rv2ev(rv)
    	    c = self.color[v]
    	    if c <= 1:
    		stone_cnt[c] += 1
    	    else:
    		nbr_cnt = [0, 0, 0, 0]
    		for d in dir4:
    		    nbr_cnt[self.color[v + d]] += 1
    		if nbr_cnt[0] > 0 and nbr_cnt[1] == 0:
    		    stone_cnt[0+2] += 1
    		elif nbr_cnt[1] > 0 and nbr_cnt[0] == 0:
    		    stone_cnt[1+2] += 1
    	stone_cnt[4]= stone_cnt[1] - stone_cnt[0] - KOMI + stone_cnt[1+2] - stone_cnt[0+2]
    	return stone_cnt
    
        def myShowSg(self, x):
    	print(">>>>>>>: "+x)
    	print("lib_cnt: ", end=" ")
    	print(self.sg[str2ev(x)].lib_cnt)
    	print("size   : ", end=" ")
    	print(self.sg[str2ev(x)].size)
    	print("v_atr  : ", end=" ")
    	print(str(self.sg[str2ev(x)].v_atr)+" : "+ev2str(self.sg[str2ev(x)].v_atr))
    	print("libs   : ", end=" ")
    	print(self.sg[str2ev(x)].libs)
    	for i in self.sg[str2ev(x)].libs:
    	  print(ev2str(i), end=", ")
    	print("")
    
        def myShowSgAll(self):
    	ans = [[],[]]
    	print("************ X ")
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 1:
    	    self.myShowSg(ev2str(v))
    	print("************ O ")
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 0:
    	    self.myShowSg(ev2str(v))
    
    
        def listUpStoneEv(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 0:
    	    ans[0].append(v)
    	  else:
    	    if c == 1:
    	      ans[1].append(v)
    	return ans
    
        def listUpAtr(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  v2 = self.sg[v].v_atr
    	  if self.color[v2]==2 :
    	    if c == 0:
    		ans[0].append(v2)
    	    else:
    	      if c == 1:
    		ans[1].append(v2)
    	return ans
    
        def listUpNeedCheckEvs(self):
    	ans = [[],[]]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  c2 = self.sg[v].lib_cnt
    	  if c2 == 1 :
    	    v2 = list(self.sg[v].libs)[0]
    	    if c == 0:
    		ans[0].append(v2)
    	    else:
    	      if c == 1:
    		ans[1].append(v2)
    	return ans
    
        def listUpLibsEvs(self):
    	ans = [set([]),set([])]
    	for rv in range(BVCNT):
    	  v = rv2ev(rv)
    	  c = self.color[v]
    	  if c == 0 or c == 1:
    	    ans[c] = ans[c] | self.sg[v].libs
    	ans=[set(self.filterEmpty(ans[0])),set(self.filterEmpty(ans[1]))]
    	ans.append(ans[0]|ans[1]) 
    	return ans
    
        def filterEmpty(self,listorset):
    	ans=[]
    	for v in listorset:
    	  c = self.color[v]
    	  if c == 2 :
    	    ans.append(v)
    	return ans
    
        def getDeadStonesEv(self,ev):
    	c=Board()
    	self.copy(c)
    	ans1=c.legal(ev)
    	c.play(ev)
    	return (ans1,c.remove_ev_list)
    
        def place_stones(self,evs):
    	for v in evs:
    	  self.place_stone(str2ev(v))
    
        def place_stones10(self,evs1,evs0):
    	orgturn=self.turn
    	self.turn=1
    	self.place_stones(evs1)
    	self.turn=0
    	self.place_stones(evs0)
    	self.turn=self.turn
    
        def place_stones01(self,evs0,evs1):
    	orgturn=self.turn
    	self.turn=0
    	self.place_stones(evs0)
    	self.turn=1
    	self.place_stones(evs1)
    	self.turn=self.turn
    
        def evs2strs(self,evs):
    	ans=[]
    	for v in evs:
    	  ans.append(ev2str(v))
    	return ans
    
    .....省略
    

12.2.6 IPythonを起動

ipython3

12.2.7 IPython内で以下を実行

from board import *

b=Board()                       # ボードを作成
b.place_stones10(["E5","E6"],["E7","D6","D5","E4","F6"])  # 石を置く
# F5に石を置いたら、どこが取れるか (True, [60, 71])
# 最初のTrueは置ける場所を示す
b.getDeadStonesEv(str2ev("F5")) 
# F5に石を置いたら、どこが取れるかをstr形式で ['E5', 'E6']
b.evs2strs(b.getDeadStonesEv(str2ev("F5"))[1]) 
b.showboard()               # ボードを表示
#    A  B  C  D  E  F  G  H  J
#  9 .  .  .  .  .  .  .  .  .  9
#  8 .  .  .  .  .  .  .  .  .  8
#  7 .  .  .  .  O  .  .  .  .  7
#  6 .  .  .  O  X  O  .  .  .  6
#  5 .  .  .  O  X  .  .  .  .  5
#  4 .  .  .  .  O  .  .  .  .  4
#  3 .  .  .  .  .  .  .  .  .  3
#  2 .  .  .  .  .  .  .  .  .  2
#  1 .  .  .  .  .  .  .  .  .  1
#    A  B  C  D  E  F  G  H  J
b.turn                      # 手番確認 => 0
b.turn=1
b.getDeadStonesEv(str2ev("F5")) # F5にXをおいても取れない => (True, [])
b.listUpLibsEvs()               # 石に上下で隣接してて置ける場所をリストアップ
# [{38, 48, 50, 58, 61, 69, 73, 81, 83, 93},
#  {61},
#  {38, 48, 50, 58, 61, 69, 73, 81, 83, 93}]
b.evs2strs(b.listUpLibsEvs()[2]) # 石に隣接している空の目の座標をstr形式に変換
# ['C6', 'E3', 'G6', 'D4', 'D7', 'F4', 'F7', 'F5', 'C5', 'E8']

12.3 この章でのまとめ

  • Boardクラスのメンバ関数の拡張を行った
  • 事前に取れる石のチェックを出来るようになった

13 今後

  • こんぱ今後も文書追加していきます。

14 この文書のチェンジログ

  • 2020/02/03 初版
  • 2020/02/05 Boardクラスの調査2の章を追加
  • 2020/02/09 評価関数で、好きな盤の状態を評価させてみた の章追加
  • 2020/02/10 任意の盤を与えてお勧めの手をゲット の章追加
  • 2020/03/05 Groupクラスの調査 の章追加
  • 2020/03/06 Boardクラスのscore関数の調査 の章追加
  • 2020/03/06 Boardクラスのコピー方法について調査 の章追加
  • 2020/03/13 幾つかの調査関数をBoardクラスのメンバ関数に組み込み の章追加
  • 2020/03/14 playした時に取り除いた石のev値を保持するように改造 の章追加
  • 2020/03/14 Boardクラスのメンバ関数拡張 の章追加
  • 2020/03/15 Boardクラスのメンバ関数拡張2(わかりやすいStoneGroup機能追加) の章追加
  • 2020/04/04 Boardクラスのメンバ関数拡張2(わかりやすいStoneGroup機能追加) の章削除(バグがありました)

著者: NM Max

Created: 2020-04-04 土 20:52

Validate

機械学習ライブラリTensorFlow超入門

TensorFlow超入門

1 概要

1.1 TensorFlowの概要

  • Pythonが人気になった一番の理由かもしれない、超有名AIライブラリ
  • 最新バージョンのバイナリ配布物はCPUの拡張命令であるAVXをサポートされている必用あり(AVX無しタイプのバイナリを生成すれば、AVX拡張命令の無いCPUでも実行可能)

1.2 この文書の概要

  • TensorFlow関係の入門者用文書
  • Dockerイメージを利用して行う
  • 実際の作業部分を真似しやすいように作成
  • 学習手順として、実際やってみてから、修正したり調べた方が効率良いケースが多い為
  • ベースはTensorflowの本家の文書なので、この文書のライセンスもTensorflowの本家と同じとします。

2 リンク

3 インストール(今後動画では直接環境にインストールするのではなく、Docker経由で作業を行います。次の章で使うDocker イメージを作成します。)

  • 最新バイナリはCPUの拡張命令AVXを利用するバイナリになっています。AVX命令をサポートしていないCPUの場合は、1.5以前のバージョンのtensorflowを使えば、コンパイル無しに利用可能(コンパイルルすれば、新しいバージョンでも使えますが、マシン性能にもよりますが、コンパイルに24時間程度必用)
  • 環境差を軽減するため、Dockerを利用して作業していきます。
  • WindowsやMacの場合、Ubuntu等Linuxの仮想環境や模擬環境であれば、ほぼ同じ操作で可能だと思います。
  • 直接インストールしてもほぼ同じような手順で作業可能

3.1 以下の操作を行っている動画


3.2 Dockerによるローカルへのインストール手順

  • まずDockerをインストールしてください。「利用OS Docker インストール」でネット検索あるいは、Docker本家の文書にインストール手順https://docs.docker.com/install/が確認出来ます。
  • Linux系なら、docker.io パッケージをインストール(Debian,Ubuntuなら sudo apt install docker.io )で簡単にインストール出来ます。

3.2.1 Dockerで提供されているtensorflow/tensorflowのイメージpull

docker pull tensorflow/tensorflow
docker pull tensorflow/tensorflow:latest-py3-jupyter

3.2.2 動作確認

  • 以下の起動コマンドはhttps://hub.docker.com/r/tensorflow/tensorflow/で確認可能、一番下のRunning Containersに説明あり(ここでは説明していない起動方法もあり)
  • 以下のコマンドを実行し、表示されるlocalhost:8888のURLをブラウザで開く
docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 tensorflow/tensorflow:latest-py3-jupyter
  • ブラウザじゃなくて、コマンドラインで動かしたい場合は以下
docker run -it --rm tensorflow/tensorflow bash

4 最初の実行

4.1 関係する部分のリファレンス

4.2 本家のBeginner quickstart部分

#!/usr/bin/env python
# coding: utf-8

# In[1]:


# tutorial 
# https://www.tensorflow.org/tutorials
# https://www.tensorflow.org/tutorials/quickstart/beginner
import tensorflow as tf
import numpy as np
tf.__version__


# In[2]:


mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()  # データ読み込み
x_train, x_test = x_train / 255.0, x_test / 255.0         # 正規化


# In[3]:


# モデルの構築
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),          # 入力の形式指定
  tf.keras.layers.Dense(128, activation='relu'),          # 活性化関数としてrelu(ランプ関数)を使って、ノード128のlayer作成
  tf.keras.layers.Dropout(0.2),                           # 過学習を軽減する為らしい
  tf.keras.layers.Dense(10, activation='softmax')         # 関数softmax
])

model.compile(optimizer='adam',
	      loss='sparse_categorical_crossentropy',
	      metrics=['accuracy'])


# In[4]:


model.fit(x_train, y_train, epochs=5)

model.evaluate(x_test,  y_test, verbose=2)


# In[5]:


x_train.shape


# In[6]:


y_train.shape


# In[7]:


x_train[0][0]


# In[8]:


len(np.array(x_train)[0])


# In[9]:


y_train[2]


# In[10]:


x_train[0]


# In[11]:


import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.imshow(x_train[2], cmap="gray")
print(y_train[2])


# In[12]:


model.predict(x_train)


# In[13]:


type(x_train)


# In[14]:


type(x_train[0])


# In[15]:


model.predict_classes(np.stack([x_train[0],x_train[1]]))


# In[16]:


(y_train[0],y_train[1])


# In[17]:


ps=model.predict_classes(x_test)


# In[18]:


ps


# In[19]:


fx=x_test[ps!=y_test]
fy=y_test[ps!=y_test]
fps=ps[ps!=y_test]
fps2=y_test[ps!=y_test]


# In[20]:


[fx.shape,fy.shape]


# In[21]:


fps


# In[22]:


fps2


# In[23]:


fig2, ax2 = plt.subplots()
ax2.imshow(fx[0], cmap="gray")


# In[24]:


fig3, ax3 = plt.subplots()
ax3.imshow(fx[1], cmap="gray")


# In[25]:


print(y_test.shape)


# In[26]:


100.0*len(fx)/len(y_test)


# In[27]:


model.evaluate(x_test,  y_test, verbose=2)


# In[ ]:
  • 上を実行したら
In [1]:
# tutorial 
# https://www.tensorflow.org/tutorials
# https://www.tensorflow.org/tutorials/quickstart/beginner
import tensorflow as tf
import numpy as np
tf.__version__
Out[1]:
'2.1.0'
In [2]:
mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
In [3]:
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
In [4]:
model.fit(x_train, y_train, epochs=5)

model.evaluate(x_test,  y_test, verbose=2)
Train on 60000 samples
Epoch 1/5
60000/60000 [==============================] - 6s 106us/sample - loss: 0.3013 - accuracy: 0.9128
Epoch 2/5
60000/60000 [==============================] - 6s 100us/sample - loss: 0.1450 - accuracy: 0.9567
Epoch 3/5
60000/60000 [==============================] - 6s 101us/sample - loss: 0.1108 - accuracy: 0.9673
Epoch 4/5
60000/60000 [==============================] - 6s 102us/sample - loss: 0.0891 - accuracy: 0.9724
Epoch 5/5
60000/60000 [==============================] - 6s 101us/sample - loss: 0.0775 - accuracy: 0.9751
10000/10000 - 1s - loss: 0.0728 - accuracy: 0.9780
Out[4]:
[0.07283716697944329, 0.978]
In [5]:
x_train.shape
Out[5]:
(60000, 28, 28)
In [6]:
y_train.shape
Out[6]:
(60000,)
In [7]:
x_train[0][0]
Out[7]:
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [8]:
len(np.array(x_train)[0])
Out[8]:
28
In [9]:
y_train[2]
Out[9]:
4
In [10]:
x_train[0]
Out[10]:
array([[0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.01176471, 0.07058824, 0.07058824,
        0.07058824, 0.49411765, 0.53333333, 0.68627451, 0.10196078,
        0.65098039, 1.        , 0.96862745, 0.49803922, 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.11764706, 0.14117647,
        0.36862745, 0.60392157, 0.66666667, 0.99215686, 0.99215686,
        0.99215686, 0.99215686, 0.99215686, 0.88235294, 0.6745098 ,
        0.99215686, 0.94901961, 0.76470588, 0.25098039, 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.19215686, 0.93333333, 0.99215686,
        0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.99215686,
        0.99215686, 0.99215686, 0.98431373, 0.36470588, 0.32156863,
        0.32156863, 0.21960784, 0.15294118, 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.07058824, 0.85882353, 0.99215686,
        0.99215686, 0.99215686, 0.99215686, 0.99215686, 0.77647059,
        0.71372549, 0.96862745, 0.94509804, 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.31372549, 0.61176471,
        0.41960784, 0.99215686, 0.99215686, 0.80392157, 0.04313725,
        0.        , 0.16862745, 0.60392157, 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.05490196,
        0.00392157, 0.60392157, 0.99215686, 0.35294118, 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.54509804, 0.99215686, 0.74509804, 0.00784314,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.04313725, 0.74509804, 0.99215686, 0.2745098 ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.1372549 , 0.94509804, 0.88235294,
        0.62745098, 0.42352941, 0.00392157, 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.31764706, 0.94117647,
        0.99215686, 0.99215686, 0.46666667, 0.09803922, 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.17647059,
        0.72941176, 0.99215686, 0.99215686, 0.58823529, 0.10588235,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.0627451 , 0.36470588, 0.98823529, 0.99215686, 0.73333333,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.97647059, 0.99215686, 0.97647059,
        0.25098039, 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.18039216,
        0.50980392, 0.71764706, 0.99215686, 0.99215686, 0.81176471,
        0.00784314, 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.15294118, 0.58039216, 0.89803922,
        0.99215686, 0.99215686, 0.99215686, 0.98039216, 0.71372549,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.09411765, 0.44705882, 0.86666667, 0.99215686, 0.99215686,
        0.99215686, 0.99215686, 0.78823529, 0.30588235, 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.09019608, 0.25882353,
        0.83529412, 0.99215686, 0.99215686, 0.99215686, 0.99215686,
        0.77647059, 0.31764706, 0.00784314, 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.07058824, 0.67058824, 0.85882353, 0.99215686,
        0.99215686, 0.99215686, 0.99215686, 0.76470588, 0.31372549,
        0.03529412, 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.21568627,
        0.6745098 , 0.88627451, 0.99215686, 0.99215686, 0.99215686,
        0.99215686, 0.95686275, 0.52156863, 0.04313725, 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.53333333,
        0.99215686, 0.99215686, 0.99215686, 0.83137255, 0.52941176,
        0.51764706, 0.0627451 , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.        ]])
In [11]:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.imshow(x_train[2], cmap="gray")
print(y_train[2])
4
In [12]:
model.predict(x_train)
Out[12]:
array([[3.1222185e-11, 6.9625267e-10, 4.9216315e-09, ..., 9.0638885e-10,
        6.4819944e-10, 5.1220550e-08],
       [9.9997747e-01, 3.0144658e-11, 2.0699679e-05, ..., 2.7271714e-09,
        1.1915243e-09, 1.8208118e-06],
       [5.7959029e-09, 2.2825763e-05, 1.6314464e-04, ..., 2.7926173e-05,
        5.3994507e-05, 1.9133378e-05],
       ...,
       [5.1175184e-12, 8.8972918e-09, 4.4402681e-13, ..., 1.0011616e-10,
        5.6010720e-08, 1.8483890e-06],
       [4.7604684e-05, 1.5032154e-07, 1.6677732e-05, ..., 3.6445201e-07,
        1.3603052e-07, 1.1720140e-08],
       [9.7213610e-04, 5.9256303e-07, 1.5326268e-04, ..., 1.7348322e-05,
        9.9865472e-01, 1.6498259e-04]], dtype=float32)
In [13]:
type(x_train)
Out[13]:
numpy.ndarray
In [14]:
type(x_train[0])
Out[14]:
numpy.ndarray
In [15]:
model.predict_classes(np.stack([x_train[0],x_train[1]]))
Out[15]:
array([5, 0])
In [16]:
(y_train[0],y_train[1])
Out[16]:
(5, 0)
In [17]:
ps=model.predict_classes(x_test)
In [18]:
ps
Out[18]:
array([7, 2, 1, ..., 4, 5, 6])
In [19]:
fx=x_test[ps!=y_test]
fy=y_test[ps!=y_test]
fps=ps[ps!=y_test]
fps2=y_test[ps!=y_test]
In [20]:
[fx.shape,fy.shape]
Out[20]:
[(220, 28, 28), (220,)]
In [21]:
fps
Out[21]:
array([6, 9, 8, 2, 0, 4, 7, 7, 0, 9, 0, 2, 6, 8, 4, 9, 8, 9, 9, 9, 4, 0,
       5, 2, 8, 6, 8, 0, 1, 2, 4, 9, 5, 1, 2, 3, 6, 3, 0, 1, 9, 5, 7, 6,
       4, 6, 0, 7, 0, 2, 8, 3, 4, 0, 2, 0, 9, 2, 9, 8, 9, 9, 1, 0, 7, 0,
       9, 1, 5, 2, 5, 6, 6, 0, 0, 1, 1, 0, 4, 5, 1, 1, 4, 9, 0, 2, 2, 7,
       5, 7, 2, 9, 0, 9, 9, 9, 0, 1, 4, 2, 0, 3, 0, 3, 2, 6, 3, 1, 4, 3,
       3, 6, 5, 8, 1, 4, 4, 9, 3, 3, 7, 9, 7, 8, 3, 7, 5, 7, 3, 3, 4, 7,
       1, 5, 9, 9, 4, 5, 6, 3, 0, 4, 0, 6, 8, 4, 1, 2, 0, 2, 6, 8, 9, 8,
       7, 6, 0, 2, 9, 3, 8, 3, 8, 9, 9, 0, 9, 9, 3, 3, 8, 6, 0, 9, 7, 6,
       7, 8, 0, 7, 6, 8, 8, 8, 9, 8, 8, 8, 9, 7, 2, 6, 6, 9, 6, 2, 2, 2,
       2, 5, 4, 8, 7, 3, 8, 6, 0, 6, 2, 0, 0, 0, 0, 1, 4, 7, 8, 0, 2, 6])
In [22]:
fps2
Out[22]:
array([5, 4, 9, 4, 6, 8, 2, 3, 6, 4, 8, 8, 4, 1, 8, 4, 5, 7, 4, 8, 5, 6,
       6, 7, 6, 4, 3, 4, 6, 7, 9, 4, 9, 7, 7, 8, 8, 5, 7, 7, 7, 1, 8, 4,
       6, 2, 2, 3, 8, 7, 2, 8, 9, 5, 7, 2, 8, 7, 7, 4, 4, 7, 8, 2, 3, 6,
       4, 6, 3, 1, 0, 5, 5, 8, 9, 9, 2, 2, 2, 3, 7, 6, 9, 4, 8, 3, 3, 9,
       3, 9, 1, 5, 6, 8, 7, 4, 6, 9, 6, 3, 5, 9, 7, 2, 7, 4, 7, 7, 9, 5,
       1, 4, 3, 2, 7, 9, 9, 0, 8, 9, 2, 7, 9, 2, 5, 2, 9, 3, 5, 5, 9, 8,
       9, 6, 4, 7, 8, 3, 4, 8, 6, 9, 9, 8, 0, 8, 7, 3, 3, 7, 1, 1, 7, 1,
       3, 8, 7, 4, 4, 5, 3, 5, 3, 3, 3, 2, 3, 3, 9, 9, 5, 2, 9, 8, 9, 2,
       0, 0, 9, 8, 1, 4, 4, 5, 8, 1, 5, 2, 3, 4, 7, 0, 8, 4, 5, 7, 7, 7,
       7, 8, 9, 0, 2, 6, 2, 5, 4, 5, 4, 2, 5, 5, 2, 4, 9, 2, 6, 6, 3, 5],
      dtype=uint8)
In [23]:
fig2, ax2 = plt.subplots()
ax2.imshow(fx[0], cmap="gray")
Out[23]:
<matplotlib.image.AxesImage at 0x7f9e6c78a4a8>
In [24]:
fig3, ax3 = plt.subplots()
ax3.imshow(fx[1], cmap="gray")
Out[24]:
<matplotlib.image.AxesImage at 0x7f9e6c73d2b0>
In [25]:
print(y_test.shape)
(10000,)
In [26]:
100.0*len(fx)/len(y_test)
Out[26]:
2.2
In [27]:
model.evaluate(x_test,  y_test, verbose=2)
10000/10000 - 1s - loss: 0.0728 - accuracy: 0.9780
Out[27]:
[0.07283716697944329, 0.978]
In [ ]:
 

4.3 この章のまとめ

  • 実際に学習させ、学習させたものを評価してみた
  • データがどのようになっているのか確認した

5 サンプル classification.ipynb (Fashion MNIST dataset)

  • Docker image tensorflow/tensorflow に含まれているサンプル
  • 中身は前章のサンプルとほぼ同じで、違うのは、データの指定
fashion_mnist = keras.datasets.fashion_mnist
  • なので前章でやったものを以下に修正
# mnist = tf.keras.datasets.mnist
mnist = tf.keras.datasets.fashion_mnist
  • なので前章のデータを keras.datasets.fashion_mnist にしてやればほぼ同じ
  • あと学習のepochの数値が5->10になっている
  • ここでは、前章のファイルのデータ読み込み部分だけ変更して実行してみる
  • 後でサンプルを実行して内容確認してみてください。
  • サンプルファイルを開いて、Shift+Enter連打で動きます。
  • イメージの起動は以下のコマンド
docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 tensorflow/tensorflow:latest-py3-jupyter

5.1 以下の操作を行っている動画


6 サンプル regression.ipynb (車の燃費関係のデータ)

  • Docker image tensorflow/tensorflow に含まれているサンプル
  • gitをインストールしないと動かないので、シェルを起動して、gitをインストール
apt install git
  • 後はサンプルファイルを開いて、Shift+Enter連打で動きます。
  • イメージの起動は以下のコマンド
docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 tensorflow/tensorflow:latest-py3-jupyter

6.1 以下の操作を行っている動画


7 サンプル object_detection.ipynbを動かしてみる

7.1 以下の操作を行っている動画


7.2 事前準備

  • 以下のコマンドを実行し、表示されるlocalhost:8888のURLをブラウザで開く
docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 tensorflow/tensorflow:latest-py3-jupyter
  • 必用なフォントと、必用なパッケージを追加でインストール(シェルを立ち上げて)
pip3 install tensorflow_hub
pip3 install pillow
apt install fonts-liberation
  • 元のノートをダウンロード、コマンドラインで行うなら以下、ブラウザでダウンロードして、ホームディレクトリのnotebooksフォルダに入れてもOK
cd ~/notebooks/
wget https://github.com/tensorflow/hub/raw/master/examples/colab/object_detection.ipynb

7.3 ソースの修正

def draw_boxes(image, boxes, class_names, scores, max_boxes=10, min_score=0.1):
...省略
      display_str = "{}: {}%".format(class_names[i].numpy().decode("ascii"),
                                     int(100 * scores[i]))
  • 上の部分を以下に修正(numpy()を除く)
def draw_boxes(image, boxes, class_names, scores, max_boxes=10, min_score=0.1):
...省略
      display_str = "{}: {}%".format(class_names[i].decode("ascii"),
                                     int(100 * scores[i]))

7.4 実行

  • Shift + Enter を押しまくり、実行
  • 最後にシートを保存

7.5 この章について

  • object detectionのサンプルソースを動かしてみた
  • すでに訓練してくれてるデータが配布されていた
  • 一部ソースを修正しないと動かなかった
  • Dockerのtensorflow/tensorflowのイメージで動かすには追加のパッケージをインストールする必用があった

8 モデルの保存と読み込み

8.1 以下の操作を行っている動画


8.2 保存する命令

  • 色々保存する種類があるが、ディレクトリに保存する場合
  • tensorflow/tensflowに含まれているサンプル(save_and_load.ipynb) の例
  • saved_modelディレクトリにmy_modelで保存する場合
.... ここまでにモデルを作成し、学習した後に
!mkdir -p saved_model
model.save('saved_model/my_model') 

8.3 読み込む命令

  • tensorflow/tensflowに含まれているサンプル(save_and_load.ipynb) の例
  • saved_modelディレクトリにmy_modelを保存してある場合
  • new_modelに読み込み
new_model = tf.keras.models.load_model('saved_model/my_model')

9 続きを追記してきます。

10 この文書のチェンジログ

  • 2020/01/23 初版
  • 2020/01/24 3,4章追加
  • 2020/01/24 5章 サンプル object_detection.ipynbを動かしてみる を追加

著者: NM Max

Created: 2020-01-27 月 21:44

Validate

Lenovo-G580で利用可能と思われるCPUについて

前の記事でG570の交換可能CPUを調べたので、今度はG580についても同じように調べてみました。(チップセットを調べて、そのチップセットで利用可能なCPUを調べる)

G580のチップセットは「G580 チップセット」でネット検索すると、ここがヒットしました。「モバイル インテル® HM76 Express チップセット」とのことです。

このチップセットに対応しているCPUは、ここに情報がありました。このページの左下の「対応する製品」をたどると、対応CPUがでてきます。

製品のマニュアルがここにありました。ハードウェア関係のマニュアルもみつけて、これみれば、もっと簡単にCPUの交換できてたきがした。こないだ交換した時きづけてなかった。

製品のラインナップで使われていたCPUはここで確認できました。(G580製品一覧でネット検索)