I'm developing a poker app and currently I want to store all the card combinations names I'm planning to use list and do something like this :
private static List<string> combinationNames = new List<string>
{
" High Card ",
" Pair ",
" Two Pair ",
" Three of a Kind ",
" Straight ",
" Flush ",
" Full House ",
" Four of a Kind ",
" Straight Flush ",
" Royal Flush ! "
};
for (int j = 0; j < combinationNames.Count; j++)
{
if (current == j)
{
MessageBox.Show("You Have : ", combinationNames[j]);
}
}
So is there a better way of storing those names and later access them like I did ?
There's not much to go on in your question to understand what's specifically wrong with the code you have. That said, at the very least I would expect the following to be an improvement:
private readonly static string[] combinationNames =
{
" High Card ",
" Pair ",
" Two Pair ",
" Three of a Kind ",
" Straight ",
" Flush ",
" Full House ",
" Four of a Kind ",
" Straight Flush ",
" Royal Flush ! "
};
if (current >= 0 && current < combinationNames.Length)
{
MessageBox.Show("You Have : ", combinationNames[current]);
}
I.e.:
Since the list won't change, it can be an array instead of a list
Since the list object won't change, the variable can be readonly
All the code you did does with j is compare it to current; there's no need to enumerate every possible value for jā¦just make sure current is within the valid range and then use its value directly.
Note on that last point it's not really clear where you get current from, but likely it should already be guaranteed to be valid before you get as far as displaying the text, so you shouldn't even really need the range check. I just put that there to ensure the new version of code above is reasonably consistent with the behavior of the code you showed (what little was there).
If you need more specific advice than the above, please explain more precisely what you think would be "better" and in what way the code you have now is not sufficiently addressing your needs. I.e. what does the code do now and how is that different from what you want it to do?
Related
I'm running a very simple function that reads lines from a text file in batches. Each line contains an sql query so the function grabs a specified number of queries, executes them against the SQL database, then grabs the next batch of queries until the entire file is read. The problem is that over time with very large files the process starts to slow considerably. I'm guessing there is a memory leak somewhere in the function but can't determine where it may be. There is nothing else going on while this function is running. My programming skills are crude at best so please go easy on me. :)
for (int x = 0; x<= totalBatchesInt; x++)
{
var lines = System.IO.File.ReadLines(file).Skip(skipCount).Take(batchSize).ToArray();
string test = string.Join("\n", lines);
SqlCommand cmd = new SqlCommand(test.ToString());
try
{
var rowsEffected = qm.ExecuteNonQuery(CommandType.Text, cmd.CommandText, 6000, true);
totalRowsEffected = totalRowsEffected + rowsEffected;
globalRecordCounter = globalRecordCounter + rowsEffected;
fileRecordCounter = fileRecordCounter + rowsEffected;
skipCount = skipCount + batchSize;
TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Starting, "Rows
progress for " + folderName + "_" + fileName + " : " + fileRecordCounter.ToString() + "
of " + linesCount + " records");
}
catch (Exception esql)
{
TraceSource.TraceEvent(TraceEventType.Information, (int)ProcessEvents.Cancelling, "Error
processing file " + folderName + "_" + fileName + " : " + esql.Message.ToString() + ".
Aborting file read");
}
}
There are many things wrong with your code:
You never dispose your command. That's a native handle to an ODBC driver, waiting for the garbage collector to dispose it is very bad practice.
You shouldn't be sending those commands individually anyway. Either send them all at once in one command, or use transactions to group them together.
This one is the reason why it's getting slower over time: File.ReadLines(file).Skip(skipCount).Take(batchSize) will read the same file over and over and ignore a growing amount of lines every attempt, and so growing slower and slower as the number of lines ignored (but processed) gets larger and larger.
To fix #3, simply create the enumerator once and iterate it in batches. In pure C#, you can do something like:
using var enumerator = File.ReadLines(file).GetEnumerator();
for (int x = 0; x<= totalBatchesInt; x++)
{
var lines = new List<string>();
while(enumerator.MoveNext() && lines.Count < batchSize)
list.Add(enumerator.Current);
string test = string.Join("\n", lines);
// your code...
}
Or if you're using Morelinq (which I recommend), something like this:
foreach(var lines in File.ReadLines(file).Batch(batchSize))
{
// your code...
}
Here's the code that I have:
if (spc > 1)
{
if (shpc == 0)
return "You have " + spc.ToString() + " visible cards in your card deck. ";
if (shpc == 1)
return "You have " + vc.ToString() + " visible and 1 hidden card in your deck. ";
return "You have " + vc.ToString() + " visible and " + shpc.ToString() + " hidden cards in your deck. ";
}
return null;
Does anyone know of a way I can code this with a switch or another way I could tidy the code?
This is an opportunity to step back and refactor. What's the problem? Pluralization is the problem, so start with that.
private static string[] words = {"no", "one", "two", "three" };
public static string Pluralize(this string t, int q)
{
string s = q == 1 ? "" : "s";
string n = q < words.Length ? words[q] : q.ToString();
return n + " " + t + s;
}
Can you see how you can use this to make your code look more like its meaning?
I don't think it would make it tidier; switch statements are pretty ugly. But if you really want to, you could do something like this:
string Output = null;
switch(shpc)
{
case 0: Output = $"You have {spc} visible cards in your card deck."; break;
case 1: Output = $"You have {vc} visible and 1 hidden card in your deck."; break;
default: Output = $"You have {vc} visible and {shpc} hidden cards in your deck."; break;
}
return Output;
EDIT.
As suggested by Franck in the comments, case 1 could be omitted in favor of a smarter default case:
$"You have {vc} visible and {shpc} hidden card{(shpc > 1? "s":"")} in your deck."
You could also omit the Output variable and return from the switch directly. None of this things would make it clearer IMO, so I wouldn't bother.
Why polluting some easy to read code by some fancy syntax? But if you really want, you may use a chained ternary operator.
if (spc > 1)
{
return
shcp == 0 ? "You have " + spc.ToString() + " visible cards in your card deck. " :
shpc == 1 ? "You have " + vc.ToString() + " visible and 1 hidden card in your deck. " :
"You have " + vc.ToString() + " visible and " + shpc.ToString() + " hidden cards in your deck. ";
}
return null;
You can further delete all those ToString-calls, as they are implictely added anyway when concatenating strings and objects.
Assuming that spc and vc are the same thing (you forgot to clean the code up for us) this is the holy grail that you asked for, which I however don't particularly like. Full localizable sentences are preferred in my world.
if (vc > 0)
return $"You have {vc} visible {shpc > 0 ? $"and {shpc} hidden " : ""}card{vc > 1 && shpc == 0 || shpc > 1 ? "s" : ""} in your deck. ";
How about:
if(shpc < 2)
return null;
if (vc == 0 && hc == 0)
return "You have no cards in your deck"
if (vc == 0)
return $"You have {hc} hidden card{S(hc)} in your deck";
if (hc == 0)
return $"You have {vc} visible card{S(vc)} in your deck";
return $"You have {vc} visible and {hc} hidden card{S(hc}} in your deck";
//a cheapo pluralize method.
private string S(int i){
return i == 1 ? "": "s";
}
I've always preferred things that format string to be as readable (fewest string concats) as possible. Feel free to chop some of these out if for example you can never have an empty deck or a deck that has only hidden cards ; not sure what the rules of this game are
If you invert the logic of your if(shpc) you can avoid nesting. I've used another variable hc for the count of hidden cards - I couldn't work out if this was shpc or not, and there was a bit of confusion over consistency of spc/shpc/vc?
If you ever plan on translating your game into another language, don't do any of this. Take a look at something like i18next instead
Perhaps see also Clever way to append 's' for plural form in .Net (syntactic sugar)
This is a refactoring of your code using C# 6.0 string interpolation, C# 7.0 pattern matching and a C# 8.0 switch expression which answers your (purely syntactical) question. There are lots of other ways of doing it, I'm just giving a hint what's possible with modern C# language features. Whether it actually makes sense, depends on your business context. At the very least, the more concise syntax makes it easier to spot any logical problems; e.g. is it correct that you sometimes use spc and at other times vc to indicate the number of visible cards?
return shpc switch{
_ when spc <= 1 => null,
0 => $"You have {spc} visible cards in your card deck. ",
1 => $"You have {vc} visible and one hidden card in your deck. ",
_ => $"You have {vc} visible and {shpc} hidden cards in your deck. "
};
So I'm doing a simple poker test in which I have to display the players' names and their hands, and the player who has the higher hand wins. For this test, there are no card suits and ranks (e.g. ten of spades, jack of diamonds), just the type of hand the player is supposed to have (e.g. royal flush, straight, high card, etc). The output should be like this:
Player 1, Jane's hand is: Full House
Player 2, John's hand is: One Pair
Winner: Jane (Full House)
So now, I have all the logic working for this (which you'll see below). However, I'm now supposed to make a unit test for this. I've seen some tutorials but if you see my code below, I don't think it's suitable for a unit test. If anyone can help me fix my code for unit testing, then I highly appreciate it.
Here's the code:
public class PokerGame
{
static void Main(string[] args)
{
// Names of the players
string player1Name, player2Name;
// The array of the poker hands
string[] pokerHands =
{
"High Card", "One Pair", "Two Pair", "Three of a Kind", "Straight", "Flush",
"Full House", "Four of a Kind", "Straight Flush", "Royal Flush"
};
// This will prompt the players to type their name
Console.Write("Enter Player 1: ");
player1Name = Console.ReadLine();
Console.Write("Enter Player 2: ");
player2Name = Console.ReadLine();
// This Random object will deal random hands accordingly
Random randomHand = new Random();
// The random hand index assigned to Player 1
int hand1 = randomHand.Next(pokerHands.Length);
// The random hand index assigned to Player 2
int hand2 = randomHand.Next(pokerHands.Length);
Console.WriteLine("Player 1, " + player1Name + "'s, hand is: " + pokerHands[hand1]);
Console.WriteLine("Player 2, " + player2Name + "'s, hand is: " + pokerHands[hand2]);
// If the random hand index for Player 1 is greater than that for Player 2
if (hand1 > hand2)
{
// Then Player 1 wins
Console.WriteLine("Winner: " + player1Name + " (" + pokerHands[hand1] + ").");
}
// But if it's the opposite
else if (hand1 < hand2)
{
// Player 2 wins
Console.WriteLine("Winner: " + player2Name + " (" + pokerHands[hand2] + ").");
}
// And if they have the same hands
else
{
Console.WriteLine("It's a tie!");
}
Console.ReadLine();
}
}
EDIT: After getting help from some friends and from people on Facebook (LOL), I managed to refactor some of my code into this:
public class PokerDealer
{
string[] hands =
{
"High Card", "One Pair", "Two Pair", "Three of a Kind", "Straight", "Flush",
"Full House", "Four of a Kind", "Straight Flush", "Royal Flush"
};
public void DealCards(int hand1, int hand2, string name1, string name2)
{
Random randomHand = new Random();
hand1 = randomHand.Next(hands.Length);
hand2 = randomHand.Next(hands.Length);
Console.WriteLine("Player 1, " + name1 + "'s hand: " + hands[hand1]);
Console.WriteLine("Player 2, " + name2 + "'s hand: " + hands[hand2]);
CheckWinner(hand1, hand2, name1, name2);
}
public int CheckWinner(int win1, int win2, string name1, string name2)
{
int winner;
if (win1 > win2)
{
winner = win1;
Console.WriteLine("Winner: " + name1 + " (" + hands[winner] + ")");
}
else if (win1 < win2)
{
winner = win2;
Console.WriteLine("Winner: " + name2 + " (" + hands[winner] + ")");
}
else
{
winner = 0;
Console.WriteLine("It's a tie!");
}
return winner;
}
}
DealCards() is basically my randomizer (gives out random cards) and CheckWinner(), well, checks who has the winning card. Also, I've already run unit tests for the winning conditions of both players, and they work! Now here are some problems:
How will I now test if they have the same card? (The last condition)
I'm trying to run a test for DealCards() to see if the players indeed get random cards and to see if it doesn't go out of the range (0 to 9; probably more important). For this one, I don't know how I will assert the latter condition. Here's the testing method:
[TestMethod]
public void RandomHand()
{
// Tests if players are given a random hand within the range
PokerDealer pd = new PokerDealer();
Random randomHand = new Random();
int randomHandIndex = randomHand.Next(10);
pd.DealCards(randomHandIndex, randomHandIndex, "Player 1", "Player 2");
}
To make the code better suited for unit testing, my advice would be: Only the Main() method should print text via Console.Write(). All the other methods should only return values. This way your tests can call the methods and check your assumptions about the return values. For example, CheckWinner() should return the text it currently writes to the console so you can verify in a test that the string returned by CheckWinner() (maybe rename to GetResultText() or something) matches the input parameters.
As for testing certain scenarios like both players having the same hand there are two options:
Create a mockup for Random. This way you can control which values it returns when used within a unittest. This is an advanced topic but it is a very useful technique for unit testing. Google C# mocking.
Use the same seed for the Random-instance every time (of course only when testing!); this way the values returned by the Next() calls will be always the same and you can use them for testing. For example
Random r = new Random(9);
Console.WriteLine(r.Next(10));
Console.WriteLine(r.Next(10));
will give you two fours in a row - every time.
As for your last point, how to test if ranodm returns random numbers within the given range. Why would you do that? Random it is not part of your code, so it does not make sense for you to test it.
This if statement within the update() have 2 for-loop, but it only runs the first one after the if condition is activated, and I don't know why.
I'm building a code for path optimizing in unity. Currently I have to find out the path that came across the nodes/points/positions with a certain positions array that the index is the order the path should follow. Some path between 2 nodes are repeated , ex: A to B and B to A is consider the same path and shall thicken the width of line AB eventually rendered. So I tried to sort out the position array into 2 different array for comparing if any of the pair of nodes(or we can say line) is repeated. And I encountered a problem in if statement within the update().
The first should sort out the original array for later comparison. The second one is just for testing if the first one do their job. No comparing yet. However after hitting play and satisfy the if statement I can see all the Debug.log in the first one, everything is normal, the sorting is normal, while the second one just doesn't print anything at all.
I tried comment out the first one, and the second one will run.
I tried to put second one outside the if statement, after it, and without commenting the first one, the second one won't run.
I tried to put the second one before the first one, in the if statement, the second one will run and the first one won't.
So I think this might be some kind of syntax error or am I using the if statement wrong? Please help.
if (l > 0)//activate when we choose any preset processes
{
for (int n = 0; n <= positions.Length; n++)//this loop will sort all the pos1 and pos 2 into array for current frame
{
curPos_1 = positions[n];//current position of node 1
curPos_2 = positions[n + 1];
Debug.Log("CURPOS_1 of line number " + n + " is " + curPos_1);
Debug.Log("CURPOS_2 of line number " + n + " is " + curPos_2);
flag[n] = 0;
Pos_1[n] = curPos_1;
Pos_2[n] = curPos_2;
Debug.Log("POS_1 array of line number " + n + " is " + Pos_1[n]);
Debug.Log("POS_2 array of line number " + n + " is " + Pos_2[n]);
}
for (int o = 0; o <= positions.Length; o++)
{
Debug.Log("flag of number " + o + " is " + flag[o]);
}
}
As described, all for loop should print something. Not just one of it.
Have you checked your Unity Console Window ?
In your first loop you get the next item but its condition will fail at the end, i.e. off by one.
Correct code should be something like this:
var floats = new float[100];
for (var i = 0; i < floats.Length - 1; i++)
{
var f1 = floats[i];
var f2 = floats[i + 1];
}
Now, Unity, has a behavior of ON ERROR RESUME NEXT, so it's highly probable that an error has occured but you haven't seen it (did you turn off the red icon for toggling errors in console ?).
Also, for some conditions only you know about (you didn't post the whole context), it could work once after you've changed some state of your program.
I am working on a text-based game, and I want to print the results in the end.
However, at the moment it only prints the latest input data and not the 5 loops in the array.
This is my array
int[] turnarr = new int[5];
turnarr[x] = turn;
for (int i = 0; i < turnarr.Length; i++)
Console.WriteLine(turnarr[i] + "\t" );
It's hard to be certain, as I only see part of the code, but I suspect that you are recreating the turnarr array in each turn, which would make every entry except the last one zero.
If the value of x never changes then you're only writing to a single item in the array, and thus overwriting it every time with the latest value of turn.
If turn is your last turn value, and x is 4, you will see four zeroes on their own lines and then the value of turn because you are only assigning to the xth index of turnarr
I took a look at your pastebin and tracked the issue down I believe:
The following line:
Console.WriteLine(turnarr[i] + "\t" + windarr[i] + " ms \t" + apmeterarr[x] + "m\t\t" + lenghtarr[x] + " meter\t\t");
you are using i for 2 spots, and x for the other 2 for your index variable...
Change
apmeterarr[x] and
lenghtarr[x]
To
apmeterarr[i] and
lenghtarr[i]