Fires of Heaven Guild Message Board  

Go Back   Fires of Heaven Guild Message Board > General forums > Development
User Name
Password
Or, use your gamerDNA username: (more...)
ForumSpy Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply
 
LinkBack Thread Tools Search this Thread Rate Thread Display Modes
Old 12-23-2006, 07:59 PM   #1 (permalink)
Zippygoose
Math Enthusiast/Badass MC
 
Zippygoose's Avatar
 
Join Date: Jun 2002
Location: Seattle
Posts: 650
+0 Internets
Send a message via AIM to Zippygoose
Programming Problem #1

So I'm sitting in SEA-TAC waiting for my flight home for Christmas and found a free internet connection which means I finally have time to do this.

Note: I have no idea if this will be worthwhile, but if this helps just one person learn something about programming, I'll consider it a success. I'm going to post the problem now and then solve it for myself on my flight.

Problem #1:

Create a class that functions as a standard 52 card deck of cards.

Methods:
Constructor: Creates the deck

Shuffle: Shuffles the deck (this is where beginners can stretch themselves and those more advanced can get as ridiculous as they'd like).

Cut: (Edited based on input from Daerath) Cut the deck - Cuts the deck in a random place
+1 Overload - Passes in index of deck cut to occur.

Deal: Passes in number parameter (or just parameter for non-strongly typed languages) and deals that many cards off of the top of the deck.

That's it. I figured I'd start with something simple-ish. If you've got some time, post your solutions.

Last edited by Zippygoose : 01-02-2007 at 06:01 PM.
Zippygoose is offline   Reply With Quote
Old 01-02-2007, 03:49 PM   #2 (permalink)
Rodyland
Registered User
 
Join Date: Oct 2005
Posts: 227
+0 Internets
You planning on posting your solution? Or is this really an assignment from University and you're hoping to cut-and-paste someone else's solution?
Rodyland is offline   Reply With Quote
Old 01-02-2007, 04:19 PM   #3 (permalink)
Daerath
Registered User
 
Join Date: Mar 2002
Posts: 813
-1 Internets
Quote:
Originally Posted by Zippygoose View Post
Cut: Cut the deck - Passes in index of deck cut to occur.
IMO, this isn't the best design. Whenever someone cuts a deck they generally do so at random. Add a method that has no parameters that will randomly cut the deck and then have it call the overloaded method that takes an index. This way you don't have to specify the index.
__________________
Lukas: it is, he used his own logarithms that he wrote for the shadow system in doom 3 which was simply not needed.
Eomer: logarithms huh? Fuck you are an idiot.
Lukas: algorithms, sorry mr english teacher
Kan: lol that goes beyond misspelling thats just plain retardism Lukas
Daerath is offline   Reply With Quote
Old 01-02-2007, 05:53 PM   #4 (permalink)
Zippygoose
Math Enthusiast/Badass MC
 
Zippygoose's Avatar
 
Join Date: Jun 2002
Location: Seattle
Posts: 650
+0 Internets
Send a message via AIM to Zippygoose
Good call daerath, my shuffling method already does what you've described.

Yes, I have a solution - it's on my laptop. I finished it on the plane home long after the realization that I should try to not program during my vacation and hang out with my family instead

I'll post it when I get home from work.
Zippygoose is offline   Reply With Quote
Old 01-02-2007, 06:35 PM   #5 (permalink)
Zuuljin
So there's this plane on a treadmill...
 
Zuuljin's Avatar
 
Join Date: Jan 2005
Location: Southern California
Posts: 2,952
+2 Internets
Send a message via AIM to Zuuljin
Quote:
Originally Posted by Daerath View Post
IMO, this isn't the best design. Whenever someone cuts a deck they generally do so at random. Add a method that has no parameters that will randomly cut the deck and then have it call the overloaded method that takes an index. This way you don't have to specify the index.
I would disagree. Assuming this is a game for multiple people to play, allowing them to choose a spot to cut the deck makes it more realistic. Not everyone does it randomly. And adding a method who's sole purpose is to call another method is IMO a waste of time, energy and space.
Zuuljin is offline   Reply With Quote
Old 01-02-2007, 07:32 PM   #6 (permalink)
Rodyland
Registered User
 
Join Date: Oct 2005
Posts: 227
+0 Internets
Quote:
Originally Posted by Zuuljin View Post
And adding a method who's sole purpose is to call another method is IMO a waste of time, energy and space.
I must disagree entirely. If you follow some of the rules of of good class design you will end up with many methods whose sole purpose is to call another method.

A no-parameter version of a cut function that generates a random number between 1 and 51 and passes that to a cut(int) function sounds sensible, although not required by the original spec.
Rodyland is offline   Reply With Quote
Old 01-02-2007, 07:44 PM   #7 (permalink)
kogarne
Registered Lurker
 
kogarne's Avatar
 
Join Date: Dec 2004
Posts: 40
+0 Internets
Send a message via ICQ to kogarne Send a message via AIM to kogarne Send a message via MSN to kogarne Send a message via Yahoo to kogarne
nt

Last edited by kogarne : 01-03-2007 at 11:13 AM.
kogarne is offline   Reply With Quote
Old 01-02-2007, 08:42 PM   #8 (permalink)
Rodyland
Registered User
 
Join Date: Oct 2005
Posts: 227
+0 Internets
Quote:
Originally Posted by kogarne View Post
Cutting should always be at random, as so... so should be all ga... nm that.... to each their own...., and to all a good knig...... ,..... post?...?
First, lol.

Second, cutting IRL isn't random. It's barely semi-random. I know when I cut I make a conscious decision to _try_ to cut at a specific location. I've been known to cut at 1 and 51 on purpose. Cutting at 27 is a bit more difficult to manage, but sometimes I try.

If you were going to be totally anal about it you'd figure out the randomness of the actual cut compared to the intended cut (0 at 1 and 51, maybe +/- 10 at 26, with a slope between) and add a random factor to the intended cut. But given that the deck is sorted pseudo-randomly (or should be) when it's shuffled, unlike a human shuffle, the actual effect of the cut should be negligible if any. You could make cut(int) a noop and nobody'd know unless they read the code.

EDIT: Actually, I've also done a zero-cut (ie accepted the deck as shuffled).

Last edited by Rodyland : 01-02-2007 at 08:48 PM.
Rodyland is offline   Reply With Quote
Old 01-02-2007, 10:49 PM   #9 (permalink)
Zippygoose
Math Enthusiast/Badass MC
 
Zippygoose's Avatar
 
Join Date: Jun 2002
Location: Seattle
Posts: 650
+0 Internets
Send a message via AIM to Zippygoose
You could also pass in "top" "middle" "bottom" which would then randomly cut the deck within the passed criteria.

i.e., passing "top" would cut the deck randomly between 0 and 20, middle between 21 and 32, etc. etc.

I liked the idea of an overloaded method simply because it introduces the idea to people who might not be familiar with it.

Edit: Posting solution soon, had to tweak cut method to account for overloads.

Last edited by Zippygoose : 01-02-2007 at 11:20 PM.
Zippygoose is offline   Reply With Quote
Old 01-03-2007, 12:21 AM   #10 (permalink)
Daerath
Registered User
 
Join Date: Mar 2002
Posts: 813
-1 Internets
Quote:
Originally Posted by Zuuljin View Post
I would disagree. Assuming this is a game for multiple people to play, allowing them to choose a spot to cut the deck makes it more realistic. Not everyone does it randomly. And adding a method who's sole purpose is to call another method is IMO a waste of time, energy and space.
You'd be surprised how useful it is to have one method call another. One common situation where it comes into play is when you are extending a class and you want to minimize the impact on existing code.

Lets say you have a method known as GetAddresses. It takes no parameters and returns a typed dataset of all Addresses in a database.


public Addresses GetAddresses()
{
// Source code to get Addresses from the database.
}


Some time later during development you discover that in some cases it is useful to only get the active or inactive addresses instead of just getting all of them. And yes, in many systems, you can deactivate an address. Customers can be very particular about not losing their data.

The easiest way to accomplish this with the least possible risk to your existing code is to create an overloaded method of GetAddresses that takes an input parameter. In this case I'll use an enum that allows you to specify "All", "Active", or "Inactive". Pull the code out from the original GetAddresses method and place it into your new parameterized method. Modify it to recognize the input parameter. Then in the body of the original method, have it call your new parameterized method with the appropriate parameter (ex. an enum value representing All).


enum RecordState { All = 1, Active, Inactive };

public Addresses GetAddresses(RecordState recState)
{
// Source code to get Addresses from the database.
}

public Addresses GetAddresses()
{
return GetAddresses(RecordState.All);
}


The benefit here is that you haven't duplicated any source code and you haven't changed any existing source code that uses GetAddresses(). You will still have to verify that the modified data access code works throughout the system, but you would have needed to do that anyway. Unless, of course, you chose to duplicate the data access code for your new method, which is inadvisable in almost every situation.

If later you realized that you also needed to restrict the addresses to a particular type (in some cases) you would follow the same set of steps.


enum RecordState { All = 1, Active, Inactive };
enum AddressType { All = 1, Home, Business };

public Addresses GetAddresses(RecordState recState, AddressType aType)
{
// Source code to get Addresses from the database.
}

public Addresses GetAddresses(RecordState recState)
{
return GetAddresses(recState, AddressType.All);
}

public Addresses GetAddresses()
{
return GetAddresses(RecordState.All, AddressType.All);
}


Again, I'm not changing the behavior of the existing methods, but I am adding functionality to the class.

Additionally, many overloaded methods in Java, .NET, many C++ libraries, etc. are implemented in this manner. It can be incredibly useful to create methods that call overloaded versions of themselves. This lets you set default values while still using the same source code.

It also lets you release a new version of a public component used by other developers without changing the signatures or behaviors of the existing methods.
__________________
Lukas: it is, he used his own logarithms that he wrote for the shadow system in doom 3 which was simply not needed.
Eomer: logarithms huh? Fuck you are an idiot.
Lukas: algorithms, sorry mr english teacher
Kan: lol that goes beyond misspelling thats just plain retardism Lukas
Daerath is offline   Reply With Quote
Old 01-03-2007, 01:39 AM   #11 (permalink)
Rodyland
Registered User
 
Join Date: Oct 2005
Posts: 227
+0 Internets
Quote:
Originally Posted by Daerath View Post
Lets say you have a method known as GetAddresses. It takes no parameters and returns a typed dataset of all Addresses in a database.
snip...


I like your example, and have done similar things myself many times. Well explained.
Rodyland is offline   Reply With Quote
Old 01-07-2007, 10:41 PM   #12 (permalink)
Zippygoose
Math Enthusiast/Badass MC
 
Zippygoose's Avatar
 
Join Date: Jun 2002
Location: Seattle
Posts: 650
+0 Internets
Send a message via AIM to Zippygoose
Apologies for the delay, work was crazy this week.

One thing to note about my solution: My shuffle and cut methods are quite literal. I liked the idea of having a shuffle method that acted like a physical shuffle, meaning the cards become more random as the number of shuffles increase, and vice versa. So before you go blasting me for an inefficient shuffling method, I realize there are much faster computational shuffles

I also opted for an enum of cut types to pass into my cut method rather than overloading the method.

Class is in C#

Code:
using System; using System.Collections.Generic; using System.Text; using System.Data; using System.Security.Cryptography; namespace Cards { public class Deck { private string[] arrSuit = { "Hearts", "Clubs", "Diamonds", "Spades" }; private string[] arrName = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King" }; private Stack sDeck = new Stack(); public Deck() { //Reversing the loop would have made this easier, that way I could just have //written tmpCard = arrName, then tmpCard += " of " + iCurrentSuit. This would //have put the cards on the stack in number order. I wanted to get the cards by //suit though, which is how a new deck of cards is ordered (I think) string tmpCard = ""; string tmpSuit = ""; for (int iCurrentSuit = 0; iCurrentSuit < arrSuit.Length; iCurrentSuit++) { tmpSuit = ""; tmpSuit = arrSuit[iCurrentSuit]; for (int iCurrentName = 0; iCurrentName < arrName.Length; iCurrentName++) { tmpCard = arrName[iCurrentName].ToString() + " of " + tmpSuit; //Push this card on the stack sDeck.Push(tmpCard); } } } //Returns the deck as an array //I'm not pushing or popping here because I just want to see the cards //This was for testing only, it populates a listbox in my form (not included) public string[] View() { return sDeck.ToArray(); } //Shuffle the deck literally. This method simulates a standard shuffle: //Cut the cards somewhere around the middle of the deck, //Take the two halves and shuffle them into each other creating a new stack of cards //This is NOT the most efficient computational shuffle by any means, I just wanted //to simulate a real world shuffle, i.e. the more times you shuffle the deck the more //random the cards become. public void LiteralShuffle() { //Turn the stack into a queue. We want to use queues because //a standard shuffle shuffles the bottom cards first and the top cards last string[] arrTmp = sDeck.ToArray(); Queue qDeck = new Queue(); for (int x = arrTmp.Length - 1; x >= 0; x--) { qDeck.Enqueue(arrTmp[x].ToString()); } //Seed Rand Random oRand = new Random(DateTime.Now.Millisecond); //Index of the deck where it is split (added randomness since it isn't constant IRL) int iIndex = oRand.Next(20, 30); //now that we have a queue, cut the deck into 2 queues Queue qHalf = new Queue(); int iNumCount = qDeck.Count - iIndex; for (int j = 0; j < iNumCount; j++) { qHalf.Enqueue(qDeck.Dequeue()); } //Making a "third stack" that will be created from shuffling //the original 2 queues Stack sFinal = new Stack(); int iOddEven = 0; bool bCardsRemain = true; while (bCardsRemain) { //Generating a 0 or a 1 iOddEven = oRand.Next(2); //if 0, put the bottom card on the "left" queue on top of the //shuffled stack if (iOddEven == 0 && qDeck.Count > 0) { sFinal.Push(qDeck.Dequeue()); } //if it isn't 0, put the bottom card in the "right" queue //on top of the stack else if (qHalf.Count > 0) { sFinal.Push(qHalf.Dequeue()); } else if (qDeck.Count == 0 && qHalf.Count == 0) { bCardsRemain = false; } } sDeck = sFinal; } //Type of cut: Totally random, top 20% of deck, middle 20% of deck, bottom 20% of deck public enum CutTypes { Random, Top, Middle, Bottom } public void Cut(CutTypes cType) { //Seed Rand Gen Random oRand = new Random(DateTime.Now.Millisecond); int iIndex = 0; //determine 20% of the deck for cutting purposes //using an int so the decimal is just rounded off int iCutRange = (int)(sDeck.Count * .2); //Determine the user's cutting preference, and generate an appropriate index switch(cType) { case CutTypes.Random: iIndex = oRand.Next(sDeck.Count + 1); break; case CutTypes.Top: iIndex = oRand.Next(0, iCutRange + 1); break; case CutTypes.Middle: iIndex = oRand.Next((sDeck.Count/2) - (iCutRange/2), (sDeck.Count/2) + (iCutRange/2) + 1); break; case CutTypes.Bottom: iIndex = oRand.Next(sDeck.Count - iCutRange, sDeck.Count + 1); break; } string[] arrDeck = sDeck.ToArray(); //Turn the array into a queue Queue qDeck = new Queue(); for (int i = arrDeck.Length - 1; i >= 0; i--) { qDeck.Enqueue(arrDeck[i].ToString()); } //Determine how many cards to move from the bottom of //the deck to the top (this is a cut) int NumCards = (arrDeck.Length - 1) - iIndex; for (int j = 0; j < NumCards; j++) { qDeck.Enqueue(qDeck.Dequeue()); } Stack sFinal = new Stack(); //assign qDeck count to a variable since the count will change in the loop int qCounter = qDeck.Count; for (int y = 0; y < qCounter; y++) { //create the new stack of cards sFinal.Push(qDeck.Dequeue()); } sDeck = sFinal; } public Stack Deal(int iNumCards) { //store the dealt cards to return Stack sDealtCards = new Stack(); for (int i = 0; i < iNumCards; i++) { sDealtCards.Push(sDeck.Pop()); } return sDealtCards; } } }

Last edited by Zippygoose : 01-07-2007 at 10:45 PM.
Zippygoose is offline   Reply With Quote
Old 01-08-2007, 11:14 PM   #13 (permalink)
Zuuljin
So there's this plane on a treadmill...
 
Zuuljin's Avatar
 
Join Date: Jan 2005
Location: Southern California
Posts: 2,952
+2 Internets
Send a message via AIM to Zuuljin
thats an interesting way to shuffle.
Zuuljin is offline   Reply With Quote
Old 01-10-2007, 02:03 PM   #14 (permalink)
simeon
Banned
 
Join Date: Jan 2005
Location: O_o
Posts: 704
+2 Internets
removed
simeon is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is On
Trackbacks are On
Pingbacks are On
Refbacks are On
uberguilds network



All times are GMT -7. The time now is 01:04 AM.


Powered by vBulletin® Version 3.6.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.0.0 RC6