マルバツゲーム
Posted feedbacks - C#
IPlayerBaseインターフェースを実装していればプレーヤーになれます。
勝敗判定の部分をもっとエレガントに書きたいですね。
結果
○ WIN : 5837
× WIN : 2846
DRAW : 1317
○ WIN : 5863
× WIN : 2924
DRAW : 1213
○ WIN : 5811
× WIN : 2895
DRAW : 1294
勝敗判定の部分をもっとエレガントに書きたいですね。
結果
○ WIN : 5837
× WIN : 2846
DRAW : 1317
○ WIN : 5863
× WIN : 2924
DRAW : 1213
○ WIN : 5811
× WIN : 2895
DRAW : 1294
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | using System;
using System.Collections.Generic;
using System.Linq;
namespace どう書く_org_マルバツゲーム {
class Program {
static void Main(string[] args) {
int maruWin = 0;
int batuWin = 0;
int draw = 0;
IPlayerBase maru = new Player() { Name = "○" };
IPlayerBase batu = new Player() { Name = "×" };
for(int i = 0; i < 10000; i++) {
Game game = new Game(maru, batu);
switch(game.Start()) {
case "○":
maruWin++;
break;
case "×":
batuWin++;
break;
case "draw":
draw++;
break;
}
}
Console.WriteLine("○ WIN : " + maruWin.ToString());
Console.WriteLine("× WIN : " + batuWin.ToString());
Console.WriteLine(" DRAW : " + draw.ToString());
Console.ReadLine();
}
}
class Game {
private IPlayerBase _maru;
private IPlayerBase _batu;
public string[] Board = new string[] {
"□□□",
"□□□",
"□□□" };
public Game(IPlayerBase maru, IPlayerBase batu) {
_maru = maru;
_maru.Game = this;
_batu = batu;
_batu.Game = this;
}
public string Start() {
string jadge = "";
while(true) {
_maru.Play();
jadge = Judge(_maru.Name);
if(jadge != "") {
break;
}
_batu.Play();
jadge = Judge(_batu.Name);
if(jadge != "") {
break;
}
}
return jadge;
}
//勝者を判定
private string Judge(string name) {
string name3 = name + name + name;
//横
foreach(string str in Board) {
if(str == name3) {
return name;
}
}
//縦
for(int x = 0; x < 3; x++) {
string str = "";
for(int y = 0; y < 3; y++) {
str += Board[y][x];
}
if(str == name3) {
return name;
}
}
//斜め
string tmp = Board[0][0].ToString() + Board[1][1].ToString() + Board[2][2].ToString();
if(tmp == name3) {
return name;
}
tmp = Board[0][2].ToString() + Board[1][1].ToString() + Board[2][0].ToString();
if(tmp == name3) {
return name;
}
//引き分け
if(!(Board[0] + Board[1] + Board[2]).Contains('□')) {
return "draw";
}
return "";
}
}
class Player :IPlayerBase {
#region IPlayerBase メンバ
public Game Game { get; set; } //参加しているゲーム
public string Name { get; set; } //○か×か
private Random Rnd = new Random();
//一手打つ
public void Play() {
List<Location> cells = new List<Location>(); //置けるマス
//置けるマスを列挙
for(int y = 0; y < 3; y++) {
for(int x = 0; x < 3; x++) {
if(Game.Board[y][x] == '□') {
Location location = new Location();
location.x = x;
location.y = y;
cells.Add(location);
}
}
}
//置けるマスが無ければ何もしない
if(cells.Count == 0) return;
//乱数で置くマスを決定
int index = Rnd.Next(cells.Count);
Location cell = cells[index];
//石を置く
Game.Board[cell.y] = Game.Board[cell.y].Remove(cell.x, 1).Insert(cell.x, Name);
}
#endregion
}
//マスの位置
struct Location {
public int x;
public int y;
}
//プレーヤーが実装するインターフェース
//これを実装したプレーヤーに差し替え可
interface IPlayerBase {
Game Game { set; get; }
string Name { set; get; }
void Play();
}
}
|
PlayerはIPlayerを継承してTacticseを実装すれば置き換え可能です。 LocalRandomPlayerとMemberRandomPlayerといますが、 両方ともランダムで場所を決めていて、 Randomのインスタンス生成をクラス内で保持してる(Member)か、 関数内で保持してる(Local)かの違いです。 /*実行結果 開始時間:2008年4月25日 17:54:06 1回目 ---LocalRandomPlayer--- ○Win :5903 ×Win :3103 Draw :994 2回目 ---LocalRandomPlayer--- ○Win :5492 ×Win :3073 Draw :1435 3回目 ---LocalRandomPlayer--- ○Win :5693 ×Win :3351 Draw :956 4回目 ---LocalRandomPlayer--- ○Win :5681 ×Win :3228 Draw :1091 5回目 ---LocalRandomPlayer--- ○Win :6277 ×Win :2812 Draw :911 終了時間:2008年4月25日 17:54:13 開始時間:2008年4月25日 17:55:21 1回目 ---MemberRandomPlayer--- ○Win :5565 ×Win :3202 Draw :1233 2回目 ---MemberRandomPlayer--- ○Win :5490 ×Win :3240 Draw :1270 3回目 ---MemberRandomPlayer--- ○Win :5606 ×Win :3130 Draw :1264 4回目 ---MemberRandomPlayer--- ○Win :5456 ×Win :3207 Draw :1337 5回目 ---MemberRandomPlayer--- ○Win :5482 ×Win :3199 Draw :1319 終了時間:2008年4月25日 17:55:21
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | using System;
using System.Collections.Generic;
/// <summary>
/// 座標構造体
/// </summary>
struct Point
{
public int x;
public int y;
public Point(int x, int y) { this.x = x; this.y = y; }
}
/// <summary>
/// プレイヤーインターフェース
/// </summary>
interface IPlayer
{
/// <summary>
/// fieldにおける座標を返す。
/// </summary>
/// <param name="field">現在のフィールド</param>
/// <param name="pointList">おけることのできる座標</param>
/// <returns></returns>
Point Tacticse(ref int[,] field, ref List<Point> pointList);
}
class LocalRandomPlayer
: IPlayer
{
public Point Tacticse(ref int[,] field, ref List<Point> pointList)
{
Random rnd = new Random();
int n = rnd.Next(pointList.Count);
Point tmp = pointList[n];
pointList.RemoveAt(n);
return tmp;
}
}
class MemberRandomPlayer
: IPlayer
{
private Random rnd;
public MemberRandomPlayer()
{
rnd = new Random();
}
public Point Tacticse(ref int[,] field, ref List<Point> pointList)
{
int n = rnd.Next(pointList.Count);
Point tmp = pointList[n];
pointList.RemoveAt(n);
return tmp;
}
}
class Judge
{
private int[,] field;
private IPlayer Maru;
private IPlayer Batu;
private List<Point> pointList;
private const int FIELD_SIZE = 3;
public Judge(IPlayer m, IPlayer b)
{
Maru = m;
Batu = b;
}
/// <summary>
/// 初期化
/// </summary>
private void Init()
{
field = new int[FIELD_SIZE, FIELD_SIZE];
pointList = new List<Point>();
for (int i = 0; i < FIELD_SIZE; i++)
{
for (int j = 0; j < FIELD_SIZE; j++)
{
pointList.Add(new Point(i, j));
}
}
}
/// <summary>
/// 試合開始
/// </summary>
/// <returns>試合結果(0:引き分け、1:○Win、2:×Win)</returns>
public int Game()
{
const int MARU = 1, BATU = -1;
int n = 0, winnerFlag;
IPlayer[] Player = { Maru, Batu };
int[] Mark = { MARU, BATU };
Init();
do
{
Point p = Player[n % 2].Tacticse(ref field, ref pointList);
field[p.x, p.y] = Mark[n % 2];
if ((winnerFlag = checkJudge()) != 0) break;
} while (++n < 9);
//BATUを-1→2に変換
if (winnerFlag == BATU)
winnerFlag = 2;
return winnerFlag;
}
/// <summary>
/// 勝敗判定
/// </summary>
/// <returns>勝敗が決まっていれば0以外、決まっていなければ0</returns>
private int checkJudge()
{
for (int i = 0; i < FIELD_SIZE; i++)
{
//横
if (Math.Abs(field[0, i] + field[1, i] + field[2, i]) - 3 == 0)
return field[0, 1];
//縦
if (Math.Abs(field[i, 0] + field[i, 1] + field[i, 2]) - 3 == 0)
return field[i, 0];
}
//斜め
if (Math.Abs(field[0, 0] + field[1, 1] + field[2, 2]) - 3 == 0 ||
Math.Abs(field[2, 0] + field[1, 1] + field[0, 2]) - 3 == 0)
return field[1, 1];
return 0;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("開始時間:{0}", DateTime.Now.ToString("F"));
for (int i = 0; i < 5; i++)
{
Console.WriteLine("{0}回目", i + 1);
//Start(new LocalRandomPlayer(),
// new LocalRandomPlayer(),
// 10000,
// "LocalRandomPlayer");
//Console.WriteLine();
Start(new MemberRandomPlayer(),
new MemberRandomPlayer(),
10000,
"MemberRandomPlayer");
Console.WriteLine();
}
Console.WriteLine("終了時間:{0}", DateTime.Now.ToString("F"));
}
static void Start(IPlayer m, IPlayer b, int num, string typeCode)
{
int[] count = new int[3];
Judge judge = new Judge(m, b);
for (int i = 0; i < num; i++)
count[judge.Game()]++;
Console.WriteLine("---{0}---", typeCode);
Console.WriteLine("○Win\t:{0}", count[1]);
Console.WriteLine("×Win\t:{0}", count[2]);
Console.WriteLine("Draw\t:{0}", count[0]);
}
}
|



syat
#6190()
Rating4/4=1.00
マルバツゲームは3×3の格子に交互に○と×を書き込み、先に縦・横・斜めに記号をそろえたほうが勝ちというおなじみのゲームです。
「毎ターン乱数を使って手を決めるランダムプレイヤー同士を対戦させる」というのが今回のお題です。 1万回対戦させ、勝ち・負け・引き分けの数を表示してください。 そして先手が有利であることを確かめてください。
良い手を思考するプレイヤーについては別のお題にしようと思っています。 プレイヤーを簡単に差し換えることができる設計を目指してください。
[ reply ]