CardList
This class will be a linked list that
stores Cards. For notes on linked lists, read 15.3-15.5 and you
can look at
this incomplete code for
tips on how to do this. You should include the following
methods.
public
void add(Card a) // adds a card to the end of a CardList
public void add(int pos, Card a)
// adds a card to a position in the
CardList
public Card remove() // removes
the last item of the linked list, and
returns the item being deleted
public Card remove(int pos) //
removes a card from the middle of the
CardList and returns the item
public int size() // returns
the number of elements in the CardList
public Card get(int pos) //
returns the Card stored at node pos
public void set(int pos, Card a)
// sets the node at position pos to
Card a
public void clear() // resets
the CardList to empty
Note: if you follow the example of the code from here, you will find a
problem... namely it is impossible to remove the first item. This
is a big problem for any shuffling algorithm as it means you will get
an error if you ever try to pick the 1st card to place in the new
deck. There are a few ways to fix this, though I will talk about
the easiest hacks to fix this. The ideal way is that the linked
list ignores the first node altogether, and starts counting with the
2nd node (making that node 0), but that requires much more irritating
code. There are easier solutions. One solution is to hack
remove so when a user asks to remove node 0, it will act like an array
and copy the data from the next node into this node, and then
recursively do the same for all nodes until the 2nd to last node, where
it copies the data from the last node, and then removes the last node,
in the end it needs to return the value of the first node it
overrides. This solution will work fine for this project.
Alternately you can make sure the shuffling code NEVER tries to pick
the first card from the ordered deck, and instead runs for the other 51
cards only. (add 1 to the value of nextInt to skip the 1st
element). At the end, insert the value of card 0 into a the
middle of the shuffled deck. Also make sure that remove at
returns the current data value (but does not bother to actually remove)
the first card when the index is 0. I will try to go over this in
detail in class.
Card
This immutable class is provided for
you
below. This class stores a single card, its rank and its
suit. It can tell you if two cards are the same.
Screen
This is a GUI class used by the client
that is defined below. It will not run on its own. It
requires you to create an instance of the class in the Client class in
order to display the window. Of importance here are the 3 JList
objects and the JComboBox object which you will have to update, and the
single JButton you need to create an ActionListener for in order to ask
for a card. It might be wise to create a class variable of type
Screen in the Client class and assign the instance of Screen you create
to display the screen to that variable so that Client can access the
JLists, the JComboBox and assign an ActionListener to the
JButton. In theory you should not need to modify this class if
you do not intend to implement any extensions beyond the basic
assignment.
Server
You will need to have these class
variables (and quite likely more than this):
private static CardList deck; //
the
deck of cards
private static CardList player1Sets; //
the list of all complete ranks for player 1
private static CardList player2Sets; //
the list of all complete ranks for player 2
private static boolean isPlayer1Turn; //
basically a boolean to figure out if player 1 or player 2 should play
private static boolean gameplaying; //
a boolean to tell you if the game is actually going or not (it should
start off as false, and only turn to
true when 2 clients have connected and cards have been dealt)
private static int players = 0;
//
counts the number of players in the system
private static Random r = new
Random(); //
a single random object to handle all random number generation
private static PrintWriter
player1Writer; //
a reference to the printWriter that sends messages to Player 1
private static PrintWriter
player2Writer; //
a reference to the printWriter that sends messages to Player 2
You will also need a nested class inside of this class to handle
creating threads for the clients, the nested class needs to look
something like this:
public class clientThread implements
Runnable {
private int player =
0;
private BufferedReader fromClient;
private PrintWriter toClient;
public clientThread(int p, BufferedReader from, PrintWriter to) {
fromClient = from;
toClient = to;
player = p;
}
// you need to write this method and anything else!
public void run () {
/* a possible strategy for this is to
have an infinite while loop that constantly reads data from the client
via readLine and then runs code appropriate for each of the 5 messages
depending on what is read in. This is where you need to do some
work figuring out how to define the messages, and then what to do for
the five messages in the server */
}
}
Remember, when you create the threads you need to pass the
player # they are, the BufferedReader and the PrintWriter for the given
socket. (that way they know what thread they are, and how to
communicate)
This is the main class for the
Server. There does not need to be any GUI.
The server is
responsible for
- creating the CardList of
all 52 cards
- shuffling
the cards in the deck
- creating a ServerSocket object (you decide on the port
number),
- waiting for the two clients to connect
- creating a thread for
each client
- deal the cards to each client
(and thereby removing it from the shuffled deck)
- randomly deciding
which client is to go first
- signaling the clients when it is their turn (by sending the
appropriate message)
- passing requests for cards between the clients, and if neccesary
cards from the deck to the clients
The client will need to be able to ask for a
rank of the other client through the server. The server will need
to pass the message to the other client, and the client is responsible
for figuring out if they have those cards, and if so, they must send a
message to the first client of which cards they have, and remove those
cards from the 2nd client's hand. The server passed that message
to the client that asked. If the 2nd client does not have any
cards, it sends a message to the server that it has none, and then the
server passes the next card on its deck to the 1st client (Go
Fish!). Every time a client has a new complete set of one of the
ranks, it informs the server, and the server updates its CardList of
ranks that that client has, and then sends a message to the other
client so it can update the list of the cards that the other player has
complete.
Some tips: in order to shuffle the deck, first create a CardList
with all 52 cards in order, then create a new empty CardList.
Randomly remove a card from the first deck and place it onto the new
CardList. Do this 52 times. Each time you pick a card make
sure you pick a random card based on the CURRENT SIZE of the first
deck. (every time you remove one the size decreases by 1)
In addition you might want to have this code in your public static void
main(String[] args) to make the game easier to play:
System.out.println(InetAddress.getLocalHost().getHostAddress());
This will print out the ip address of the server (hopefully)
when you start up the game.
The actual methods for the Server class can be defined in any way, but
realistically I'd suggest have one for creating the CardList (defining
all 52 cards), one to shuffle the same CardList, and then a public
static void main(String[] args) that does the following:
- display the ip address (see the note just above)
- create the cardlist of 52 cards (or call the method that does
this)
- shuffle the cardlist
- create a ServerSocket object
- wait for a connection via accept. Once you have it, create
a PrintWriter and BufferedReader from it, and then create a thread for
it. Assign the class variable player1Writer to the printWriter
created here. (when you need to send a message to player 1 from a
thread, you can use this)
- wait for another connection via accept. Once you have it,
create a PrintWriter and BufferedReader from it, and then create a
thread for it. Assign the class variable player2Writer to the
printWriter created
here. (when you need to send a message to player 2 from a thread,
you
can use this)
- deal the correct number of cards to both players by sending
messages to player 1 & player 2 with the "send a card" message.
- then have an infinite loop to make sure that the program doesn't
exit
Client
This class should probably have at
least the following class variables (and probably more)
private static Screen myScreen; //
a
reference to the Screen object created
private static CardList myHand; //
a
CardList of your hand
private static CardList mySets; //
your completed sets
private static CardList theirSets; //
their completed sets
private static boolean ismyturn =
false; //
when this is true, you can accept clicks on the button asking for a suit
private static PrintWriter toServer; //
to send messages to the server (created after the socket object is
created)
private static BufferedReader
fromServer; //
to recieve messages from the server (created after the socket object is
created)
You will also need at least two nested
classes, a class to be an
ActionListener for the JButton, and a Runnable class to handle the
network thread. The network thread class will look very similiar
to the one defined for the server, except that you do not care what
player # you are here and since this is a nested class, you can use the
toServer and fromServer references from the class you are nested within
so you do not need to bother with the variables inside of the thread,
nor do you have to bother with a non-standard constructor. (so
those references should be excised here). The actionListener will
be like any normal one, except that you will need to say
myScreen.askForButton.addActionListener(new
{thenameofyouractionlistenerclasshere}()); to actually assign it.
Also make sure to check if it is your turn or not in the
actionPerformed BEFORE you go around and request the card.
Basically all the network thread will have to do is wait for messages
from the server, and react to them, usually by updating the display,
but also to signal that is your turn and such.
Before you even define the connection to the server or create the
Screen object, you need to know how to reach the server, so you will
need to ask the user via a JOptionPane for the name of the
server. Use that in creating your Socket object to help you
connect.