Programing

체스 게임을위한 객체 지향 디자인

lottogame 2020. 9. 12. 11:19
반응형

체스 게임을위한 객체 지향 디자인 [닫힘]


저는 객체 지향 방식으로 디자인하고 생각하는 방법에 대한 느낌을 얻으려고 노력하고 있으며이 주제에 대한 커뮤니티의 피드백을 받고 싶습니다. 다음은 OO 방식으로 디자인하고 싶은 체스 게임의 예입니다. 이것은 매우 광범위한 디자인이며이 단계에서 저의 초점은 누가 어떤 메시지를 담당하고 게임을 시뮬레이션하기 위해 오브젝트가 서로 어떻게 상호 작용하는지 식별하는 것입니다. 잘못된 설계 요소 (높은 커플 링, 나쁜 응집성 등)가 있는지 그리고 개선 방법을 지적하십시오.

체스 게임에는 다음과 같은 클래스가 있습니다.

  • 플레이어
  • 조각
  • 광장
  • 체스 게임

Board는 사각형으로 구성되어 있으므로 Board는 Square 개체의 생성 및 관리를 담당 할 수 있습니다. 각 조각은 또한 사각형에 있으므로 각 조각에는 해당 사각형에 대한 참조도 있습니다. (이게 말이 돼?). 그런 다음 각 조각은 한 사각형에서 다른 사각형으로 이동해야합니다. Player 클래스는 자신이 소유 한 모든 조각에 대한 참조를 보유하고 있으며 해당 조각의 생성도 담당합니다 (플레이어가 조각을 만들어야합니까?). Player에는 현재 위치에서 다른 위치로 조각의 위치를 ​​변경하는 조각 클래스에 속하는 movePiece 메서드를 차례로 호출하는 takeTurn 메서드가 있습니다. 이제 Board 클래스가 정확히 무엇을 담당해야하는지 혼란 스럽습니다. 나는 게임의 현재 상태를 확인하고 게임이 언제 끝나는 지 알기 위해 필요하다고 생각했습니다. 하지만 조각이 바뀌면 s 위치 게시판은 어떻게 업데이트해야합니까? 조각이 존재하고 조각이 이동함에 따라 업데이트를받는 별도의 사각형 배열을 유지해야합니까?

또한 ChessGame은 처음에 각각 사각형과 조각을 생성하고 시뮬레이션을 시작하는 보드 및 플레이어 개체를 생성합니다. 간단히 말해서 ChessGame의 코드가 다음과 같을 수 있습니다.

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();

}

이사회 상태가 어떻게 업데이트 될지 잘 모르겠습니다. 조각에 보드에 대한 참조가 있어야합니까? 책임은 어디에 있어야합니까? 누가 어떤 참조를 가지고 있습니까? 당신의 의견을 도와 주시고이 디자인의 문제점을 지적 해주세요. 나는 디자인 측면에만 관심이 있기 때문에 의도적으로 알고리즘이나 게임 플레이의 추가 세부 사항에 초점을 맞추지 않습니다. 이 커뮤니티가 귀중한 통찰력을 제공 할 수 있기를 바랍니다.


사실 난 단지 내가 (내가 먹고 싶어하지 않기 때문에 실제 구현 제거를 모델링 방법은 다음과 대략의 등 체스 보드, 조각, 규칙, 전체의 C # 구현을 쓴 모든 당신의 코딩의 즐거움을) :

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 {
    // ....
}

기본 아이디어는 게임 / 보드 등이 단순히 게임의 상태를 저장한다는 것입니다. 예를 들어 원하는 경우 위치를 설정하도록 조작 할 수 있습니다. 다음을 담당하는 IGameRules 인터페이스를 구현하는 클래스가 있습니다.

  • castling 및 en passant를 포함하여 유효한 동작을 결정합니다.
  • 특정 이동이 유효한지 확인합니다.
  • 플레이어가 체크 / 체크 메이트 / 부실한시기를 결정합니다.
  • 동작을 실행합니다.

Separating the rules from the game/board classes also means you can implement variants relatively easily. All methods of the rules interface take a Game object which they can inspect to determine which moves are valid.

Note that I do not store player information on Game. I have a separate class Table that is responsible for storing game metadata such as who was playing, when the game took place, etc.

EDIT: Note that the purpose of this answer isn't really to give you template code you can fill out -- my code actually has a bit more information stored on each item, more methods, etc. The purpose is to guide you towards the goal you're trying to achieve.


Here is my idea, for a fairly basic chess game :

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 {....}

I recently created a chess program in PHP (website click here, source click here) and I made it object oriented. Here are the classes I used.

  • ChessRulebook (static) - I put all my generate_legal_moves() code in here. That method is given a board, whose turn it is, and some variables to set the level of detail of the output, and it generates all the legal moves for that position. It returns a list of ChessMoves.
  • ChessMove - Stores everything needed to create algebraic notation, including starting square, ending square, color, piece type, capture, check, checkmate, promotion piece type, and en passant. Optional additional variables include disambiguation (for moves like Rae4), castling, and board.
  • ChessBoard - Stores the same information as a Chess FEN, including an 8x8 array representing the squares and storing the ChessPieces, whose turn it is, en passant target square, castling rights, halfmove clock, and fullmove clock.
  • ChessPiece - Stores piece type, color, square, and piece value (for example, pawn = 1, knight = 3, rook = 5, etc.)
  • ChessSquare - Stores the rank and file, as ints.

I am currently trying to turn this code into a chess A.I., so it needs to be FAST. I've optimized the generate_legal_moves() function from 1500ms to 8ms, and am still working on it. Lessons I learned from that are...

  • Do not store an entire ChessBoard in every ChessMove by default. Only store the board in the move when needed.
  • Use primitive types such as int when possible. That is why ChessSquare stores rank and file as int, rather than also storing an alphanumeric string with human readable chess square notation such as "a4".
  • The program creates tens of thousands of ChessSquares when searching the move tree. I will probably refactor the program to not use ChessSquares, which should give a speed boost.
  • Do not calculate any unnecessary variables in your classes. Originally, calculating the FEN in each of my ChessBoards was really killing the program's speed. I had to find this out with a profiler.

I know this is old, but hopefully it helps somebody. Good luck!

참고URL : https://stackoverflow.com/questions/4168002/object-oriented-design-for-a-chess-game

반응형