2013-12-14 16 views
5

OK, jestem w trakcie tworzenia prostej gry szachowej Java. To pytanie dotyczy raczej projektu OOP niż Java Swing.OOP desing, Java Swing, gra w szachy, instanceof

mam następujące:

  • Mam klasy panel, który implementuje JPanel.
  • Mam następnie klasą abstrakcyjną kawałek, który rozciąga się od mojej klasie Panelu
  • Wtedy mam zajęcia dla różnych elementów: Pożyczki, król, biskup etc, które rozciągają się od mojej klasie Elementów

W moim głównym ChessGame Klasa:

  • Używam tablicę Panelu przechowywać układ moim pokładzie
  • więc tablica będzie przechowywać, obiekty pANEL, miejsc płyta z żadnym sztuk na nim.
  • I będzie przechowywać, podklasy, takie jak Pożyczki, Queen, Bishop etc (miejsc płyta z kawałkach)

Tak, lewy górny kwadrat (0,0) mapuje do mojaTablica [0] [0]

Mój problem polega na tym, aby sprawdzić, czy miejsce jest pusta lub szachy w nim muszę używać:

 if(panels[x][y] instanceof Piece){ 
      ((Piece)panels[x][y]).makeMove(); 
     } 

co pytam jest to straszny projekt? Wiem, że powinienem starać się unikać przykładów. Jakie byłoby lepsze podejście?

Dzięki.

+0

Możesz wpisać 'null', aby powiedzieć, że tam nie ma elementu, lub możesz utworzyć nową klasę' Empty' i dziedziczyć z panelu, a następnie tak, instanceof jest dobrym sposobem dookoła. – kajacx

+0

@kajacx sprawiają, że odpowiedź. To jest idealne. – DiogoSantana

+0

@kajacx Dzięki za szybką odpowiedź. Obiekty panelu zapewniają funkcjonalność, tworzą puste miejsca na planszy. Więc nie jestem pewien, czy zadziała null. Moja klasa Panel to moja pusta klasa, prawda? Po prostu tworzy puste miejsca na planszy. – user1543871

Odpowiedz

0

Zamiast dzielić panel na 8x8 mniejszych paneli, należy narysować planszę i elementy na płótnie. Później gracze będą w końcu przeciągać, aby przenieść kawałki na pokładzie. Możesz również szukać prezentacji Bitboardowej w grze szachowej, chociaż ta prezentacja jest wymagana tylko w przypadku silników szachowych, które są w stanie "myśleć" o szybkich obliczeniach, nadal jest przydatna, gdy musisz sprawdzić, czy ruch, który gracz próbuje wykonać, jest poprawny.

Posible Bitboard:

public class BitBoard 
{ 
    public static final int P = 0; 
    public static final int N = 2; 
    public static final int B = 4; 
    public static final int R = 6; 
    public static final int Q = 8; 
    public static final int K = 10; 

    public static final int p = 1; 
    public static final int n = 3; 
    public static final int b = 5; 
    public static final int r = 7; 
    public static final int q = 9; 
    public static final int k = 11; 

    // empty field 
    public static final int empty = 12; 

    // number of pieces , squares 
    public static final int nPieces = 12; 
    public static final int nSquares = 64; 

    public static final int whitePieces = 12; 
    public static final int blackPieces = 13; 
    public static final int nBoards = 14; 

    public static long squareBits[]; 

    // static member initialization 
    static 
    { 
     squareBits = new long[64]; 
     long square = 1; 
     square = square << 8 * 8 - 1; 
     for (int i = 0; i < 64; i++) { 
      squareBits[i] = square >>> i; 
     } 
    } 

    long bitBoards[]; 

    public BitBoard() { 
     bitBoards = new long[nBoards]; 
    } 

    public boolean initBoard() 
    { 
     // Put the pieces on the board 
     EmptyBoard(); 
     addPiece(0, r); 
     addPiece(1, n); 
     addPiece(2, b); 
     addPiece(3, q); 
     addPiece(4, k); 
     addPiece(5, b); 
     addPiece(6, n); 
     addPiece(7, r); 
     for (int i = 8; i < 16; i++) { 
      addPiece(i, p); 
     } 

     for (int i = 48; i < 56; i++) { 
      addPiece(i, P); 
     } 
     addPiece(56, R); 
     addPiece(57, N); 
     addPiece(58, B); 
     addPiece(59, Q); 
     addPiece(60, K); 
     addPiece(61, B); 
     addPiece(62, N); 
     addPiece(63, R); 

     return true; 
    } 

    public boolean addPiece(int whichSquare, int whichPiece) 
    { 
     bitBoards[whichPiece] |= squareBits[whichSquare]; 
     bitBoards[nPieces + (whichPiece % 2)] |= squareBits[whichSquare]; 
     return true; 
    } 

    private boolean removePiece(int whichSquare, int whichPiece) 
    { 
     bitBoards[whichPiece] ^= squareBits[whichSquare]; 
     bitBoards[nPieces + (whichPiece % 2)] ^= squareBits[whichSquare]; 
     return true; 
    } 

    private boolean EmptyBoard() 
    { 
     for (int i = 0; i < nBoards; i++) 
     { 
      bitBoards[i] = 0; 
     } 
     return true; 
    } 
} 
0

Po rozważeniu problemu, a znając domeny problemu, chciałbym rzeczywiście sugerują następujące ...

W swojej klasie Panel zaimplementować funkcję int hasMass() następująco .. .

public int hasMass() { 
    return 0; 
} 

w klasie Piece ręcznym, że działają w następujący sposób ...

public int hasMass() { 
    if (isWhite()) // white pieces are negative. 
    return -1; 
    return 1; // black pieces positive. 
} 

Teraz możesz sprawdzić, czy kwadrat ma część, czy inny element może ją przyjąć ... (ponieważ mają przeciwną polaryzację) ... np. masa + masa == 0 oznacza przechwytywanie,! = 0 oznacza, że ​​panel był pusty. I oczywiście bezwzględna wartość 2 (dla masy) oznaczałaby, że ruch był nielegalny.

4

Nie należy łączyć kodu modelu (sztuki) z kodem widoku (JPanels).Jeśli kiedykolwiek chcesz zmienić sposób wyświetlania tablicy, musisz zmienić sposób przechowywania sztuk!

Lepszym projektem może być oddzielenie Piece od JPanels. Następnie możesz użyć pojedynczego JPanela do wyświetlenia macierzy Sztuk: Pieces[8][8].

Mój problem polega na tym, aby sprawdzić, czy miejsce jest pusta lub szachy w nim muszę używać:

przypadku korzystania z macierzy, można po prostu mieć zerową komórkę lub użyj Null Object Wzór do "pustego" kawałka.

EDIT

każdej komórki w macierzy jednostkowej jest kwadratowy na płytce tak piece[0][0] będzie górnym rogu płyty (A8).

Aby pomalować tablicę, twoja metoda paintComponent() będzie musiała powtórzyć tę macierz i odpowiednio narysować każdą komórkę. Istnieje kilka sposobów, aby zaimplementować to:

  1. trzeba by zrobić podobny instanceof sprawdzić rysować każdego rodzaju sztukę inaczej

  2. Utwórz nowy pośredni „Strategia farba” obiekt używając wzorca strategii. Może to wymagać macierzy obiektów strategii zamiast obiektów części. Być może nadal będziesz musiał wykonać kontrole, ale może tylko raz, aby utworzyć obiekty strategii.

+0

Zgadzam się, nie jestem pewien, czy rozumiem, co masz na myśli pod względem podejścia? Więc tablica int lub char może być przechowywana, gdzie każdy element jest na planszy? Następnie dodaj JPanels, aby dopasować konfigurację macierzy Pieces? – user1543871

+0

@ user1543871 dodane zmiany – dkatzel

+0

OK dzięki. Zrobię to. Czyli liczenie kart jest lepszym rozwiązaniem niż użycie 64 JPaneli? – user1543871

0

Chciałbym zachować strukturę kawałków oddzielnie od renderowanej planszy.

Na przykład chciałbym, aby figury szachowe były czystymi modelami bez znajomości trafienia, które są renderowane.

Pieces (baseclass) 
+- Pawn 
+- Knight 
+- King 
+- Queen 
+- ..etc 

Pozwoli to zachować tablicę tylko elementów, gdzie puste kwadraty są puste.

Dla uproszczenia, to bym po prostu macierz peices: (oczywiście metoda inicjalizacji przemierzać swoją płytę „” i wypełnić planszę w/początkowych pozycjach)

Peices[][] board = new Pieces[8][8]; 

Chciałbym wtedy mieć widoczną tablicę zbudowaną z JPanels; klasa o nazwie "Szachy" do zarządzania grą; oraz faktyczne renderowanie płytki/panelu w funkcji przenoszenia. Wyobraź sobie:

// what a move might look like when initializing your panels 
piece = board [0][0]; 
Chess.move(piece, 0 ,0); //responsible for clearing the old panel and rendering the panel at target location. 

Gdy użytkownik wchodzi w interakcję w/swojej game..they kliknij swoją panels..which daje współrzędne panel. Za pomocą tych samych współrzędnych w/swoim „pokładzie”, aby ustalić, co kawałek is..how może poruszać etc ..

Coś takiego ...

ja po prostu reprezentują planszę za pomocą obiektów. ..dla prostoty. Najprościej zrozumieć ... a poza tym ... komputery są teraz dużo szybkie.

+0

Tak, całkowicie się zgadzam. Wszelkie porady, jak to zrobić? Może tablica int lub string do przechowywania ustawień płyty? Następnie dopasuj odpowiedni JPanel do każdego elementu tablicy? – user1543871

0

OK, chory zacznij od odrzucenia opcji ustawienia wartości pustej, aby wskazać, że miejsce jest puste (możesz to zrobić ofc, ale używanie klasy Empty jest po prostu "lepsze" w pewnym sensie).

Więc powiedzmy, że masz tablicę Panel s reprezentujący swoją planszę:

Panel[][] board; 

Teraz ilustration, jak twoja hierarchia klasa mogłaby wyglądać następująco:

abstract class Panel extends JPanel { ... } 

class Empty extends Panel { ... } 

abstract class Piece extends Panel { ... } 

class Pawn extends Piece { ... } 

... 

Moja klasa panel jest moja pusta klasa, prawda?

Nie jestem pewien, czy rozumiem cię, ale rzućmy okiem na to, co extends oznacza dokładnie: w show nmodel każdy kawałek jest również panel lub każdy Pożyczki jest także kawałek, więc każdy pionek może wykonuj wszystkie czynności tak samo jak Piece (na przykład 4 to liczba zespolona, ​​a także liczba naturalna lub liczba rzeczywista, więc w pewnym sensie można powiedzieć, że liczby rzeczywiste rozszerzają liczby zespolone o, ponieważ każda liczba rzeczywista jest również złożona numer)

Teraz możesz mieć trochę ładny abstrakcyjny getTexture() metoda zadeklarowana w Panel wdrożona w klasie Empty i we wszystkich podklasach Piece, a podczas rysowania Panel, nie trzeba patrzeć, czy jest pusta czy nie.

0

Zamiast tworzyć (zakładam) niemal identyczne klasy dla każdego kawałka (wieża, pionek, królowa itp.), Można po prostu zachować oryginalną klasę Piece, uczynić ją nie abstrakcyjną i dodać do niej pole PieceType. PieceType to po prostu enum, który mówi, jaki rodzaj elementu (jeśli jest) jest tam umieszczony. Zamiast używać instanceof, teraz możesz sprawdzić, używając panels[i][j].getType() == PieceType.ROOK. Przynajmniej to właśnie robię w mojej implementacji :)

Używam także JLabel zamiast JPanel dla mojej planszy 8x8.

+0

Klasy nie będą identyczne, każda klasa będzie miała metody wykonywania ruchów. – user1543871

+0

Najlepszą praktyką jest oddzielenie kodu UI od logiki. Oznacza to umieszczenie kodu ruchu (i sprawdź logikę, en passant itp.) Na zewnątrz paneli i utrzymywanie paneli do wyświetlania dowolnego elementu (jeśli jest). Ale to zależy od Ciebie. Przyjrzyj się wzorowi MVC (Model-View-Controler), jeśli chcesz. – async