我有一个通用的基础接口IGameble(用于示例移动是通用的)和类:Chess和Tic-Tac-Toe(以及更多的棋盘游戏),它们来自通用接口IGmable但不再是通用的。
我想设计类代理(可能有几种类型)可以播放任何类型的游戏(不是同时),但问题是我不能
例如:
interface IGame<T_move,T_matrix>
{
T_matrix[,] game_state { get; }
void MakeMove(Move mov);
List<Move> ListAllMoves();
...// some more irrelevant code
}
class Tic_Tac_Toe : IGameble<Tuple<int,int>,int>
{
public int turn;
public int[,] game_state;
public List<Tuple<int,int>> ListAllMoves() {...}
public void MakeMove(Tuple<int,int> mov) {...}
}
public Chess : IGameble <some other kind> //...
// so on more classes which uses other kind in the generic.
interface IAgent<Move>
{
Move MakeMove();
}
public RandomAgent<T_Move,T_Matrix> : IAgent
{
public IGameble<T_move> game;
public D(IGameble game_) {game = game_}
public T_Move MakeMove() {//randomly select a move}
}
public UserAgent<T_Move,T_Matrix> : IAgent {get the move from the user}
问题是我想要一个随机代理(或任何其他代理)的实例来玩所有游戏(一次一个游戏)并使用通用强制我专门选择我的T_Move和T_Matrix的类型想用。
我可能会把它全部弄错,并且使用的通用版本很差。
有人建议使用IMovable和IBoardable而不是通用。这是正确的设计吗?它会解决所有问题吗?
我在C#的设计模式中仍然是一个noobie :(
如果有人可以获得一些可以帮助我的设计模式的链接(如果有一个......),我将非常感激。
答案 0 :(得分:3)
我认为您可以使用is
关键字:
public D(IA<T> a_)
{
if (a_ is B)
{
//do something
}
else if (a_ is C)
{
//do something else
}
}
C#中的泛型并不像C ++那样灵活,所以正如一些评论者指出的那样,你可能不想这样做。您可能想要设计一个中间接口,比如IMove
,您的算法可以使用它来以通用的方式枚举移动。
答案 1 :(得分:1)
我不知道你想要什么,但你可以不用泛型来做。
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main (string[] args)
{
var game = new TicTacToe (
(x) => new UserAgent (x, "John"),
(x) => new RandomAgent (x));
game.Play ();
Console.ReadKey ();
}
}
public interface IGame
{
IMove[] GetAvailableMoves ();
}
public interface IMove
{
void MakeMove ();
string Description { get; }
}
public interface IAgent
{
string Name { get; }
IMove SelectMove ();
}
public delegate IAgent AgentCreator (IGame game);
public class RandomAgent : IAgent
{
private readonly IGame game;
private readonly Random random = new Random ();
public RandomAgent (IGame game)
{
this.game = game;
}
public string Name => "Computer (random moves)";
public IMove SelectMove ()
{
var availableMoves = game.GetAvailableMoves ();
int moveIndex = random.Next (availableMoves.Length);
return availableMoves[moveIndex];
}
}
public class UserAgent : IAgent
{
private readonly IGame game;
public UserAgent (IGame game, string playerName)
{
this.game = game;
Name = playerName;
}
public string Name { get; }
public IMove SelectMove ()
{
var availableMoves = game.GetAvailableMoves ();
Console.WriteLine ("Choose your move:");
for (int i = 0; i < availableMoves.Length; i++)
{
Console.WriteLine (i + " " + availableMoves[i].Description);
}
int selectedIndex = int.Parse (Console.ReadLine ());
return availableMoves[selectedIndex];
}
}
public class TicTacToe : IGame
{
enum CellState { Empty = 0, Circle, Cross }
CellState[] board = new CellState[9]; // 3x3 board
int currentPlayer = 0;
private IAgent player1, player2;
public TicTacToe (AgentCreator createPlayer1, AgentCreator createPlayer2)
{
player1 = createPlayer1 (this);
player2 = createPlayer2 (this);
}
public void Play ()
{
PrintBoard ();
while (GetAvailableMoves ().Length > 0)
{
IAgent agent = currentPlayer == 0 ? player1 : player2;
Console.WriteLine ($"{agent.Name} is doing a move...");
var move = agent.SelectMove ();
Console.WriteLine ("Selected move: " + move.Description);
move.MakeMove (); // apply move
PrintBoard ();
if (IsGameOver ()) break;
currentPlayer = currentPlayer == 0 ? 1 : 0;
}
Console.Write ("Game over. Winner is = ..."); // some logic to determine winner
}
public bool IsGameOver ()
{
return false;
}
public IMove[] GetAvailableMoves ()
{
var result = new List<IMove> ();
for (int i = 0; i < 9; i++)
{
var cell = board[i];
if (cell != CellState.Empty) continue;
int index = i;
int xpos = (i % 3) + 1;
int ypos = (i / 3) + 1;
var move = new Move ($"Set {CurrentPlayerSign} on ({xpos},{ypos})", () =>
{
board[index] = currentPlayer == 0 ? CellState.Cross : CellState.Circle;
});
result.Add (move);
}
return result.ToArray ();
}
private char CurrentPlayerSign => currentPlayer == 0 ? 'X' : 'O';
public void PrintBoard ()
{
Console.WriteLine ("Current board state:");
var b = board.Select (x => x == CellState.Empty ? "." : x == CellState.Cross ? "X" : "O").ToArray ();
Console.WriteLine ($"{b[0]}{b[1]}{b[2]}\r\n{b[3]}{b[4]}{b[5]}\r\n{b[6]}{b[7]}{b[8]}");
}
}
public class Move : IMove // Generic move, you can also create more specified moves like ChessMove, TicTacToeMove etc. if required
{
private readonly Action moveLogic;
public Move (string moveDescription, Action moveLogic)
{
this.moveLogic = moveLogic;
Description = moveDescription;
}
public string Description { get; }
public void MakeMove () => moveLogic.Invoke ();
}
}