2017-03-08 11 views
1

ジェネリックベースのインタフェースIGameble(例:moveはジェネリック)とクラス:ChessとTic-Tac-Toe(さらに多くのボードゲーム)もはや一般的ではありません。C#でgenericの代わりにpolymorphismを使用する方法

は、私は(ない同じ時間で)ゲームのあらゆる種類を再生します(これらのいくつかの種類があるかもしれない)クラスのエージェントを設計したいのですが、問題は、私は、たとえば

を傾けることです。

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} 

問題は(一度に1ゲーム)すべてのゲームをプレイするために、私はランダムエージェント(または任意の他の薬剤)の1つのインスタンスをしたいということで、一般的な、具体的T_Moveの種類を選択するために私を強制使用私が使用したいT_Matrixがあります。

私はそれがすべて間違っている可能性があり、ジェネリックをあまり使用していない可能性があります。

ジェネリックの代わりにIMovableとIBoardableを使用するように提案がありました。それは正しいデザインですか?それはすべての問題を解決するだろうか?

私はまだC#で​​デザインパターンでnoobieよ:(

1がある場合、いくつかのいずれかがここで私を助けることができるいくつかのデザインパターン(へのリンクを得ることができる場合も、私はそれを非常に感謝されます

...)私はあなただけisキーワードを使用することができると思う

+2

あなたTの目的は何ですか?私はあなたが達成しようとしていることを正確に理解できません。あなたのインターフェイスにいくつかのメソッドを置くことができますか?いくつかの実装を、より多くの問題を記述できるクラスに入れてください。 – kat1330

+5

もっと現実的なコードを与えてください。 A B C Eのような名前は私の脳を燃やす。 – apocalypse

+4

あなたの目標は何であるかはっきりしていません。おそらくあなたの汎用インターフェースはあなたが達成しようとしている目標に対して不適切に設計されており、不適切なデザインに言語を適合させるのに苦労しています –

答えて

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(); 
    } 
} 
+0

これはまさに私が探していた種類のコードです!多くのthx:D – pio

3

:。いくつかのコメンターが指摘したように、あなたがしたくないかもしれませんので、C#で

public D(IA<T> a_) 
{ 
    if (a_ is B) 
    { 
     //do something 
    } 
    else if (a_ is C) 
    { 
     //do something else 
    } 
} 

ジェネリックは、C++ほど柔軟ではありませんあなたは中間インターフェイスを設計したいかもしれませんが、たとえばIMoveというように、あなたのアルゴリズムが動きを一般的な方法で列挙するために使用できることを示します。

+0

私は中間インターフェイスIMovableを設計することは、どんな種類のクラスであるかをいつでも尋ねるよりも良いと思う。 isキーワードについては分かっていませんが。 そんなにたくさん! – pio

関連する問題