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