|
@@ -40,66 +40,108 @@ import javax.swing.JFrame;
|
40
|
40
|
*/
|
41
|
41
|
public class GameWindow extends JFrame implements GameObserver, MouseListener, KeyListener {
|
42
|
42
|
|
|
43
|
+ /**
|
|
44
|
+ * A version number for this class. It should be changed whenever the class
|
|
45
|
+ * structure is changed (or anything else that would prevent serialized
|
|
46
|
+ * objects being unserialized with the new class).
|
|
47
|
+ */
|
43
|
48
|
private static final long serialVersionUID = 1;
|
44
|
49
|
|
|
50
|
+ /** The delay between events for the "fast" speed. */
|
45
|
51
|
public final static int SPEED_FAST = 200;
|
|
52
|
+ /** The delay between events for the "normal" speed. */
|
46
|
53
|
public final static int SPEED_NORMAL = 1000;
|
|
54
|
+ /** The delay between events for the "slow" speed. */
|
47
|
55
|
public final static int SPEED_SLOW = 5000;
|
48
|
56
|
|
|
57
|
+ /** The initial width of the window. */
|
49
|
58
|
private final static int WIDTH = 800;
|
|
59
|
+ /** The initial height of the window. */
|
50
|
60
|
private final static int HEIGHT = 600;
|
51
|
61
|
|
|
62
|
+ /** The number of buttons shown on each side. */
|
52
|
63
|
private final static int NUM_BUTTONS = 4;
|
53
|
64
|
|
|
65
|
+ /** The width of buttons. */
|
54
|
66
|
private final static int BUTTON_WIDTH = 100;
|
|
67
|
+ /** The height of buttons. */
|
55
|
68
|
private final static int BUTTON_HEIGHT = 25;
|
56
|
|
- private final static int BUTTON_OFFSET = 25;
|
|
69
|
+ /** The offset from the screen edge of the buttons. */
|
|
70
|
+ private final static int BUTTON_OFFSET = 15;
|
|
71
|
+ /** The space between each button. */
|
57
|
72
|
private final static int BUTTON_SPACER = 10;
|
58
|
73
|
|
|
74
|
+ /** The width of the cards in use. */
|
59
|
75
|
private int cardWidth = 71;
|
|
76
|
+ /** The height of the cards in use. */
|
60
|
77
|
private int cardHeight = 96;
|
|
78
|
+ /** The space between each card. */
|
61
|
79
|
private final static int CARD_SPACER = 4;
|
62
|
80
|
|
|
81
|
+ /** The horizontal offset of the community ccards. */
|
63
|
82
|
private int communityOffset = 150;
|
|
83
|
+ /** The offset of each community card from the others if there's enough space. */
|
64
|
84
|
private int cardLargeOffset = cardWidth + CARD_SPACER;
|
|
85
|
+ /** The offset of each community card from the others if there's not enough space. */
|
65
|
86
|
private int cardShortOffset = 25;
|
66
|
|
-
|
|
87
|
+ /** The amount of space required to use the large offset. */
|
67
|
88
|
private int communityMinSize = 2 * communityOffset + 6 * cardWidth + 5 * CARD_SPACER;
|
68
|
89
|
|
|
90
|
+ /** The background colour to use. */
|
69
|
91
|
private Color backgroundColour = new Color(0, 100, 0);
|
70
|
92
|
|
|
93
|
+ /** The current speed. */
|
71
|
94
|
private int speed = SPEED_NORMAL;
|
72
|
95
|
|
73
|
|
- private Game game;
|
|
96
|
+ /** The game we're playing. */
|
|
97
|
+ private final Game game;
|
74
|
98
|
|
|
99
|
+ /** The player whose turn it is. */
|
75
|
100
|
private Player turn;
|
|
101
|
+ /** The player who has an outstanding message. */
|
76
|
102
|
private Player messagePlayer;
|
77
|
103
|
|
|
104
|
+ /** A list of known winners. */
|
78
|
105
|
private final List<Player> winners = new ArrayList<Player>();
|
79
|
|
- private final Map<Player, Integer> percentages = new HashMap<Player, Integer>();
|
|
106
|
+ /** A position where the next card should be dealt to for each player. */
|
80
|
107
|
private final Map<Player, Point> nextCardPos = new HashMap<Player, Point>();
|
81
|
108
|
|
|
109
|
+ /** The current player message. */
|
82
|
110
|
private String message;
|
83
|
111
|
|
|
112
|
+ /** The human player who we're waiting for to chose his move. */
|
84
|
113
|
private HumanPlayer player = null;
|
|
114
|
+ /** The human player who we're waiting for to continue. */
|
85
|
115
|
private HumanPlayer waitPlayer = null;
|
|
116
|
+ /** The human player who we're waiting for to discard. */
|
86
|
117
|
private HumanPlayer discardPlayer = null;
|
87
|
118
|
|
|
119
|
+ /** The minimum number of cards that need discarding. */
|
88
|
120
|
private int discardMin = -1;
|
|
121
|
+ /** The maximum number of cards that need discarding. */
|
89
|
122
|
private int discardMax = -1;
|
|
123
|
+ /** The cards that have been chosen to discard. */
|
90
|
124
|
private Deck discards = null;
|
91
|
125
|
|
|
126
|
+ /** Whether the current player can fold. */
|
92
|
127
|
private boolean canFold = false;
|
|
128
|
+ /** Whether the current player can raise. */
|
93
|
129
|
private boolean canRaise = true;
|
|
130
|
+ /** Whether or not we're in showdown. */
|
94
|
131
|
private boolean inShowdown = false;
|
95
|
132
|
|
|
133
|
+ /** The image buffer we render to. */
|
96
|
134
|
private BufferedImage buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
|
97
|
135
|
|
|
136
|
+ /** A cache of card images. */
|
98
|
137
|
private final Map<String, BufferedImage> cards = new HashMap<String, BufferedImage>();
|
|
138
|
+ /** A cache of card positions (for discarding). */
|
99
|
139
|
private final Map<Rectangle, Card> cardPositions = new HashMap<Rectangle, Card>();
|
100
|
140
|
|
|
141
|
+ /** The buttons we're using. */
|
101
|
142
|
private final Map<Button.TYPE, Button> buttons = new HashMap<Button.TYPE, Button>();
|
102
|
143
|
|
|
144
|
+ /** A semaphore used to control rendering access. */
|
103
|
145
|
private final Semaphore drawSem = new Semaphore(1);
|
104
|
146
|
|
105
|
147
|
/** The style of the card to use. */
|
|
@@ -335,6 +377,11 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
335
|
377
|
}
|
336
|
378
|
}
|
337
|
379
|
|
|
380
|
+ /**
|
|
381
|
+ * Paints the visible community cards.
|
|
382
|
+ *
|
|
383
|
+ * @param g The graphics object to render the buttons to.
|
|
384
|
+ */
|
338
|
385
|
private void paintCommunityCards(final Graphics g) {
|
339
|
386
|
int i = 0;
|
340
|
387
|
int xOffset = getWidth() < communityMinSize ? cardShortOffset : cardLargeOffset;
|
|
@@ -345,6 +392,13 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
345
|
392
|
}
|
346
|
393
|
}
|
347
|
394
|
|
|
395
|
+ /**
|
|
396
|
+ * Paints the dealer token at the specified position.
|
|
397
|
+ *
|
|
398
|
+ * @param g The graphics object to render the token to.
|
|
399
|
+ * @param x The x co-ordinate of the token
|
|
400
|
+ * @param y The y co-ordinate of the token
|
|
401
|
+ */
|
348
|
402
|
private void paintDealerToken(final Graphics g, final int x, final int y) {
|
349
|
403
|
g.setColor(Color.ORANGE);
|
350
|
404
|
g.fillOval(x, y, 25, 25);
|
|
@@ -352,6 +406,13 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
352
|
406
|
g.drawString("D", x + 9, y + 17);
|
353
|
407
|
}
|
354
|
408
|
|
|
409
|
+ /**
|
|
410
|
+ * Paints the winner token at the specified position.
|
|
411
|
+ *
|
|
412
|
+ * @param g The graphics object to render the token to.
|
|
413
|
+ * @param x The x co-ordinate of the token
|
|
414
|
+ * @param y The y co-ordinate of the token
|
|
415
|
+ */
|
355
|
416
|
private void paintWinnerToken(final Graphics g, final int x, final int y) {
|
356
|
417
|
g.setColor(Color.GREEN);
|
357
|
418
|
g.fillOval(x + 37, y - 3, 20, 20);
|
|
@@ -359,11 +420,25 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
359
|
420
|
g.drawString("W", x + 42, y + 12);
|
360
|
421
|
}
|
361
|
422
|
|
|
423
|
+ /**
|
|
424
|
+ * Paints the turn token at the specified position.
|
|
425
|
+ *
|
|
426
|
+ * @param g The graphics object to render the token to.
|
|
427
|
+ * @param x The x co-ordinate of the token
|
|
428
|
+ * @param y The y co-ordinate of the token
|
|
429
|
+ */
|
362
|
430
|
private void paintTurnToken(final Graphics g, final int x, final int y) {
|
363
|
431
|
g.setColor(Color.WHITE);
|
364
|
432
|
g.fillOval(x - 12, y - 10, 10, 10);
|
365
|
433
|
}
|
366
|
434
|
|
|
435
|
+ /**
|
|
436
|
+ * Paints the current message at the specified position.
|
|
437
|
+ *
|
|
438
|
+ * @param g The graphics object to render the message to.
|
|
439
|
+ * @param x The x co-ordinate of the message
|
|
440
|
+ * @param y The y co-ordinate of the message
|
|
441
|
+ */
|
367
|
442
|
private void paintMessage(final Graphics g, final int x, final int y) {
|
368
|
443
|
g.setColor(Color.YELLOW);
|
369
|
444
|
g.drawString(message, x, y);
|
|
@@ -592,6 +667,14 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
592
|
667
|
repaint();
|
593
|
668
|
}
|
594
|
669
|
|
|
670
|
+ /**
|
|
671
|
+ * Indicates that a human player controller is waiting for the player to
|
|
672
|
+ * discard some cards.
|
|
673
|
+ *
|
|
674
|
+ * @param player The player who has to do the discarding
|
|
675
|
+ * @param min The minimum number of cards to discard
|
|
676
|
+ * @param max The maximum number of cards to discard
|
|
677
|
+ */
|
595
|
678
|
public void setDiscardPlayer(final HumanPlayer player, final int min, final int max) {
|
596
|
679
|
this.discardPlayer = player;
|
597
|
680
|
discardMin = min;
|
|
@@ -633,6 +716,11 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
633
|
716
|
}
|
634
|
717
|
}
|
635
|
718
|
|
|
719
|
+ /**
|
|
720
|
+ * Handles the user clicking on a button.
|
|
721
|
+ *
|
|
722
|
+ * @param type The type of button that was clicked on
|
|
723
|
+ */
|
636
|
724
|
private void processMouseClick(final Button.TYPE type) {
|
637
|
725
|
boolean done = false;
|
638
|
726
|
|
|
@@ -711,28 +799,38 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
711
|
799
|
repaint();
|
712
|
800
|
}
|
713
|
801
|
|
|
802
|
+ /** {@inheritDoc} */
|
|
803
|
+ @Override
|
714
|
804
|
public void mousePressed(MouseEvent e) {
|
715
|
805
|
// Do nothing
|
716
|
806
|
}
|
717
|
807
|
|
|
808
|
+ /** {@inheritDoc} */
|
|
809
|
+ @Override
|
718
|
810
|
public void mouseReleased(MouseEvent e) {
|
719
|
811
|
// Do nothing
|
720
|
812
|
}
|
721
|
813
|
|
|
814
|
+ /** {@inheritDoc} */
|
|
815
|
+ @Override
|
722
|
816
|
public void mouseEntered(MouseEvent e) {
|
723
|
817
|
// Do nothing
|
724
|
818
|
}
|
725
|
819
|
|
|
820
|
+ /** {@inheritDoc} */
|
|
821
|
+ @Override
|
726
|
822
|
public void mouseExited(MouseEvent e) {
|
727
|
823
|
// Do nothing
|
728
|
824
|
}
|
729
|
825
|
|
730
|
826
|
/** {@inheritDoc} */
|
|
827
|
+ @Override
|
731
|
828
|
public void keyTyped(KeyEvent e) {
|
732
|
829
|
// Do nothing
|
733
|
830
|
}
|
734
|
831
|
|
735
|
832
|
/** {@inheritDoc} */
|
|
833
|
+ @Override
|
736
|
834
|
public void keyPressed(KeyEvent e) {
|
737
|
835
|
if (player != null) {
|
738
|
836
|
boolean done = false;
|
|
@@ -823,7 +921,12 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
823
|
921
|
}
|
824
|
922
|
}
|
825
|
923
|
|
826
|
|
- private void toggleDiscard(int card) {
|
|
924
|
+ /**
|
|
925
|
+ * Toggles the "discard" state of the specified card.
|
|
926
|
+ *
|
|
927
|
+ * @param card The index of the card to be toggled
|
|
928
|
+ */
|
|
929
|
+ private void toggleDiscard(final int card) {
|
827
|
930
|
final Deck playerCards = discardPlayer.getPlayer().getCards();
|
828
|
931
|
|
829
|
932
|
if (playerCards.size() >= card) {
|
|
@@ -842,10 +945,13 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
842
|
945
|
}
|
843
|
946
|
|
844
|
947
|
/** {@inheritDoc} */
|
|
948
|
+ @Override
|
845
|
949
|
public void keyReleased(KeyEvent e) {
|
846
|
950
|
// Do nothing
|
847
|
951
|
}
|
848
|
952
|
|
|
953
|
+ /** {@inheritDoc} */
|
|
954
|
+ @Override
|
849
|
955
|
public void discards(Player player, int number) {
|
850
|
956
|
messagePlayer = player;
|
851
|
957
|
message = "Discards " + number + " card" + (number == 1 ? "" : "s");
|
|
@@ -853,6 +959,9 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
853
|
959
|
doUpdate();
|
854
|
960
|
}
|
855
|
961
|
|
|
962
|
+ /**
|
|
963
|
+ * Flips all cards over.
|
|
964
|
+ */
|
856
|
965
|
private void flipAllCards() {
|
857
|
966
|
final List<Card> unflipped = new ArrayList<Card>();
|
858
|
967
|
|
|
@@ -870,6 +979,12 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
870
|
979
|
flipCard(false, unflipped.toArray(new Card[0]));
|
871
|
980
|
}
|
872
|
981
|
|
|
982
|
+ /**
|
|
983
|
+ * Flips the specified cards over.
|
|
984
|
+ *
|
|
985
|
+ * @param startsVisible Whether or not the card starts visible
|
|
986
|
+ * @param cards The cards to be flipped
|
|
987
|
+ */
|
873
|
988
|
private void flipCard(final boolean startsVisible, final Card ... cards) {
|
874
|
989
|
drawSem.acquireUninterruptibly();
|
875
|
990
|
boolean visible = startsVisible;
|
|
@@ -923,6 +1038,8 @@ public class GameWindow extends JFrame implements GameObserver, MouseListener, K
|
923
|
1038
|
drawSem.release();
|
924
|
1039
|
}
|
925
|
1040
|
|
|
1041
|
+ /** {@inheritDoc} */
|
|
1042
|
+ @Override
|
926
|
1043
|
public void cardDealt(final Player player, final Card card) {
|
927
|
1044
|
drawSem.acquireUninterruptibly();
|
928
|
1045
|
|