GithubHelp home page GithubHelp logo

reversi_board's People

Contributors

dotnsf avatar

Watchers

 avatar

reversi_board's Issues

処理結果に矛盾がある

例えば以下の条件を満たすレコードは存在していないはずだが、(depth = 8 くらいになると)実際にはある:

select count(*) from reversi where ( depth + 4 < player0_count + player1_count ) or ( depth + next_choices_num > 12 );

bot.js と analytics.js の統合

どちらの機能を使うべきか、も自動判断する

サーバーは next_processed_num != 1 のレコードが存在していたら旧 bot.js の、存在していなかったら analytics.js の処理を行うためのレコードを返す。

クライアントは返されたレコードの next_processed_num の値を見て、1 以外だったら旧 bot.js の、1 だったら analytics の処理を行う。

CORS 対応

bot はブラウザを使うわけではない(REST API を使うだけ)ので、CORS 対応自体が不要?

reversi テーブル変更

create table reversi(
  id bigserial not null,
  parent_id bigint default -1,   //. 1つ前の board の id
  next_id bigint default -1,  //. 1つ先の節が既存している場合の行先 id
  next_idx int default -1,  //. next_id が存在している場合、boards の何番目にリンクするか
  board_size int default -1,
  depth int default -1,
  //choice_idx int default -1,
  //choice_x int default -1,
  //choice_y int default -1,
  board text default '',   //. 現在のボード状態を1次配列で表したものを文字列化したもの
  boards text default '',  //. 現在のボード状態を1次配列で表した複数の状態(上下左右回転を考慮)を昇順に並べて文字列化して ":" でつないだもの
  next_choices text default '',
  next_choices_num int default -1,
  process_status int default 0,  //. これまで next_processed_num として使っていたものの列名を変更
  player0_count int default -1,
  player1_count int default -1,
  next_player int default 0,  //. -1 or 1。0 の場合は終了
  value int default 0,
  value_status default 0,
  created bigint default 0,
  updated bigint default 0,
  primary key (id)
);
create index on reversi ( board_size, next_choices_num, process_status, updated );
alter table reversi add unique( boards, next_player );

ステータスが -1 のものを対象とするかしないかを分けて処理可能な bot

-1 のものは(別の誰かが処理中、ということを意味するので)対象外としないと、分散処理時の効率が悪くなる。

一方で対象外にして処理を先に進めてしまうと、親が未処理なのに子を実施することになりかねない。この事態を避けるにはどういうアルゴリズムとするべきか?

分岐は環境変数を使う?

同じ盤面かどうかの判断は「自分の boards の中に過去に記録された board があるかどうか」とする

こんな感じ

var found_id = null;
for( var i = 0; i < this.boards.length && !found_id; i ++ ){
  //. できればループではなく、1回の DB アクセスで見つけたい
  found_id = findIdByBoard( this.boards[i] );
}

if( found_id ){
  //. 過去に同じボードが見つかった
  this.next_id = found_id;
  save( this );
}else{
  //. *
}

でも初手はこれだと見つからない。* で工夫する必要がある。

New Web UI

  • コンシューマー向け UI
  • Web UI からもボタンクリック後に連続実行させる
  • 明示的に止める手段を用意

board 配列や boards 配列内の順序は縦方向

例えば、

  0  0  0  0
  0  1  1  1
  0  1 -1  0
  0  0  0  0

の board は

[ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, -1, 0, 0, 1, 0, 0 ]

とする。

こうしておくと ( x, y ) の駒は board[board_size * x + y] で求めることができるようになる。

深読みと解析の切り替え

#14 実装後に、bot (深読み)機能から analytics(解析)機能に正しく切り替わることを確認する。そのためには bot 処理終了直前の DB データが必要。

現在の DB 状態を Web 画面に表示

GET / 内で以下の結果を表示できるように API を追加した上で status.ejs を改良する:

  • select depth,value_status,count(*) from reversi group by depth, value_status order by depth, value_status;

HTTP を使わない bot

REST API ではなく、スタンドアロンで直接関数を実行するようなイメージ。高速化のため。

自分一人で調査する時のためだけにしか使わないので、需要については疑問。

ミニマックス戦略で先手(後手)の最適解を求める

アルゴリズム(先手の最適手を求める)

  • max(depth) が偶数であることを(後手が最後の手を選択していることを)確認する
  • reversi から全レコードを以下の条件で取得
    • 取り出すのは id, parent_id, ( board_size, ) depth, choice_idx, player0_count, next_player
    • board_size は指定の固定値
    • depth の大きい順, parent_id の小さい順, choice_idx の小さい順
  • (*) 同じ depth を持ち、同じ parent_id を持つレコードカテゴリごとに player0_count の最小値を求めて、この parent_idid として持つレコードの player0_count とする
  • depth を1つ減らして、(*) と同じ計算を行う。ただし求めるのは player0_count の最小値ではなく最大値
  • depth を1つ減らして、(*) と同じ計算を行う。ただし求めるのは player0_count の最大値ではなく最小値
  • depth = 0 になるまで (*) を繰りかえす
  • depth = 0 の時に求めた player0_countboard_size * board_size / 2 よりも小さい場合は後手必勝、大きい場合は先手必勝

k8s 対応

IBM Cloud の 30 日間無料 k8s でも動くようにする

reversi オブジェクトを変更

var reversi = class{
  //. コンストラクタの引数は整数または文字列(JSON オブジェクトは使わない)
  constructor( id, parent_id, next_id, next_idx, board_size, depth, board, boards, next_player ){
    this.id = id;
    this.parent_id = parent_id;
    this.next_id = next_id;
    this.next_idx = this.next_idx;
    this.board_size = board_size;
    this.depth = depth;
    this.board = JSON.parse( board );
    this.boards = JSON.parse( boards.split( ":" ) );
    this.next_player = next_player;

    //. ここから下はすべて計算で求める
    this.next_choices = [];
    this.next_choices_num = 0;
    this.process_status = 0;
    this.player0_count = 0;
    this.player1_count = 0;
    this.value = 0;
    this.value_status = 0;
  };

#22 の問題を解決する現実的なアイデア

1手目を4つではなく(どうせ同じなので)1つだけ選んで進めた場合でも、depth = 9 は4分の1になるが depth = 10, 11, .. と進めていくとすぐに非現実的な数字になってしまいそう。思っていたよりも限界が早かった。。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.