Greg Searle's captains log star date
m (Greg Searle's Captains Log Star Date moved to Greg Searle's captains log star date: lowercased name) |
Revision as of 05:38, 29 July 2008
Okay, due to the fact that this course seems to be about Refactoring and analysing code I thought that I should start off with a base scenario. So here is what I'm starting fresh with. I beleive all the work I have done in the past will just aid me with my design rather than as a complete waste. This base case was taken from a book Blair Neate found in the library called: The Object-Oriented Thought Process by Matt Weisfeld.
What I plan to do to this is get rid of useless code, such as the cards and the shuffled cards Vector classes inside the Deck class.
Okay I fixed up the Deck class, that was filled with some useless behavior. What sort of book teaching the thoughts behind OO uses an int to store the next card. Using the idea behind Do the simplest thing that could possibly work I got rid of all of the card creation methods and just put the creation of them in the constructor. Got rid of the use of vectors for storage of class and hid the design as Lists. Got rid of the shuffledList and am just using the cards, Once and only once. Replaced the getNextCard method with a popCard method to remove the card from the deck once it has been dealt.
The card class has been stripped. Why does a card need to have a name I will never know. Bought in an enum in the form of a Suit to represent the suits of the cards and got rid of all the getters and setters except for getValue. The constructor has been changed so that it takes a Suit and value instead of having to set it after creation.
What I want to do next is make it so that a player can split if he has two cards which values are the same. This requires the player to have multiple hands, and the getHand method must be changed. This strikes me as a reason for using TellDontAsk, I may forget about that right now and try it later. Also want it to accept Aces as 1 or 11 (Where should I do this and how?).
Okay this code doesn't fully work anymore. I've come across an annoying 'feature' when splitting. I really don't like the way splitting occurs. I'll give you a little introduction. Currently the game is for one player only. However that will change soon enough. The problem that I am having is when I split at the moment I am having a concurrent list modification error. I attribute this to some piss poor coding. Everything gets done in the dealer class at the moment. (well too much to my liking anyway. The startNewGame method is massive, and isn't just starting a new game, but is a new game now. I'm doing some dirty Card c = player.getHands.get(0); which we all sink to at some level of our assignments. What I propose to do is make the player decide which hand the dealer is dealing to. This way there will be no concurrent list modification, and it will be scalable for when I allow multiple people to play at the same time.
Okay its now starting to feel better. That's mainly because of the functionality more than the design. I got rid of the link between player and dealer, they really don't need to know about each other. I'm trying to ModelTheRealWorld so all the information is passed through TellDontAsk. To find out if the player wants another card the dealer tells the hand which tells the player which returns a Decision. Currently the Decision class is just an enum but currenly have a SwitchOnValue so i'll probably make that a new class later today. The functionality currently added is the ability to have more than one hand -> more than one player. One thing to note about the current design is that for every hand there is a different player, that needent be the case but i'll fix it later. Also need to fix the dirtyness of the ace, all hands storing two booleans just to track whether an ace is in the hand isn't nice. Need to implement a real blackjack, doubling, betting and then need to start thinking about the statistics generation, the automation of it all, bringing back the lovely shoe and shuffle card and then the whole make it clean part.
Here is the code which I am currently using for finding out what the player wants to do from the dealer class:
ListIterator<Hand> li = hands.listIterator(); while(li.hasNext()){ Hand h = li.next(); while(h.getValue()<22){ Decision d = h.askPlayer(hand.getValue()); if(d == Decision.STAND){ break; } else if (d == Decision.HIT){ dealCard(h); } else if (d == Decision.SPLIT) { li.add(h.splitHand()); } else if(d == Decision.DOUBLE){ //not yet } } }
As MartinFowler states in his refactoring book this uses information about the Decision, but not the Dealer. I should consider a refactor here using Polymorphism.
Okay refactor done:
The code now looks like:
ListIterator<Hand> li = hands.listIterator(); while(li.hasNext()){ Hand h = li.next(); while(!h.isFinished()){ Decision d = h.askPlayer(hand.getValue()); d.useDecision(li,this,h); } }
By doing this it also fixed the dirty line for the loop iteration. But now I'm not liking th hand class. There are a fair few booleans keeping track of states. Maybe time to consider the State pattern.
Okay had a nice talk to Wal. Wal pointed out to me that the design above is actually the Command pattern, but he reckons that it could be overkill. It states the intent is to "Encapsulate a request as an object, thereby leting oyu parameterize clients with different requests" This is exactly what I am doing. It then goes on to add "...different requests, queue or log requests and support undoable operations." This is what I am allowing, but have no need to. It states that the applicability of the Command pattern is mainly time issues: logging, undo, callback. This is not what I need for this solution so what I have done is allow a little too much.
This means two possible solutions. I can use a real Tell dont ask approach, unlike the half approach used above where I still return an object (instead of getting it I tell it to give it). The real tell don't ask approach would, instead of returning the Decision, tell the hand to do whatever which then tells the dealer. The other approach would be to pass the dealer to the player and allow the player to tell the dealer directly. Personally I have no problem with the Player telling the Dealer directly. So that's what i'll do.
Wal went on to point out that I have a lot of interaction between Player and Dealer. Maybe I should have the Dealer have a list of Players. This idea does not Model the real world. It also puts a restriction against the way BlackJack is actually played. With the Dealer having knowledge of Players then he would iterate through each player, but because a player can have multiple hands and each hand doesn't have to be consecutive with respect to the game. To give an example: Player 1 is playing a game of BlackJack with Player2. Player1 is playing the first hand the dealer deals to. Player2 is playing the second. Player1 decides that he wants to play another hand so he plays the 3rd hand. He is now playing both the first and the third hands, this cannot be accomplished if the Dealer has knowledge of the players rather than the hands.
Also fixed the Ace scenario, added a containsAce bool in the Hand class. The getValue of the hand now looks like:
public int getValue() { int total = 0; for(Card c:hand){ total += c.getValue(); if(c.getValue() == 1){ containsAce = true; } } if(containsAce && total <= (HIGHEST_WINNING_SCORE - SOFT_ACE_INCREMENT)){ total += 10; } return total; }
The HIGHEST_WINNING_SCORE & SOFT_ACE_INCREMENT are Wal's idea to allow the game rules to be changed more easily that hard wiring the value of 21 and 10 respectivly. Named constants - can't disagree with that.
Okay new problem. The Dealer is struggling to clear the table. There is a missing class and I'm going to have to bring in the lovely Table class that I bought in chucked out and then bought in again in the previous design. The reason for this is that all the communication between Dealer and Player is going through hand. At the end of a game the Dealer wants to clear the table and ask everyone whom is playing if they want to play again. If they ask the hand of someone they'll be asking a player twice. However if I make a set of who to ask then people playing two hands will only be able to play one hand in the next game. I propose the Table class as a link.
A table can have many boxes, a box can have one table.
A hand has one box, a box has one hand, but may have more.
A box can have a bet
A box has one player with my implementation, I'm looking at stats, I don't care about the fact that the casino allows more than one player per box.
A table can have one Dealer, the Dealer can have one table.
This way to clear the table all the Dealer has to do is go through each "Box" and ask the player behind it if they want to keep playing. A Box is a hand where people bet on, if they split the new hand stays in the same box.
This also gives me the opportunity to model the side games such as Perfect Pairs and Sevens. Although these odds are much more in favour of the casino and can be worked out using a simple mathmatical model so this will be an "If I can be bothered option".
Okay, finally. I now have this class diagram to show. I have taken out the Command pattern. I have also added two more classes: Table and Box. I will have to provide a diagram at some stage but a Box is basically where a player plays his hand. If a player splits their hand then they create a new hand in their box. This was the main separation needed for the Box class. The table class is now the Controller as such. Blair Neate and Alex Wong like to refer to this as the God blass. But its not.
What I find happening with Tell, Don't Ask is everything has become bi-directional. This is a complete contradiction to Avoid owner references.
I have also added the PlayingStrategy class. This is going to be changed with my next iteration for one reason:
I hate the inheritance of Participant. Its going. The more functionallity I add the less Dealer and Player relate. The reason I created the inheritance was for the Hand class. What I think I'll do is separate the hand into a DealersHand and a PlayersHand. This I believe will get rid of all of the awful things that is happening because of this stupid inheritance.