Newer
Older
TicTacToe / TTTConsole / Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using TTT;

namespace TTTConsole {

    class Program {

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr LoadLibrary(string lib);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern void FreeLibrary(IntPtr module);
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr GetProcAddress(IntPtr module, string proc);

        private delegate void GetNameDelegate(StringBuilder s, Int32 bufsize);
        private delegate bool IsHumanDelegate();
        private delegate int MyTurnDelegate(IntPtr board);

        static string[] PLAYER_STR = new string[] { "", "先手", "後手" };
        static string[] PLAYER_MARK = new string[] { " ", "○", "×" };
        static List<string> names = new List<string>();
        static int[] thinkers;
        static bool showNumber = false;

        /// <summary>
        /// プログラム開始点
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args) {

            Console.WriteLine(new string('*', 30));
            Console.WriteLine("拡張○×ゲーム");
            Console.WriteLine(new string('*', 30));
            Console.WriteLine("");
            var ttt = new TicTacToe();

            // プラグインDLLを開く
            var pluginFiles = new List<string>() { "TPIHuman.dll", "TPIRandom.dll" };
            var modules = new List<IntPtr>();
            var GetName = new List<GetNameDelegate>();
            var IsHuman = new List<IsHumanDelegate>();
            var MyTurn = new List<MyTurnDelegate>();

            foreach (var file in pluginFiles) {
                var module = LoadLibrary(file);
                if (module == IntPtr.Zero) // error handling
                {
                    Console.WriteLine($"Could not load library: {Marshal.GetLastWin32Error()}");
                    continue;
                }

                IntPtr method = GetProcAddress(module, "GetName");
                if (method == IntPtr.Zero) // error handling
                {
                    Console.WriteLine($"Could not load 'GetName' method: {Marshal.GetLastWin32Error()}");
                    FreeLibrary(module);  // unload library
                    continue;
                }
                GetName.Add((GetNameDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(GetNameDelegate)));

                method = GetProcAddress(module, "IsHuman");
                if (method == IntPtr.Zero) // error handling
                {
                    Console.WriteLine($"Could not load 'IsHuman' method: {Marshal.GetLastWin32Error()}");
                    FreeLibrary(module);  // unload library
                    continue;
                }
                IsHuman.Add((IsHumanDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(IsHumanDelegate)));

                method = GetProcAddress(module, "MyTurn");
                if (method == IntPtr.Zero) // error handling
                {
                    Console.WriteLine($"Could not load 'MyTurn' method: {Marshal.GetLastWin32Error()}");
                    FreeLibrary(module);  // unload library
                    continue;
                }
                MyTurn.Add((MyTurnDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(MyTurnDelegate)));

                modules.Add(module);
            }

            // プラグイン名の取得
            System.Text.StringBuilder sb = new System.Text.StringBuilder(256);
            foreach (var gn in GetName) {
                gn(sb, sb.Capacity);
                names.Add(sb.ToString());
            }

            // プレイヤーの選択
            Console.WriteLine("プレイヤーの選択");
            thinkers = new int[ttt.PLAYERS];
            for (var pl=0; pl< ttt.PLAYERS; pl++) {
                for (var i = 0; i < names.Count; i++) {
                    Console.WriteLine($"({i + 1}) {names[i]}");
                }
                Console.Write($"{PLAYER_STR[pl + 1]} を選んでください: ");
                var input = Console.ReadLine();

                if (!int.TryParse(input, out thinkers[pl])) return;
                if (thinkers[pl] < 1 || thinkers[pl] > names.Count) return;
                --thinkers[pl];
            }

            // 数字表示の選択
            Console.Write("○×の順番を表示しますか? 1:しない 2:する ");
            showNumber = int.Parse(Console.ReadLine()) == 2 ? true : false;

            // 対戦開始
            ttt.Init();
            do {
                Console.WriteLine("");
                ShowBoard(ttt);
                Console.Write($"{PlayerStr(ttt.Player)} の番");

                if (IsHuman[thinkers[(int)ttt.Player - 1]]()) Console.WriteLine("");
                ttt.Set(MyTurn[thinkers[(int)ttt.Player - 1]](ttt.GetBoard()));
                if (IsHuman[thinkers[(int)ttt.Player - 1]]()) Console.WriteLine($" --> {ttt.LastSet + 1}");

            } while (ttt.Judge == JUDGE.None);

            // 結果表示
            Console.WriteLine("");
            Console.WriteLine(new string('*', 30));
            ShowBoard(ttt);
            Console.WriteLine("");
            switch (ttt.Judge) {
            case JUDGE.WIN:
                Console.WriteLine($"{PlayerStr(ttt.Winner)} の勝利");
                break;
            case JUDGE.DRAW:
                Console.WriteLine($"引き分け");
                break;
            case JUDGE.OUT_OF_RANGE:
                Console.WriteLine($"{PlayerStr(ttt.Player)} の反則負け(範囲外)");
                break;
            case JUDGE.OVERLAP:
                Console.WriteLine($"{PlayerStr(ttt.Player)} の反則負け(重ね置き)");
                break;
            }
            Console.WriteLine(new string('*', 30));

            // 終了
            Console.Write("Press [Enter] to exit.");
            Console.ReadLine();
            foreach (var module in modules) FreeLibrary(module);
        }

        /// <summary>
        /// 盤の表示
        /// </summary>
        /// <param name="ttt"></param>
        static void ShowBoard(TicTacToe ttt) {
            Console.WriteLine(new string('~', 6) + $" ターン{ttt.Turn} " + new string('~', 6));

            var flip = ttt.Player == PLAYER.Second ? -1 : 1;
            for (var row = 0; row < ttt.BOARD_ROWS; row++) {
                Console.Write("    ");
                for (var col = 0; col < ttt.BOARD_COLS; col++) {
                    var pos = row * ttt.BOARD_COLS + col;
                    var pIdx = ttt.Board[pos] * flip > 0 ? PLAYER.First :
                        ttt.Board[pos] * flip < 0 ? PLAYER.Second : PLAYER.None;
                    Console.Write(PLAYER_MARK[(int)pIdx]);
                    if (showNumber) Console.Write(ttt.Board[pos] == 0 ? "  " : 
                        string.Format("{0,2}", Math.Abs(ttt.Board[pos])));
                    if (col < ttt.BOARD_COLS - 1) Console.Write(" | ");
                }
                Console.WriteLine("");
                if (row < ttt.BOARD_ROWS - 1) {
                    if (showNumber) Console.WriteLine("    -----+------+-----");
                    else Console.WriteLine("    ---+----+---");
                }
            }
        }

        /// <summary>
        /// プレイヤーの表示文字列を生成
        /// </summary>
        /// <param name="p">プレイヤー</param>
        /// <returns>表示文字列</returns>
        static string PlayerStr(PLAYER p) {
            return $"{PLAYER_STR[(int)p]}({names[thinkers[(int)p - 1]]})";
        }
    }
}