目指せ!第14回UEC杯コンピューター囲碁大会<本編> Step [O12o__11o__100o0] データファイル作成 ~ Step [O12o__11o__10o0] 連データベース定義 ~ Step [O12o__11o__10o5o__10o0] 連データベースのロード
連載の目次
Step [O12o__11o__100o0] データファイル作成 - data/ren_db1.json ファイル
あとで使うファイルを先に作成する
👇 以下のファイルを新規作成してほしい
📂 kifuwarabe-uec14
├── 📂 data
👉 │ └── 📄 ren_db1.json
├── 📂 kernel
│ ├── 📄 go.mod
│ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
{
"header": {
"boardWidth": 19,
"boardHeight": 19
},
"rens": {
"001,01A": {
"stone": "x",
"locate": "A1",
"liberty": "B1 A2"
},
"001,06N": {
"stone": ".",
"locate": "N6",
"liberty": ""
},
"001,13E": {
"stone": "o",
"locate": "E13",
"liberty": "E12 D13"
}
}
}
Step [O12o__11o__101o0]
Removed
Step [O12o__11o__10o0] 連データベース定義
- 取った石の場所を記憶しておく構造を作成する
- 入出力ファイルの構造でもある
📖 目指せ!第14回UEC杯コンピューター囲碁大会☆(^q^)<その4>
Step [O12o__11o__10o1o0]
Removed
Step [O12o__11o__10o2o0] ファイル作成 - ren_db.go ファイル
👇 以下のファイルを新規作成してほしい
📂 kifuwarabe-uec14
├── 📂 kernel
│ ├── 📄 go.mod
│ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ ├── 📄 o12o__10o1o0_point.go
│ ├── 📄 ren_db_item.go
👉 │ ├── 📄 ren_db.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
// BOF [O12o__11o__10o2o0]
package kernel
import (
"encoding/json"
"fmt"
"os"
"strings"
)
// RenId - 連データベースに格納される連のId
// * 外部ファイルの可読性を優先して数値型ではなく文字列
type RenId string
// GetRenId - 連のIdを取得
func GetRenId(boardMemoryWidth int, positionNthFigure int, positionNumber int, minimumLocation Point) RenId {
var posNth = positionNumber + geta
var coord = getRenIdFromPointOnBoard(boardMemoryWidth, minimumLocation)
return RenId(fmt.Sprintf("%0*d,%s", positionNthFigure, posNth, coord))
}
// RenDb - 連データベース
type RenDb struct {
// Header - ヘッダー
Header RenDbDocHeader `json:"header"`
// 要素
Rens map[RenId]*Ren `json:"rens"`
}
// NewRenDb - 連データベースを新規作成
func NewRenDb(boardWidth int, boardHeight int) *RenDb {
var db = new(RenDb)
db.Header.Init(boardWidth, boardHeight)
db.Rens = make(map[RenId]*Ren)
return db
}
// Init - 初期化
func (db *RenDb) Init(boardWidth int, boardHeight int) {
db.Header.Init(boardWidth, boardHeight)
// Clear
for ri := range db.Rens {
delete(db.Rens, ri)
}
}
// Save - 連データベースの外部ファイル書込
func (db *RenDb) Save(path string, convertLocation func(Point) string, onError func(error) bool) bool {
// 外部ファイルに出力するための、内部状態の整形
db.RefreshToExternalFile(convertLocation)
// Marshal関数でjsonエンコード
// ->返り値jsonDataにはエンコード結果が[]byteの形で格納される
jsonBinary, errA := json.Marshal(db)
if errA != nil {
return onError(errA)
}
// ファイル読込
var errB = os.WriteFile(path, jsonBinary, 0664)
if errB != nil {
return onError(errB)
}
return true
}
// FindRen - 連を取得
func (db *RenDb) GetRen(renId RenId) (*Ren, bool) {
var ren, isOk = db.Rens[renId]
if isOk {
return ren, true
}
return nil, false
}
// RegisterRen - 連を登録
// * すでに Id が登録されているなら、上書きしない
func (db *RenDb) RegisterRen(positionNthFigure int, positionNumber int, ren *Ren) {
var renId = GetRenId(db.Header.GetBoardMemoryWidth(), positionNthFigure, positionNumber, ren.minimumLocation)
var _, isExists = db.Rens[renId]
if !isExists {
db.Rens[renId] = ren
}
}
// Dump - ダンプ
func (db *RenDb) Dump() string {
var sb strings.Builder
// 全ての要素
for idStr, item := range db.Rens {
sb.WriteString(fmt.Sprintf("[%s]%s ", idStr, item.Dump()))
}
var text = sb.String()
if 0 < len(text) {
text = text[:len(text)-1]
}
return text
}
// RefreshToExternalFile - 外部ファイルに出力されてもいいように内部状態を整形します
func (db *RenDb) RefreshToExternalFile(convertLocation func(Point) string) {
for _, ren := range db.Rens {
ren.RefreshToExternalFile(convertLocation)
}
}
// RenDbDocHeader - ヘッダー
type RenDbDocHeader struct {
// BoardWidth - 盤の横幅
BoardWidth int `json:"boardWidth"`
// BoardHeight - 盤の縦幅
BoardHeight int `json:"boardHeight"`
}
// Init - 初期化
func (h *RenDbDocHeader) Init(boardWidth int, boardHeight int) {
h.BoardWidth = boardWidth
h.BoardHeight = boardHeight
}
// GetBoardMemoryArea - 枠付き盤の面積
func (h *RenDbDocHeader) GetBoardMemoryArea() int {
return h.GetBoardMemoryWidth() * h.GetBoardMemoryHeight()
}
// GetBoardMemoryWidth - 枠付き盤の横幅
func (h *RenDbDocHeader) GetBoardMemoryWidth() int {
return h.BoardWidth + bothSidesWallThickness
}
// GetBoardMemoryHeight - 枠付き盤の縦幅
func (h *RenDbDocHeader) GetBoardMemoryHeight() int {
return h.BoardHeight + bothSidesWallThickness
}
// EOF [O12o__11o__10o2o0]
Step [O12o__11o__10o3o0] ファイル編集 - kernel.go ファイル
👇 以下の既存ファイルを編集してほしい
📂 kifuwarabe-uec14
├── 📂 kernel
│ ├── 📄 go.mod
👉 │ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ ├── 📄 o12o__10o1o0_point.go
│ ├── 📄 ren_db_item.go
│ ├── 📄 ren_db.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
// ...略...
// type Kernel struct {
// ...略...
// * 以下を追加
// RenDb - [O12o__11o__10o3o0] 連データベース
renDb *RenDb
// }
// ...略...
// func NewDirtyKernel(boardWidht int, boardHeight int,
// ...略...
// * 以下を追加
// RenDb - [O12o__11o__10o3o0] 連データベース
k.renDb = NewRenDb(k.Position.Board.coordinate.GetWidth(), k.Position.Board.coordinate.GetHeight())
// return k
// }
// ...略...
Step [O12o__11o__10o4o0] コマンド編集 - kernel.go ファイル
👇 以下の既存ファイルを編集してほしい
📂 kifuwarabe-uec14
├── 📂 kernel
│ ├── 📄 go.mod
👉 │ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ ├── 📄 o12o__10o1o0_point.go
│ ├── 📄 ren_db_item.go
│ ├── 📄 ren_db.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
👇 がんばって、 Execute メソッドに挿入してほしい
// ...略...
// この下にコマンドを挟んでいく
// -------------------------
// ...略...
// * アルファベット順になる位置に、以下のケース文を挿入
case "rendb_dump": // [O12o__11o__10o4o0]
var text = k.renDb.Dump()
logg.C.Info("= dump'''%s\n'''\n", text)
logg.J.Infow("ok", "dump", text)
return true
case "rendb_save": // [O12o__11o__10o4o0]
// Example: `rendb_save data/ren_db1_temp.json`
// * ファイルパスにスペースがはいっていてはいけない
var path = tokens[1]
var convertLocation = func(location Point) string {
return k.Position.Board.coordinate.GetGtpMoveFromPoint(location)
}
var onError = func(err error) bool {
logg.C.Infof("? error:%s\n", err)
logg.J.Infow("error", "err", err)
return false
}
var isOk = k.renDb.Save(path, convertLocation, onError)
if isOk {
logg.C.Infof("=\n")
logg.J.Infow("ok")
return true
}
return false
// ...略...
// この上にコマンドを挟んでいく
// -------------------------
// ...略...
Step [O12o__11o__10o5o__10o0] 連データベースのロード
連データベースをロードするには、盤のサイズも、連も既知でないといけない
盤のサイズ、連の定義を終えた段階で、連データベースのロードを実装する
Step [O12o__11o__10o5o__10o_10o0] ファイル作成 - kernel/kernel_facade.go ファイル
👇 以下のファイルを新規作成してほしい
📂 kifuwarabe-uec14
├── 📂 kernel
│ ├── 📄 go.mod
👉 │ ├── 📄 kernel_facade.go
│ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ ├── 📄 o12o__10o1o0_point.go
│ ├── 📄 ren_db_item.go
│ ├── 📄 ren_db.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
// BOF [O12o__11o__10o5o__10o0]
package kernel
import (
"encoding/json"
"os"
)
// LoadRenDb - [O12o__11o__10o5o__10o_10o0] 連データベースの外部ファイル読取
func (k *Kernel) LoadRenDb(path string, onError func(error) bool) bool {
// ファイル読込
var binary, errA = os.ReadFile(path)
if errA != nil {
return onError(errA)
}
var db = new(RenDb)
var errB = json.Unmarshal(binary, db)
if errB != nil {
return onError(errB)
}
// 外部ファイルからの入力を、内部状態へ適用
for _, ren := range db.Rens {
var isOk = k.RefreshRenToInternal(ren)
if !isOk {
return false
}
}
// 差し替え
k.renDb = db
return true
}
// RefreshRenToInternal - TODO 外部ファイルから入力された内容を内部状態に適用します
func (k *Kernel) RefreshRenToInternal(r *Ren) bool {
{
var getDefaultStone = func() (bool, Stone) {
panic(fmt.Sprintf("unexpected stone:%s", r.Sto))
}
// TODO stone from r.Sto
// Example: "x" --> black
var isOk, stone = GetStoneFromChar(r.Sto, getDefaultStone)
if !isOk {
return false
}
r.stone = stone
}
{
// TODO locations from r.Loc
// Example: "C1 D1 E1"
if 0 < len(r.Loc) {
var codes = strings.Split(r.Loc, " ")
var numbers = []Point{}
for _, code := range codes {
var location = k.Position.Board.coordinate.GetPointFromGtpMove(code)
numbers = append(numbers, location)
}
r.locations = numbers
}
}
{
// TODO libertyLocations from r.LibLoc
// Example: "F1 E2 D2 B1 C2"
if 0 < len(r.LibLoc) {
var codes = strings.Split(r.LibLoc, " ")
var numbers = []Point{}
for _, code := range codes {
var location = k.Position.Board.coordinate.GetPointFromGtpMove(code)
numbers = append(numbers, location)
}
r.libertyLocations = numbers
}
}
return true
}
// EOF [O12o__11o__10o5o__10o0]
Step [O12o__11o__10o5o__10o1o0] コマンド編集 - kernel.go ファイル
👇 以下の既存ファイルを編集してほしい
📂 kifuwarabe-uec14
├── 📂 kernel
│ ├── 📄 go.mod
👉 │ ├── 📄 kernel.go
│ ├── 📄 logger.go
│ ├── 📄 o12o__10o1o0_point.go
│ ├── 📄 ren_db_item.go
│ ├── 📄 ren_db.go
│ └── 📄 stone.go
├── 📄 .gitignore
├── 📄 engine_config.go
├── 📄 engine.toml
├── 📄 go.mod
├── 📄 go.work
└── 📄 main.go
// ...略...
// この下にコマンドを挟んでいく
// -------------------------
// ...略...
case "rendb_load": // [O12o__11o__10o5o__10o1o0]
// Example: `rendb_load data/ren_db1_temp.json`
// * ファイルパスにスペースがはいっていてはいけない
var path = tokens[1]
var onError = func(err error) bool {
logg.C.Infof("? error:%s\n", err)
logg.J.Infow("error", "err", err)
return false
}
var isOk = k.LoadRenDb(path, onError)
if isOk {
logg.C.Infof("=\n")
logg.J.Infow("ok")
return true
}
return false
// ...略...
// この上にコマンドを挟んでいく
// -------------------------
// ...略...
Step [O12o__11o__10o5o_1o0] 設定 - .gitignore ファイル
👇 以下の既存ファイルを編集してほしい
📂 kifuwarabe-uec14
👉 └── 📄 .gitignore
👇 例えば冒頭に追加
# この下に kifuwarabe-uec14 でリポジトリにコミットしないものを追加する
# ---------------------------------------------------------------
# ...略...
# [O12o__11o__10o5o_1o0]
*_temp.json
# この上に kifuwarabe-uec14 でリポジトリにコミットしないものを追加する
# ---------------------------------------------------------------
# ...略...
Step [O12o__11o__10o5o0] 動作確認
👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい
Input:
go run .
これで、思考エンジン内の入力待機ループに入った
👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい
Input:
rendb_load data/ren_db1.json
Output > Console:
[2022-09-18 21:21:15] # rendb_load data/ren_db1.json
[2022-09-18 21:21:15] =
👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい
Input:
rendb_dump
Output > Console:
[2022-09-25 22:22:44] # rendb_dump
[2022-09-25 22:22:44] = dump'''[001,01A]22
[001,06N]139
[001,13E]278
'''
👇 以下のコマンドをコピーして、ターミナルに貼り付けてほしい
Input:
rendb_save data/ren_db1_temp.json
Output > Console:
[2022-09-18 22:15:43] # rendb_save data/ren_db1_temp.json
[2022-09-18 22:15:43] =
📄 ren_db1_temp.json:
{"header":{"boardWidth":19,"boardHeight":19},"rens":{"001,01A":{"stone":".","locate":"","liberty":""},"001,06N":{"stone":".","locate":"","liberty":""},"001,13E":{"stone":".","locate":"","liberty":""}}}