2019-11-02に更新

第11回UEC杯コンピューター囲碁大会に出場しようぜ☆(^~^)?<その1>

2019-10-31 20:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 AI竜星戦2019 だとばかり思っていて 無いな……、と思ったら
↓第11回UEC杯コンピューター囲碁大会 に戻ってて わらう☆」

第11回UEC杯コンピュータ囲碁大会

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んは タイトルも読まずに 申し込んでて わらう☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 1か月ちょい前なのに 何も作ってないわよ?」

20191031wpf39.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 WPF で どうやって囲碁盤 描くのか わたしが教えてほしいぐらいだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 キャンバスか何かを全画面に出したらどうか☆?
スクロールバーや テキストボックスといった ウィジェットは 何も置くなだぜ☆
テキストは ログに吐き出して Visual studio code で開けば リアルタイムで更新されるんだぜ☆」

XAML でクラウディアさんを描いてみました
Shapes and Basic Drawing in WPF Overview

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 さっぱり分からん……☆ こいつらは XML で絵でも描いてるのか……☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 そうなんじゃないの? サンプル・プログラムをコピー貼り付けしなさいよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 貼り付けろと言ったって、 どこに 貼り付けたらいいのか分からん……☆ <Grid> タグの中でいいのか……☆?」

20191031wpf40.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑サンプル・プログラムって できたら何か 嬉しさ が沸いてくるようなもののことだろ☆
なにも嬉しさが沸いてこない このサンプルは いったい……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んは タグ打ちで 碁盤の絵を 描くつもりか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 何その苦行☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 まず背景を 緑色に パーっと塗りましょう!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 緑って オセロじゃなかっただろうか☆?」

濃い緑色(#008833)の色見本とブランドを作る配色情報のホームページ

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こういうとき 自分の想像や勘で闇雲にやるのではなく ツールや他人の資料、ひとのおススメに頼るのが上達のコツだぜ☆」

20191031wpf41.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 MainWindow に塗れたぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 その上に 黄色い正方形を置きなさいよ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 どうやって☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ググりなさいよ!」

2019-10-31 21:00頃

Geometry Overview

20191031wpf42.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑置いたが、ウィンドウ・サイズに応じてリサイズする方法が分からんぜ☆」

20191031wpf43.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑自動的に広がってくれなければ、嬉しさは 0倍……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 イベントハンドラで再計算して 更新したらいいんじゃないのか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それを自動でやってくれる便利機能は無いのかだぜ☆?」

[WPF]Canvasに表示した画像を拡大縮小を行う

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 イベントハンドラで再計算して 更新してるな……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 CSS (カスケード・スタイル・シート)にしてくれたら API(操作方法) 分かるのに……☆
.Width(ワイス)、.Height(ハイト)はあるのに .X.Y 相当のものが無いぜ☆」

How to draw a rectangle in WPF at a specific x,y screen location?
How to get a WPF window's ClientSize?

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var window = (Window)sender;
            Trace.WriteLine($"サイズチェンジ 横幅={window.Width} 縦幅={window.Height} グリッド {grid.RenderSize.Width}, {grid.RenderSize.Height}");

            // 昔でいう呼び方で Client area は WPF では grid.RenderSize らしい(^q^)
            // 短い方の一辺を求めようぜ☆(^~^)ぴったり枠にくっつくと窮屈なんで 0.95 掛けで☆(^~^)
            var shortenEdge = System.Math.Min(grid.RenderSize.Width, grid.RenderSize.Height) * 0.95;

            // センターを求めようぜ☆(^~^)
            var centerX = grid.RenderSize.Width / 2;
            var centerY = grid.RenderSize.Height / 2;

            Canvas.SetLeft(board, centerX - shortenEdge/2);
            Canvas.SetTop(board, centerY - shortenEdge/2);
            board.Width = shortenEdge;
            board.Height = shortenEdge;
        }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ググって 質問しているやつらの話しをまとめて 図形を計算すると こうだが……☆」

20191031wpf44.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 はい 使いこなした☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 そろそろ Git hub に上げろだぜ☆」

kifuwarabe-uec11-gui

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑はい あげた☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 じゃあ 横線を20本、縦線を20本 引きましょう」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 その前に インスタント・コーヒー 飲もうぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 ビールのあとに コーヒーか☆」

WPFサンプル:Line, Polyline, Polygonで直線、図形を描く
4.2 線を引く

2019-10-31 22:00頃

20191031wpf45.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
(ずーぅいい) #コーヒーを飲む音

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 線が 盤のうしろを通るんだけど☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 z-orderz-index か、何かがあるんじゃないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Panel.ZIndex というプロパティがあるな☆ これを使っていいのか知らないが、思ったような働きをするんで使おう……☆」

20191031wpf46.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 コピー貼り付けして x:Name の数字を打ち直すの めんどうなんだけど……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 なんのために GUI が上に付いてるんだぜ☆」

20191031wpf47.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ Line が なんか見えない枠の中にいて、ここから出ると 見えなくなるんだが☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 その枠は何なの? ウィンドウをリサイズするたびに 伸ばせばいいの?」

2019-10-31 23:00頃

20191031wpf48.png

            // タテ線20本☆(^~^)
            var verticalLines = new List<Line>() {
                verticalLine0,
                verticalLine1,
                verticalLine2,
                verticalLine3,
                verticalLine4,
                verticalLine5,
                verticalLine6,
                verticalLine7,
                verticalLine8,
                verticalLine9,
                verticalLine10,
                verticalLine11,
                verticalLine12,
                verticalLine13,
                verticalLine14,
                verticalLine15,
                verticalLine16,
                verticalLine17,
                verticalLine18,
                verticalLine19,
            };
            // ヨコ線20本☆(^~^)
            var horizontalLines = new List<Line>() {
                horizontalLine0,
                horizontalLine1,
                horizontalLine2,
                horizontalLine3,
                horizontalLine4,
                horizontalLine5,
                horizontalLine6,
                horizontalLine7,
                horizontalLine8,
                horizontalLine9,
                horizontalLine10,
                horizontalLine11,
                horizontalLine12,
                horizontalLine13,
                horizontalLine14,
                horizontalLine15,
                horizontalLine16,
                horizontalLine17,
                horizontalLine18,
                horizontalLine19,
            };
            // タテ線をヨコに並べるぜ☆(^~^)
            for (var column = 0; column < 20; column++)
            {
                var verticalLine = verticalLines[column];
                Canvas.SetLeft(verticalLine, 0);
                Canvas.SetTop(verticalLine, 0);
                verticalLine.Width = grid.RenderSize.Width;
                verticalLine.Height = grid.RenderSize.Height;
                verticalLine.Stroke = Brushes.Black;
                verticalLine.StrokeThickness = 1.5;
                Panel.SetZIndex(verticalLine, 110);
                // 盤の幅を21で割ろうぜ☆(^~^)
                verticalLine.X1 = boardLeft + board.Width * 0.05 + board.Width / 21 * column;
                verticalLine.Y1 = boardTop + board.Height * 0.05;
                verticalLine.X2 = verticalLine.X1;
                verticalLine.Y2 = verticalLine.Y1 + board.Height * 0.905; // 線の太さのせいでうまく合わん
            }
            // ヨコ線をタテに並べるぜ☆(^~^)
            for (var row = 0; row < 20; row++)
            {
                var horizontalLine = horizontalLines[row];
                Canvas.SetLeft(horizontalLine, 0);
                Canvas.SetTop(horizontalLine, 0);
                horizontalLine.Width = grid.RenderSize.Width;
                horizontalLine.Height = grid.RenderSize.Height;
                horizontalLine.Stroke = Brushes.Black;
                horizontalLine.StrokeThickness = 1.5;
                Panel.SetZIndex(horizontalLine, 110);
                // 盤の幅を21で割ろうぜ☆(^~^)
                horizontalLine.X1 = boardLeft + board.Width * 0.05;
                horizontalLine.Y1 = boardTop + board.Height * 0.05 + board.Height / 21 * row;
                horizontalLine.X2 = horizontalLine.X1 + board.Width * 0.905; // 線の太さのせいでうまく合わん
                horizontalLine.Y2 = horizontalLine.Y1;
            }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これを ベタ書き という☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 配列は なんとかならなかったのか……☆」

2019-11-01 20:30頃

すやぁ すやー ずぴー

ゴンッ!

KIFUWARABE_80x100x8_01_Futu.gif
「 起きろ お父ん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 石か何かが 頭に……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 夜はさっさと寝て 早く起きればいいのに……」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 起こすのか寝かすのか どちらかにしてほしい☆
WPFに 配列は無いのかだぜ☆? 361個も 石のタグ 埋め込むの嫌なんだが…☆」

xamlでコントロールを配列として記述する方法

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 WPF ではなく XAML(ザムル)で調べればいいのか……☆」

Xamlで繰り返し要素を記述する
WPFでボタンの配列を作成する方法

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑めんどくさ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 動的に解決できないのかだぜ☆!? いつの時代のプログラマーなんだぜ☆!?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 じゃあ、動的に解決しなさいよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まず 1個 白石を置いてみようぜ☆?」

How to: Draw an Ellipse or a Circle

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑なんで こういうサンプルに 画像が付いてないんだぜ☆?
昔の雑誌なら 白黒のページにも 喜んで 画像が付いてただろ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 今は昔ではないんで☆」

20191101wpf1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑とりあえず 丸は描けそうだな☆
線の交点の上に うまく置けるかどうか計算だな☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんか また眠くなってきた……☆」

(うつらうつら)

ゴンッ!

KIFUWARABE_80x100x8_01_Futu.gif
「 起きろ お父ん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 石の大きさは、線の間隔の9掛けでいいだろ……☆」

20191101wpf2.png

            // 石を描こうぜ☆(^~^)?
            {
                stone0.Width = board.Width / 21 * 0.9;
                stone0.Height = board.Height / 21 * 0.9;
                stone0.Stroke = Brushes.Black;
                stone0.StrokeThickness = 1.5;
                Panel.SetZIndex(stone0, 120);
                stone0.Fill = Brushes.White;
                // 盤の幅を21で割ろうぜ☆(^~^)
                Canvas.SetLeft(stone0, boardLeft + board.Width * 0.05 - stone0.Width / 2);
                Canvas.SetTop(stone0, boardTop + board.Height * 0.05 - stone0.Height / 2);
            }

KIFUWARABE_80x100x8_01_Futu.gif
「 こういう計算は楽勝か☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 売れなかったゲームの数だけ書いてきたぜ☆
ゲームで儲けるより サラリーマンになった方が確実に稼げるぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 361個のXMLタグを書きなさい」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Microsoft社は何も疑問に思わないのだろうか……、
なんか オブジェクトを new できたりしないのかだぜ☆?」

2019-11-01 21:00頃

        <Canvas x:Name="canvas">
            <Ellipse x:Name="stone0" />
        </Canvas>

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 Ellipse を new して、 Canvas に Add できたら いいんだがなぁ☆」

20191101wpf3.png

            // 石を描こうぜ☆(^~^)?
            {
                var stone = new Ellipse();
                stone.Width = board.Width / 21 * 0.9;
                stone.Height = board.Height / 21 * 0.9;
                stone.Stroke = Brushes.White;
                stone.StrokeThickness = 1.5;
                Panel.SetZIndex(stone, 120);
                stone.Fill = Brushes.Black;
                // 盤の幅を21で割ろうぜ☆(^~^)
                Canvas.SetLeft(stone, boardLeft + board.Width * 0.05 - stone0.Width / 2 + board.Width / 21 * 1);
                Canvas.SetTop(stone, boardTop + board.Height * 0.05 - stone0.Height / 2);
                canvas.Children.Add(stone);
            }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑置けはした……☆ が、ウィンドウをリサイズするたびに増えてしまう……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 えらいこっちゃ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 .Initialize とか、 .OnLoad とか、それっぽい名前のイベント・ハンドラーは無いの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ Loaded に書いてみるかだぜ☆
それより コーヒー 飲もうぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 コーヒー☆?」

20191101wpf4.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑うっ、目が錯覚を☆! そして20路盤なんじゃないか これ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 オブジェクトの生成は、 .Initialize の方に書くか……☆
こういう 何はどこに書いたらいいのか さっぱり 分からんよな☆」

20191101wpf5.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 乱数で色をぶちまければ それっぽいぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 盤はできても、石をどこに置くのか 指示を飛ばすのが めんどうなのよね。
テキストボックスを置くのか、マウスでクリックするのか」

2019-11-01 22:00頃

input.txt

&clear
.

KIFUWARABE_80x100x8_01_Futu.gif
「 30秒ごとに input.txt ファイルを読み込めだぜ☆
最後の空行に ドット . を打ち込んだら 実行だぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 変わったこと すんのな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 その前に 盤に符号打たないの? 1とか Aとか」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そういえば 無いな☆」

Label クラス

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑なんだか 分からんこと 書いてるなあ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 サンプルは、
コピーして、
貼るのよ!」

20191101wpf6.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑文字が切れるのは なぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 .Width.Height と、 .FontSize をいじり回せだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 FontSize の単位が分からんよな☆」

20191101wpf7.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 トライ&エラーで 想像に近づけていってるんだが、タイポグラフィーの調整は むずかしいぜ☆」

20191101wpf8.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 フォントが正方形じゃないから 合わせるのは無理☆ てきとうで☆」

2019-11-01 23:00頃

20191101wpf9.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 でも ちまちま 合わせる……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 もういいだろ☆!」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 符号は A1 なの? 1A なの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 GNUGO では A1 だったかな……☆? x, y の並びだな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 foreach ループで回すなら A19, B19, C19… みたいな順になるの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そこは 0, 1, 2 … でいいのでは……☆
配列に入れて高速化しようぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 早く K10 に打ちたいぜ☆!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それは連珠な☆」

input.txt:

K10
.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 黒、白 の順に交互に打つので 色を指定する必要は無いだろう……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 何手目か画面に表示しましょう!」

20191101wpf10.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 めんどくさいんで 半透明で 端っこに出しとけばいいだろ……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 A19 を 0、 B19 を 1……、と変換するパーサーを作っておきたいな☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 寝ろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 そういうパーサー、前に作ったんじゃない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 多分昔のは Rust言語なんだぜ☆ C#言語で ぱぱっと書いてしまおう……☆」

namespace kifuwarabe_uec11_gui
{
    using System;
    using System.Globalization;

    /// <summary>
    /// 盤の符号のパーサー。
    /// </summary>
    public static class CellSignParser
    {
        /// <summary>
        /// `A19` を 0、 `B19` を 1、…。
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        public static int ToIndex(string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException(nameof(text));
            }

            // 最初の1文字はアルファベット。
            var column = ((char)text[0]) - 65; // 65はAsciiCodeのA。97はa。コンピューター囲碁では I は抜く慣習。
            if (32 <= column)
            {
                // 小文字から大文字へ変換。
                column -= 32;
            }

            if (8 <= column)
            {
                column--;
            }

            var row = 0;
            if (int.TryParse(text[1].ToString(CultureInfo.CurrentCulture), out int outRow1))
            {
                row = outRow1;
            }

            if (2 < text.Length)
            {
                row *= 10;
                if (int.TryParse(text[2].ToString(CultureInfo.CurrentCulture), out int outRow2))
                {
                    row += outRow2;
                }
            }

            return (19-row)*19+column;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これぐらい いい加減でいいだろ……☆ きょうは終わり☆」

2019-11-02 10:00頃

input.txt:

&set k10 b
&set k10 w
&set k10 .

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 石を置く命令文は &set でいいかだぜ☆?
列の符号は 小文字でも OK とするぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 & を打鍵するの、 Shiftキーを押さなくちゃいけなくて めんどくさくない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 日本語キーボードだと 一番打ちやすい記号は ; なんだが、 .ini ファイルのコメントみたいで 嫌だしな……☆」

put b to k10.
put w to k10.
put s to k10.

KIFUWARABE_80x100x8_01_Futu.gif
「 石を置くのなら こうなのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 構文に凝ると パーサーのメンテナンスするの大変だからな☆」

black j10 m10 n10
white k10 o10 p10
space L10 q10 r10
go.

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 繰り返し入力のしやすさを加味すると 色でまとめた方が いいかだぜ☆?
go. と書くと ファイルの内容は空っぽになって input.log に移るとしようぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ これで進めてみようぜ☆?」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 C#のロガーは 何を使うの?
エラーと、 input.log は分けるの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ファイルを 追加書き込みモードで開けっぱなしにするかだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 インプットのログだけ取るのかだぜ?
アウトプットもログを取らないと 前後関係が分からないのでは?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ communication.log に名称変更☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ログの書き出しは 非同期でやるの? 同期でやるの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 同期でやらないと、ログは読めたもんじゃないぜ☆」

namespace kifuwarabe_uec11_gui
{
    using System;
    using System.IO;
    using System.Text;

    /// <summary>
    /// 特に通信ログを書き込むことを想定したロガー。
    /// </summary>
    public sealed class CommunicationLogWriter : IDisposable
    {
        private StreamWriter StreamWriter { get; set; }

        public CommunicationLogWriter(string file)
        {
            // 追加書き込みモードでファイルを開きます。
            this.StreamWriter = new StreamWriter(file, true, Encoding.UTF8);
        }

        public void WriteLine(string text)
        {
            this.StreamWriter.WriteLine(text);
        }

        public void Flush()
        {
            this.StreamWriter.Flush();
        }

        /// <summary>
        /// 破棄。
        /// </summary>
        public void Dispose()
        {
            this.StreamWriter?.Close();
            this.StreamWriter = null;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑なんの捻りもなく書けば こうだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ラッピングしている意味は何だぜ☆? 直接 StreamWriter でいいのでは☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 In/Out の区別を付けるメソッドとか あとでほしくなるかも知らん☆」

2019-11-02 11:00頃

InputTextReader:

namespace kifuwarabe_uec11_gui
{
    using System;
    using System.IO;
    using System.Text;

    /// <summary>
    /// `input.txt` の読取☆(^~^)
    /// </summary>
    public sealed class InputTextReader : IDisposable
    {
        private StreamReader StreamReader { get; set; }

        public InputTextReader(string file)
        {
            this.StreamReader = new StreamReader(file, Encoding.UTF8);
        }

        /// <summary>
        /// 行読込。
        /// </summary>
        /// <returns>読み込んだ行、またはヌル。</returns>
        public string ReadLine()
        {
            return this.StreamReader.ReadLine();
        }

        /// <summary>
        /// 破棄。
        /// </summary>
        public void Dispose()
        {
            this.StreamReader?.Close();
            this.StreamReader = null;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑パーサー機能も付けるかは あとで考えようぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 WPF にタイマー機能は付けれるの?」

タイマにより一定時間間隔で処理を行うには?(WPFタイマ編)

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑UIスレッドで動くタイマーがあるらしいぜ☆ 精度はそんなもんでいいだろ☆」

2019-11-02 17:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 なんか いろいろなことがあって 17時だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
いらいら☆!

20191102wpf11.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ファイルをロックせずに開かないとな☆」

ファイルにロックをかける方法とロックをかけない方法

InputTextReader.cs:

namespace kifuwarabe_uec11_gui
{
    using System;
    using System.IO;
    using System.Text;

    /// <summary>
    /// `input.txt` の読取☆(^~^)
    /// TODO `input.txt` ファイルが必要☆(^~^)
    /// ファイルにロックを掛けずに開くことが重要☆(^~^)
    /// </summary>
    public sealed class InputTextReader : IDisposable
    {
        /// <summary>
        /// 読込用ファイル・ストリーム☆(^~^)
        /// </summary>
        private FileStream FileStreamR { get; set; }

        /// <summary>
        /// 読込用ストリーム・リーダー☆(^~^)
        /// </summary>
        private StreamReader StreamReader { get; set; }

        /// <summary>
        /// ファイル名☆(^~^)
        /// </summary>
        private string File { get; set; }

        public InputTextReader(string file)
        {
            this.File = file;
            this.FileStreamR = new System.IO.FileStream(
                file,
                FileMode.Open,
                FileAccess.Read,
                FileShare.ReadWrite);
            this.StreamReader = new System.IO.StreamReader(this.FileStreamR, Encoding.UTF8);
        }

        /// <summary>
        /// ファイル全部読み込む。
        /// </summary>
        /// <returns>読み込んだ行、またはヌル。</returns>
        public string ReadToEnd()
        {
            var text = this.StreamReader.ReadToEnd();

            // ファイルの先頭に読込位置を戻す。
            this.FileStreamR.Position = 0;

            // 書込み用ストリーム☆(^~^)
            using (var writer = new StreamWriter(this.File, false, Encoding.UTF8))
            {
                // ファイルを空にするぜ☆(^~^)
                writer.Write("");
                writer.Flush();
            }

            return text;
        }

        /// <summary>
        /// 破棄。
        /// </summary>
        public void Dispose()
        {
            this.FileStreamR?.Close();
            this.FileStreamR = null;

            this.StreamReader?.Close();
            this.StreamReader = null;
        }
    }
}

MainWindows.xaml.cs:

        private void Window_Initialized(object sender, System.EventArgs e)
        {
            // 中略

            // UIスレッドで動くタイマー☆(^~^)
            {
                this.DispatchTimer = new DispatcherTimer();
                this.DispatchTimer.Start();
                this.DispatchTimer.Interval = TimeSpan.FromSeconds(5);
                this.DispatchTimer.Tick += (s, e) =>
                {
                    var line = this.InputTextReader.ReadToEnd();
                    Trace.WriteLine($"Read            | {line}");
                };
            }

            // 中略
        }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ざっくり書くなら こうかだぜ☆?」

KIFUWARABE_80x100x8_01_Futu.gif
「 読み込んだ入力を ログに書き出せだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 .ReadToEnd() は 1文字ずつ取っている気がする……、仕組みが分からんが☆
行ごとに取れないのかだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 いや、文字列を foreach文で回すと1文字ずつ取ってしまうのか……☆」

            // UIスレッドで動くタイマー☆(^~^)
            {
                this.DispatchTimer = new DispatcherTimer();
                this.DispatchTimer.Start();
                this.DispatchTimer.Interval = TimeSpan.FromSeconds(5);
                this.DispatchTimer.Tick += (s, e) =>
                {
                    var text = this.InputTextReader.ReadToEnd();
                    Trace.WriteLine($"Text            | {text}");

                    this.CommunicationLogWriter.WriteLine(text);
                    this.CommunicationLogWriter.Flush();

                    foreach (var line in text.Split(Environment.NewLine))
                    {
                        Trace.WriteLine($"Read            | {line}");
                    }
                };
            }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑じゃあ こうしてみる☆」

20191102wpf12.png

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 ログ書き出しに変な文字付いてない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 多分 BOM かと思うが、バイナリ・エディターで開いてみてくれだぜ☆」

Binary Editor BZ
UTF-8のBOM付き・BOM無しの違いと確認方法

20191102wpf13.png

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 これ どうやって使うの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 BOM だったら EF BB BF というデータがあるはずだぜ☆
ちなみに 0d 0a は Windows の改行☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 先頭に EF BB BF があるわよ。 それ以外のところにも EF BB BF があるわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 じゃあ このファイルは BOM付きのUTF だぜ☆
先頭のBOMだけ無視されるが、途中に出てくるBOM は文字化けするだろう☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 BOM無しのUTFで保存してくれだぜ☆」

BOM無しのUTF-8でテキストファイルに書き込む

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑エンコーディングを指定してはいけないのか……☆」

2019-11-02 18:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 よし、BOMは直した☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 じゃあ命令を プログラミングしてくれだぜ☆
これは 別個のプロジェクトを立てた方がいいだろう☆
プロジェクト名は kifuwarabe-uec11-gui-api とか どうだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 長い名前だな……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 プロジェクトを別に立てると めんどいんで しばらく ネームスペースを kifuwarabe_uec11_gui.API にして使うぜ☆」

2019-11-02 19:00 ~ 20:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ここでお前らに パーサーの書き方を 教えてやろう☆」

MainWindow.xaml.cs:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // テスト
            Trace.WriteLine($"A19             | {CellAddress.Parse("A19", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"B19             | {CellAddress.Parse("B19", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"S1              | {CellAddress.Parse("S1", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"T1              | {CellAddress.Parse("T1", 0).Item1?.ToDisplay()}");

            Trace.WriteLine($"a19             | {CellAddress.Parse("a19", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"b19             | {CellAddress.Parse("b19", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"s1              | {CellAddress.Parse("s1", 0).Item1?.ToDisplay()}");
            Trace.WriteLine($"t1              | {CellAddress.Parse("t1", 0).Item1?.ToDisplay()}");
        }

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑テストは MSTest などを使って Assert で書くべきなんだが、めんどくさかったんで ひとまず Trace で出力ウィンドウに出すことにする☆」

CellAddress.cs

namespace kifuwarabe_uec11_gui.API
{
    /// <summary>
    /// セル番地☆(^~^) A1 とか T19 みたいなやつだぜ☆(^~^)
    /// </summary>
    public class CellAddress
    {
        public ColumnAddress ColumnAddress { get; private set; }
        public RowAddress RowAddress { get; private set; }

        public CellAddress(ColumnAddress columnAddress, RowAddress rowAddress)
        {
            this.ColumnAddress = columnAddress;
            this.RowAddress = rowAddress;
        }

        public static (CellAddress, int) Parse(string text, int start)
        {
            ColumnAddress columnAddress;
            var next = 0;
            {
                (columnAddress, next) = ColumnAddress.Parse(text, start);
                if (columnAddress == null)
                {
                    // 片方でもマッチしなければ、非マッチ☆(^~^)
                    return (null, start);
                }
            }

            // 列はマッチ☆(^~^)

            RowAddress rowAddress;
            {
                (rowAddress, next) = RowAddress.Parse(text, next);
                if (rowAddress == null)
                {
                    // 片方でもマッチしなければ、非マッチ☆(^~^)
                    return (null, start);
                }
            }

            // 列と行の両方マッチ☆(^~^)
            return (new CellAddress(columnAddress, rowAddress), next);
        }

        public int ToIndex()
        {
            return (19 - this.RowAddress.Number) * 19 + this.ColumnAddress.Number;
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            return $"{this.ColumnAddress.ToDisplay()}{this.RowAddress.ToDisplay()}";
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑セルは、列アドレスと、行アドレスの2つで できている☆」

ColumnAddress.cs

using System.Globalization;

namespace kifuwarabe_uec11_gui.API
{
    /// <summary>
    /// 列アドレスだぜ☆(^~^) A ~ T で、 I が欠番だな☆(^~^)
    /// </summary>
    public class ColumnAddress
    {
        public int Number { get; private set; }

        public ColumnAddress(int number)
        {
            this.Number = number;
        }

        public static (ColumnAddress, int) Parse(string text, int start)
        {
            if (text == null || text.Length < start + 1)
            {
                return (null, start);
            }

            // 最初の1文字はアルファベット。
            var column = ((char)text[start]) - 65; // 65はAsciiCodeのA。97はa。
            if (32 <= column)
            {
                // 小文字から大文字へ変換。
                column -= 32;
            }

            // コンピューター囲碁では I は抜く慣習。
            if (8 <= column)
            {
                column--;
            }

            return (new ColumnAddress(column), start + 1);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            // 65はAsciiCodeのA。コンピューター囲碁では I は抜く慣習。
            return ((char)(65 + (this.Number < 8 ? this.Number : this.Number + 1))).ToString(CultureInfo.CurrentCulture);
        }
    }
}

RowAddress.cs:

namespace kifuwarabe_uec11_gui.API
{
    using System;
    using System.Globalization;

    /// <summary>
    /// 行番号だぜ☆(^~^) コンピューターチェスの国際式では 一番下が1行目だぜ☆(^~^)
    /// </summary>
    public class RowAddress
    {
        public int Number { get; private set; }

        public RowAddress(int number)
        {
            this.Number = number;
        }

        public static (RowAddress, int) Parse(string text, int start)
        {
            if (text == null)
            {
                throw new ArgumentNullException(nameof(text));
            }

            var row = 0;
            {
                if (int.TryParse(text[start].ToString(CultureInfo.CurrentCulture), out int outRow))
                {
                    row = outRow;

                    // 先頭桁目は確定☆(^~^)
                    start++;
                }
                else
                {
                    // 1文字もヒットしなかった場合☆(^~^)
                    return (null, start);
                }
            }

            if (start < text.Length)
            {
                if (int.TryParse(text[start].ToString(CultureInfo.CurrentCulture), out int outRow))
                {
                    row *= 10;
                    row += outRow;

                    // 先頭から2桁目は確定☆(^~^)
                    start++;
                }
            }

            // 1文字以上のヒットがある場合☆(^~^)
            return (new RowAddress(row), start);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            return this.Number.ToString(CultureInfo.CurrentCulture);
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こんな風に 部分に分解してパースする☆
パーサーのライブラリを使えば 便利かもしれないが、ルールを覚えるのがめんどくさいので 自作する☆」

ExactlyKeyword.cs:

namespace kifuwarabe_uec11_gui.API
{
    using System;

    /// <summary>
    /// キーワードの完全一致☆(^~^)
    /// </summary>
    public class ExactlyKeyword
    {
        /// <summary>
        /// キーワード☆(^~^)
        /// </summary>
        private string Word { get; set; }

        public ExactlyKeyword(string word)
        {
            this.Word = word;
        }

        public static (ExactlyKeyword, int) Parse(string word, string text, int start)
        {
            if (word == null || text == null || text.Length < start + word.Length)
            {
                return (null, start);
            }

            if (text.Substring(start).StartsWith(word, StringComparison.Ordinal))
            {
                // 一致。
                return (new ExactlyKeyword(word), start + word.Length);
            }

            return (null, start);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            return this.Word;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ blackspace のマッチングも使用感を 同じにしておくぜ☆」

WhiteSpaces.cs:

namespace kifuwarabe_uec11_gui.API
{
    using System.Text.RegularExpressions;

    /// <summary>
    /// 1個以上の空白☆(^~^)
    /// </summary>
    public class WhiteSpace
    {
        private static Regex regex = new Regex("(\\s+)", RegexOptions.Compiled);

        /// <summary>
        /// マッチングした文字☆(^~^)
        /// </summary>
        public string Text { get; private set; }

        public WhiteSpace(string text)
        {
            this.Text = text;
        }

        public static (WhiteSpace, int) Parse(string text, int start)
        {
            if (text == null || text.Length <= start)
            {
                return (null, start);
            }

            var m = regex.Match(text.Substring(start));
            if (m.Success)
            {
                // 一致。
                var whiteSpaces = m.Groups[1].Value;
                return (new WhiteSpace(whiteSpaces), start + whiteSpaces.Length);
            }

            return (null, start);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            return this.Text;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 空白にも対応☆」

2019-11-02 21:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 飯も食った……☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 また コーヒーか☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それで☆」

BlackInstruction.cs:

using System.Collections.Generic;
using System.Text;

namespace kifuwarabe_uec11_gui.API
{
    /// <summary>
    /// black命令☆(^~^)
    /// `black k10 k11 k12` みたいにして黒石を置いていこうぜ☆(^~^)
    /// </summary>
    public class BlackInstruction
    {
        /// <summary>
        /// セル番地のリスト☆(^~^)
        /// </summary>
        public List<CellAddress> CellAddressList { get; private set; }

        public BlackInstruction(List<CellAddress> cellAddressList)
        {
            this.CellAddressList = cellAddressList;
        }

        public static (BlackInstruction, int) Parse(string text, int start)
        {
            var cellAddressList = new List<CellAddress>();
            var next = start;

            ExactlyKeyword black;
            {
                (black, next) = ExactlyKeyword.Parse("black", text, next);
                if (black == null)
                {
                    // 非マッチ☆(^~^)
                    return (null, start);
                }
            }

            // あとはリスト☆(^~^)
            for (; ; )
            {
                WhiteSpace whiteSpace;
                {
                    (whiteSpace, next) = WhiteSpace.Parse(text, next);
                    if (whiteSpace == null)
                    {
                        // おわり☆(^~^)
                        break;
                    }
                }

                CellAddress cellAddress;
                {
                    (cellAddress, next) = CellAddress.Parse(text, next);
                    if (cellAddress == null)
                    {
                        // おわり☆(^~^)
                        break;
                    }
                }

                // マッチ☆(^~^)
                cellAddressList.Add(cellAddress);
            }


            // 列と行の両方マッチ☆(^~^)
            return (new BlackInstruction(cellAddressList), next);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            // Python言語の mapコンビネーター とかあれば1行で書けるんだが、無いからforeachループで回そうぜ☆(^~^)
            var tokens = new List<string>();
            foreach (var cellAddress in this.CellAddressList)
            {
                tokens.Add(cellAddress.ToDisplay());
            }

            return $"{string.Join(' ', tokens)}";
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
(ず ず ずい ずいっ びゃー) # 熱いコーヒーをすする音
「 ぶぇぇ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 命令文を読み取れるようになったのなら、
input.txt ファイルを読み込んだ結果は 命令文オブジェクトをリストに入れて返せばいいんじゃないの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 そこは2ステップに分けてやろうぜ☆?」

2019-11-02 22:00頃

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 タイム・スタンプなんか タイトルにしても コーディングはそんなに進まん☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 その行が 何命令か 判定しないと、パーサーも当てれなくない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 行の先頭のトークンを取得してから パーサーを選ぶのが実用的かだぜ☆?」

Word.cs:

namespace kifuwarabe_uec11_gui.API
{
    using System;
    using System.Text.RegularExpressions;

    /// <summary>
    /// 次の空白までの文字列☆(^~^)
    /// </summary>
    public class Word
    {
        /// <summary>
        /// 英語がいうところの、単語☆(^~^)
        /// </summary>
        private static Regex regex = new Regex("(\\w+)", RegexOptions.Compiled);

        /// <summary>
        /// マッチングした文字☆(^~^)
        /// </summary>
        public string Text { get; private set; }

        public Word(string text)
        {
            this.Text = text;
        }

        public static (Word, int) Parse(string text, int start)
        {
            if (text == null || text.Length <= start)
            {
                return (null, start);
            }

            var m = regex.Match(text.Substring(start));
            if (m.Success)
            {
                // 一致。
                var word = m.Groups[1].Value;
                return (new Word(word), start + word.Length);
            }

            return (null, start);
        }

        /// <summary>
        /// デバッグ表示用☆(^~^)
        /// </summary>
        /// <returns></returns>
        public string ToDisplay()
        {
            return this.Text;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑単語を取れるようにして……☆」

                this.DispatchTimer.Tick += (s, e) =>
                {
                    var text = this.InputTextReader.ReadToEnd();

                    // 空行は無視☆(^~^)
                    if (!string.IsNullOrWhiteSpace(text))
                    {
                        Trace.WriteLine($"Text            | {text}");

                        this.CommunicationLogWriter.WriteLine(text);
                        this.CommunicationLogWriter.Flush();

                        foreach (var line in text.Split(Environment.NewLine))
                        {
                            Trace.WriteLine($"Read            | {line}");

                            var (word, next) = Word.Parse(line, 0);
                            if (word != null)
                            {
                                switch (word.Text)
                                {
                                    case "black": // thru
                                    case "white": // thru
                                    case "space":
                                        ColorInstructionParameter cip;
                                        (cip, next) = ColorInstructionParameter.Parse(line, next);
                                        if (cip == null)
                                        {
                                            Trace.WriteLine($"Error           | {line}");
                                        }
                                        else
                                        {
                                            Trace.WriteLine($"Test            | {word.Text} {cip.ToDisplay()}");
                                        }
                                        break;
                                }
                            }
                        }
                    }
                };

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑コマンド名をまず取って、次に引数をパースする感じに変更だぜ☆
コマンド名と 引数の間のスペースも読み飛ばすように パーサーを変更☆ 詳しくは Git hub を見ろだぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ネーム・スペースを kifuwarabe_uec11_gui.API から kifuwarabe_uec11_gui.Script にリネームしよう……☆
感覚的に☆」

2019-11-02 23:00頃

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 スクリーン・ショットを乗せなさいよ!
ソースコードばっかで つまんないのよ!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ソースコード載ってたら おもんないのかだぜ……☆」

Instruction.cs:

namespace kifuwarabe_uec11_gui.Script
{
    /// <summary>
    /// 命令。
    /// </summary>
    public class Instruction
    {
        public string Command { get; private set; }
        public object Argument { get; private set; }

        public Instruction(string command, object argument)
        {
            this.Command = command;
            this.Argument = argument;
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑パースし終わったら、こういうオブジェクトに変換していこうぜ☆」

Window_Initialized:

                this.DispatchTimer.Tick += (s, e) =>
                {
                    var text = this.InputTextReader.ReadToEnd();

                    // 空行は無視☆(^~^)
                    if (!string.IsNullOrWhiteSpace(text))
                    {
                        Trace.WriteLine($"Text            | {text}");
                        this.CommunicationLogWriter.WriteLine(text);
                        this.CommunicationLogWriter.Flush();
                    }

                    var scriptDocument = ScriptDocument.Parse(text);
                    if (scriptDocument != null)
                    {
                        // TODO:
                    }
                };

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こう書き直して……☆」

ScriptDocument.cs:

namespace kifuwarabe_uec11_gui.Script
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;

    public class ScriptDocument
    {
        public List<Instruction> Instructions { get; private set; }

        public ScriptDocument(List<Instruction> instructions)
        {
            this.Instructions = instructions;
        }

        public static ScriptDocument Parse(string text)
        {
            // 空行は無視☆(^~^)
            if (string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            var instructions = new List<Instruction>();

            foreach (var line in text.Split(Environment.NewLine))
            {
                Trace.WriteLine($"Read            | {line}");

                var (word, next) = Word.Parse(line, 0);
                if (word != null)
                {
                    switch (word.Text)
                    {
                        case "black": // thru
                        case "white": // thru
                        case "space":
                            ColorInstructionArgument argument;
                            (argument, next) = ColorInstructionArgument.Parse(line, next);
                            if (argument == null)
                            {
                                Trace.WriteLine($"Error           | {line}");
                            }
                            else
                            {
                                // Trace.WriteLine($"Test            | {word.Text} {argument.ToDisplay()}");
                                instructions.Add(new Instruction(word.Text, argument));
                            }
                            break;
                    }
                }
            }

            return new ScriptDocument(instructions);
        }
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こうだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 お父んがソースコード ばんばん貼るから ブログが重くなってきた……☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 命令を受け取ったら、それを画面に反映するコードがいるわよ?」

20191102wpf14.png

input.text:

black a19 k10 t1
white a19 k10 t1
space a19 k10 t1

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 こんな感じかだぜ☆ 明日はもっと調整、今日はここまで☆(^~^)!」

<次回につづく>

何度でもクリック!→

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

むずでょ の最近の記事