88 votes

La Conception Orientée objet pour un jeu d'Échecs

Je suis en train d'essayer de se faire une idée de la façon de concevoir et de penser à un Objet de façon Orientée et souhaitez obtenir des commentaires de la communauté sur ce sujet. Ce qui suit est un exemple d'un jeu d'échecs, que je souhaite conception OO. C'est un domaine très large de la conception et de mon accent, à ce stade, c'est juste pour déterminer qui est responsable de ce que les messages et la façon dont les objets interagissent les uns des autres pour simuler le jeu. S'il vous plaît signaler si il y a des éléments de mauvaise conception (haute couplage, mauvaise cohésion etc.) et comment les améliorer.

Le jeu d'Échecs a les classes suivantes

  • Conseil
  • Joueur
  • Pièce
  • Carré
  • Jeu d'échecsjeu

Le Conseil d'administration est composé de carrés et ainsi de Conseil peut être tenue pour responsable de la création et de la gestion des Carrés des objets. Chaque pièce est aussi sur un carré de sorte que chaque pièce a aussi une référence à la place c'est sur. (Est-il logique?). Chaque pièce est alors responsable de se déplacer d'une place à l'autre. Joueur de classe contient des références à toutes les pièces qu'il possède et est également responsable de la création (le joueur Doit créer des Pièces?) . Le joueur a une méthode takeTurn qui à son tour appelle une méthode movePiece qui appartient à la pièce de Classe qui modifie l'emplacement de la pièce à partir de son emplacement actuel vers un autre emplacement. Maintenant, je suis confus sur ce qu'est exactement le Conseil de classe doit être responsable. J'ai supposé que c'était nécessaire pour déterminer l'état actuel du jeu et de savoir quand le jeu est terminé. Mais quand un morceau change d'emplacement comment le conseil doit-il mis à jour? faut-il maintenir un autre tableau de places de pièces sur lesquelles existent et qui obtient des mises à jour des pièces?

Aussi, le jeu d'échecsjeu d'abord crée le Conseil et le joueur des objets qui, à leur tour créer des places et des pièces de, respectivement, et de commencer la simulation. Brièvement, ce pourrait être ce que le code de jeu d'échecsjeu peut ressembler à

Player p1 =new Player();
Player p2 = new Player();

Board b = new Board();

while(b.isGameOver())
{
  p1.takeTurn(); // calls movePiece on the Piece object
  p2.takeTurn();

}

Je suis dans le flou sur la manière dont l'état du conseil d'administration sera mis à jour. Devrait pièce de disposer d'une référence à la carte? Où devrait être de la responsabilité mensonge? Qui détient quelles sont les références? S'il vous plaît aidez-moi avec vos entrées et signaler des problèmes dans cette conception. Je suis délibérément de ne pas se concentrer sur les algorithmes ou d'autres détails de jeu de jeu que je suis seulement intéressé par l'aspect de la conception. J'espère que cette communauté peuvent fournir de précieuses informations.

54voto

cdhowie Points 62253

J'ai en fait juste écrit un plein C# de la mise en œuvre d'un échiquier, les pièces, les règles, etc. Voici à peu près comment je l'ai modélisé (mise en œuvre effective supprimé car je ne veux pas prendre tout le plaisir de votre codage):

public enum PieceType {
    None, Pawn, Knight, Bishop, Rook, Queen, King
}

public enum PieceColor {
    White, Black
}

public struct Piece {
    public PieceType Type { get; set; }
    public PieceColor Color { get; set; }
}

public struct Square {
    public int X { get; set; }
    public int Y { get; set; }

    public static implicit operator Square(string str) {
        // Parses strings like "a1" so you can write "a1" in code instead
        // of new Square(0, 0)
    }
}

public class Board {
    private Piece[,] board;

    public Piece this[Square square] { get; set; }

    public Board Clone() { ... }
}

public class Move {
    public Square From { get; }
    public Square To { get; }
    public Piece PieceMoved { get; }
    public Piece PieceCaptured { get; }
    public PieceType Promotion { get; }
    public string AlgebraicNotation { get; }
}

public class Game {
    public Board Board { get; }
    public IList<Move> Movelist { get; }
    public PieceType Turn { get; set; }
    public Square? DoublePawnPush { get; set; } // Used for tracking valid en passant captures
    public int Halfmoves { get; set; }

    public bool CanWhiteCastleA { get; set; }
    public bool CanWhiteCastleH { get; set; }
    public bool CanBlackCastleA { get; set; }
    public bool CanBlackCastleH { get; set; }
}

public interface IGameRules {
    // ....
}

L'idée de base est que le Jeu/Jeux/etc il suffit de stocker l'état du jeu. Vous pouvez les manipuler, par exemple de définir une position, si c'est ce que vous voulez. J'ai une classe qui implémente mon IGameRules interface qui est responsable de:

  • La détermination de ce qui bouge sont valables, y compris la roque et en passant.
  • Déterminer si un mouvement est valide.
  • Déterminer quand les joueurs sont en check/mat/impasse.
  • L'exécution des mouvements.

En séparant les règles du jeu/jeux classes signifie également que vous pouvez mettre en œuvre des variantes relativement facilement. Toutes les méthodes de la réglementation de l'interface de prendre un Game objet qui ils peuvent inspecter pour déterminer les mouvements sont valides.

Notez que je ne stocke pas les informations du joueur sur Game. J'ai une classe distincte Table qui est responsable de la conservation jeu de métadonnées telles que l'oms était en train de jouer, quand le jeu a eu lieu, etc.

EDIT: Note que le but de cette réponse n'est pas vraiment vous donner de code de modèle vous pouvez remplir -- mon code a un peu plus d'informations stockées sur chaque élément, plusieurs méthodes, etc. Le but est de vous guider vers l'objectif que vous essayez d'atteindre.

6voto

dharm0us Points 3389

Voici mon idée, pour une assez basic jeu d'échecs :

class GameBoard {
 IPiece config[8][8];  

 init {
  createAndPlacePieces("Black");
  createAndPlacePieces("White");
  setTurn("Black");

 }

 createAndPlacePieces(color) {
   //generate pieces using a factory method
   //for e.g. config[1][0] = PieceFactory("Pawn",color);
 }

 setTurn(color) {
   turn = color;
 }

 move(fromPt,toPt) {
  if(getPcAt(fromPt).color == turn) {
    toPtHasOppositeColorPiece = getPcAt(toPt) != null && getPcAt(toPt).color != turn;
    possiblePath = getPcAt(fromPt).generatePossiblePath(fromPt,toPt,toPtHasOppositeColorPiece);
   if(possiblePath != NULL) {
      traversePath();
      changeTurn();
   }
  }
 } 

}

Interface IPiece {
  function generatePossiblePath(fromPt,toPt,toPtHasEnemy);
}

class PawnPiece implements IPiece{
  function generatePossiblePath(fromPt,toPt,toPtHasEnemy) {
    return an array of points if such a path is possible
    else return null;
  }
}

class ElephantPiece implements IPiece {....}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X