I want to give even number cards to player 1 and odd number cards to player 2 . If any of you guys could do it that will be really appreciated thank you. I know how to do this with array, but I am not sure with list.
class MatchDeck
{
private const int NUMBER_OF_CARDS = 36;
private Random r = new Random();
List<MatchCard> deck = new List<MatchCard>();
public MatchDeck(){ }
public void createDeck()
{
int[] number = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
string[] suits = { "R[]", "R0", "B0", "B[]" };//these are suits i just made up
// deck = new MatchCard[NUMBER_OF_CARDS];
foreach (var suit in suits)
{
for (int num = 2; num <= 10; num++)
{
deck.Add(new MatchCard(num, suit));
// Console.WriteLine(deck[i++].toString());
}
}
foreach(MatchCard card in deck)
{
Console.WriteLine(card.Number + " " + card.Suit);
}
}
public void Shuffle()
{
Random ran = new Random();
int n = deck.Count;
while (n > 1)
{
n--;
int k = ran.Next(n + 1);
MatchCard value = deck[k];
deck[k] = deck[n];
deck[n] = value;
}
foreach (MatchCard card in deck)
{
Console.WriteLine(card.Number + " " + card.Suit);
}
}
public void deal()
{
List<MatchCard> player1 = new List<MatchCard>();
List<MatchCard> player2 = new List<MatchCard>();
}
}
What you trying to achieve can be done by using a loop or Linq.
If you want to loop through your array or List the condition would be
if(deck[i] % 2 == 0) for even numbers. The opposite for odd. But this is already mentioned in the comment of #misha130.
May be you want to read about the Linq possibilities that List offers.
Here is a post that gives you a nice example how to extract values from a List according to a condition (like in your case). To get to know the class List and its methods please read the documentation
These two particular methods would be of your main interest in this case: FindAll && Where
Now you should have all the necessary information to solve your problem. Good luck. Comment if you are still stuck.
I've refactored your code so to what you're after. The key part relating to dealing the cards is the .Where((x, n) => n % 2 == 0)& .Where((x, n) => n % 2 == 1) code.
public class MatchDeck
{
private Random r = new Random();
List<MatchCard> deck = null;
public MatchDeck()
{
int[] number = { 2, 3, 4, 5, 6, 7, 8, 9, 10 };
string[] suits = { "R[]", "R0", "B0", "B[]" };
deck = number.SelectMany(n => suits, (n, s) => new MatchCard(n, s)).ToList();
}
public void Shuffle()
{
deck = deck.OrderBy(x => r.Next()).ToList();
}
public void Deal()
{
List<MatchCard> player1 = deck.Where((x, n) => n % 2 == 0).ToList();
List<MatchCard> player2 = deck.Where((x, n) => n % 1 == 0).ToList();
}
}
Related
12,13,14,15,16,19,19,19,19
to
12,19,13,19,14,19,15,19,16
Hey all. Can anyone point me to clues/samples on how to distribute the first array of Int32 values, where a bunch of 19 values were appended, to the second where the 19 values are fairly evenly interspersed in the array?
I am not looking for a random shuffling, as in this example #19 could still appear consecutively if there was randomization. I want to make sure that #19 is placed in between the other numbers in a predictable pattern.
The use-case for this is something like teams taking turns presenting a topic: teams 12-16 each present once and then team #19 shows up but should not show their topic four times in a row, they should show their topic in between the other teams.
Later, if twelve values of 7 are added to the array, then they will also have to be evenly distributed into the sequence as well, the array would be 21 elements but the same rule that neither #19 or #7 should have consecutive showings.
I thought there might be something in Math.NET library that would do this, but I did not find anything. Using C# on .NET Framework 4.7.
Thanks.
Details on the following method that evenly (mostly) distributes the duplicates in your list. Duplicates can be anywhere in your list, they will be distributed.
Create a dictionary of all numbers and keep track of the number of times they appear in the list
Use a new list without any duplicates. For Each number that has duplicates, spread it over the size of this new list. Each time the distribution is even.
public static List<int> EvenlyDistribute(List<int> list)
{
List<int> original = list;
Dictionary<int, int> dict = new Dictionary<int, int>();
list.ForEach(x => dict[x] = dict.Keys.Contains(x) ? dict[x] + 1 : 1);
list = list.Where(x => dict[x] == 1).ToList();
foreach (int key in dict.Where(x => x.Value > 1).Select(x => x.Key))
{
int iterations = original.Where(x => x == key).Count();
for (int i = 0; i < iterations; i++)
list.Insert((int)Math.Ceiling((decimal)((list.Count + iterations) / iterations)) * i, key);
}
return list;
}
Usage in main:
List<int> test = new List<int>() {11,11,11,13,14,15,16,17,18,19,19,19,19};
List<int> newList = EvenlyDistribute(test);
Output
19,11,13,19,14,11,19,15,16,19,11,17,18
Here's how to do this.
var existing = new[] { 12, 13, 14, 15, 16 };
var additional = new [] { 19, 19, 19, 19 };
var lookup =
additional
.Select((x, n) => new { x, n })
.ToLookup(xn => xn.n * existing.Length / additional.Length, xn => xn.x);
var inserted =
existing
.SelectMany((x, n) => lookup[n].StartWith(x))
.ToArray();
This gives me results like 12, 19, 13, 19, 14, 19, 15, 19, 16.
The only thing that this won't do is insert a value in the first position, but otherwise it does evenly distribute the values.
In case random distribution is enough the following code is sufficient:
static void MixArray<T>(T[] array)
{
Random random = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
}
}
For instance:
int[] input = new int[]{12,13,14,15,16,19,19,19,19};
MixArray<int>(input);
In case you require precise evenly distribution while retaining the order of the elements, to following code will do the job:
public static T[] EvenlyDistribute<T>(T[] existing, T[] additional)
{
if (additional.Length == 0)
return existing;
if (additional.Length > existing.Length)
{
//switch arrays
T[] temp = additional;
additional = existing;
existing = temp;
}
T[] result = new T[existing.Length + additional.Length];
List<int> distribution = new List<int>(additional.Length);
double ratio = (double)(result.Length-1) / (additional.Length);
double correction = -1;
if (additional.Length == 1)
{
ratio = (double)result.Length / 2;
correction = 0;
}
double sum = 0;
for (int i = 0; i < additional.Length; i++)
{
sum += ratio;
distribution.Add(Math.Max(0, (int)(sum+correction)));
}
int existing_added = 0;
int additional_added = 0;
for (int i = 0; i < result.Length; i++)
{
if (additional_added == additional.Length)
result[i] = existing[existing_added++];
else
if (existing_added == existing.Length)
result[i] = additional[additional_added++];
else
{
if (distribution[additional_added] <= i)
result[i] = additional[additional_added++];
else
result[i] = existing[existing_added++];
}
}
return result;
}
For instance:
int[] existing = new int[] { 12, 13, 14, 15, 16};
int[] additional = new int[] { 101, 102, 103, 104};
int[] result = EvenlyDistribute<int>(existing, additional);
//result = 12, 101, 13, 102, 14, 103, 15, 104, 16
I created a Blackjack game for coding school and I'm modifying it to display other aspects of the game, like what card value total the dealer had and what value total I had at the end of the game. It all works well until the Dealer Busted and I'm getting this error:
System.InvalidOperationException: 'Sequence contains no elements'
I've googled and searched Stackoverflow, but I didn't understand any of the responses. Here's my github code for it.
https://github.com/CrystalReimche/TwentyOneGame
In the TwentyOneGame.cs, line 143 is where where I'm trying to get it to display.
foreach (KeyValuePair<Player, int> entry in Bets)
{
Players.Where(x => x.Name == entry.Key.Name).First().Balance += (entry.Value * 2);
Console.WriteLine($"{entry.Key.Name} won {entry.Value} and now has a balance of {entry.Key.Balance}!");
Console.WriteLine($"Dealer had {TwentyOneRules.DealerCardValue(Dealer.Hand)} and {entry.Key.Name} had {TwentyOneRules.PlayerCardValue(entry.Key.Hand)}");
}
In the TwentyOneRules.cs holds the methods for it.
public static Dictionary<Face, int> _cardValues = new Dictionary<Face, int>()
{
[Face.Two] = 2,
[Face.Three] = 3,
[Face.Four] = 4,
[Face.Five] = 5,
[Face.Six] = 6,
[Face.Seven] = 7,
[Face.Eight] = 8,
[Face.Nine] = 9,
[Face.Ten] = 10,
[Face.Jack] = 10,
[Face.Queen] = 10,
[Face.King] = 10,
[Face.Ace] = 1
};
public static int[] GetAllPossibleHandValues(List<Card> Hand)
{
int aceCount = Hand.Count(x => x.Face == Face.Ace); // Find out how many Ace's there are
int[] result = new int[aceCount + 1]; // Plus 1 means if there's 2 Aces, there's 3 possible results ((1,1)||(1,11)||(11,11))
int value = Hand.Sum(x => _cardValues[x.Face]); // Value is the lowest possible value with all Ace's == 1
result[0] = value;
if (result.Length == 1) return result;
for (int i = 1; i < result.Length; i++)
{
value += (i * 10);
result[i] = value;
}
return result;
}
public static bool CheckForBlackJack(List<Card> Hand)
{
int[] possibleValues = GetAllPossibleHandValues(Hand);
int value = possibleValues.Max();
if (value == 2) return true;
else return false;
}
public static bool IsBusted(List<Card> Hand)
{
int value = GetAllPossibleHandValues(Hand).Min();
if (value > 21) return true;
else return false;
}
public static bool ShouldDealerStay(List<Card> Hand)
{
int[] possibleHandvalues = GetAllPossibleHandValues(Hand);
foreach (int value in possibleHandvalues)
{
if (value > 16 && value < 22)
{
return true;
}
}
return false;
}
public static bool? CompareHands(List<Card> PlayerHand, List<Card> DealerHand)
{
int[] playerResults = GetAllPossibleHandValues(PlayerHand);
int[] dealerResults = GetAllPossibleHandValues(DealerHand);
int playerScore = playerResults.Where(x => x < 22).Max(); // Filter the values that's < 22 and bring me the max of the values
int dealerScore = dealerResults.Where(x => x < 22).Max();
if (playerScore > dealerScore) return true;
else if (playerScore < dealerScore) return false;
else return null; // this is a tie
}
public static int PlayerCardValue(List<Card> PlayerHand)
{
int[] playerResults = GetAllPossibleHandValues(PlayerHand);
int playerScore = playerResults.Where(x => x < 50).Max();
return playerScore;
}
public static int DealerCardValue(List<Card> DealerHand)
{
int[] dealerResults = GetAllPossibleHandValues(DealerHand);
int dealerScore = dealerResults.Where(x => x < 22).Max();
return dealerScore;
}
I'm thinking it has something to do with the Dictionary, since the methods work on other parts of the game that do not use the Dictionary. For example, if I busted, it would display my card value total and the dealer card value total.
if (busted)
{
Console.WriteLine($"{player.Name} Busted! You lose your bet of {Bets[player]}. Your balance is now {player.Balance}");
Console.WriteLine($"Dealer had {TwentyOneRules.DealerCardValue(Dealer.Hand)} and {player.Name} had {TwentyOneRules.PlayerCardValue(player.Hand)}");
}
I just don't have a good grasp on how to use the Dictionary properly yet.
The problem is that you're invoking Max() (in either DealerCardValue or PlayerCardValue) on a sequence which contains no elements, as the Where() return value is an empty sequence, therefore there's no max value. This is written in the Max() function's documentation in MSDN.
Add DefaultIfEmpty() before Max() in DealerCardValue and PlayerCardValue to prevent InvalidOperationException from being thrown, as shown here, like so:
public static int DealerCardValue(List<Card> DealerHand)
{
int[] dealerResults = GetAllPossibleHandValues(DealerHand);
int dealerScore = dealerResults.Where(x => x < 22).DefaultIfEmpty().Max();
return dealerScore;
}
I'm trying to do the following.
Let's say I have a List, and I want to generate a new int in a specific range, but the value cannot be already defined in the List.
List<int> PredefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
int NewRandomValue = rnd.Next(0, 10);
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it to return 2, 5, 6, 7 or 10.
Any ideas?
As always, LINQ is your friend:
[TestMethod]
public void RandomTest()
{
var except = new[] {1, 2, 3, 5};
GetRandomExcept(1, 5, except).Should().Be(4);
}
private static int GetRandomExcept(int minValue, int maxValue, IEnumerable<int> except)
{
return GetRandoms(minValue, maxValue).Except(except).First();
}
private static IEnumerable<int> GetRandoms(int minValue, int maxValue)
{
var random = new Random();
while (true) yield return random.Next(minValue, maxValue);
}
Just keep in mind that you never should call GetRandoms().ToArray() or .Max() or .OrderBy() and so on, because you will get an endless loop and generate randoms forever.
What you can do though, is call GetRandoms().Take(10).ToArray() to get the next 10 random integers in an array.
Try examining if you can use the contains() method of List class... Simple solution would be to just generate values and checking contains and rejecting values that are already in the List until you get a value that is not. Also it might be more appropriate to use the Set Class because a set can not contain two elements that are equal.
What you need to do sample from other set. Lets say P is your predefinedIntsList and A is {1,2...9}.
You need to create a list, N = A-P. You will randomly sample from this set of numbers. It can be written more elegantly I suppose but see below example.
class Program
{
static void Main(string[] args)
{
List<int> predefinedIntsList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
List<int> newIntsList = new List<int>();
int upperBound = 10;
for (int i = 0; i < upperBound; i++)
{
if (!predefinedIntsList.Contains(i))
{
newIntsList.Add(i);
}
}
for (int i = 0; i < 20; i++)
{
int newRandomValueIndex = rnd.Next(0, newIntsList.Count);
int newRandomValue = newIntsList[newRandomValueIndex];
Console.WriteLine(newRandomValue);
}
}
}
Output
2
0
6
7
5
5
5
7
0
7
6
6
5
5
5
0
6
7
0
7
rnd.Next (obviously) comes up with 1, 3, 4, 8 or 9. But I ONLY want it
to return 2, 5, 6, 7 or 10.
Obviously not, it will return value that is either 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9 :P. If you're looking to include 10, and not 0, you want .Next(1, 11)
There are two choices that can work: either try generating values until you succeed, or if the range is small enough, generate the range, mark elemens that can't be picked, and sort them to last ones, and then pick random between [0..possibleToPickElementsCount]
The first approach would look something like this:
public static class RandomExtensions
{
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
// this will crash if values contains
// duplicate values.
var dic = values.ToDictionary(val => val);
// this can go into forever loop,
// think about this a bit.
for(;;){
var randomNumber= random.Next(minInclusive, maxExclusive);
if(!dic.ContainsKey(randomNumber))
return randomNumber;
}
}
}
The second approach is this, however it's only to give you an idea:
public static class RandomExtensions
{
class NormalizedPair
{
public int Value {get;set;}
public PairStatus Status {get;set;}
public NormalizedPair(int value){
Value = value;
}
public enum PairStatus {
Free,
NotFree
}
}
private static Random _internalRandom = new Random();
public static int Next(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var elements = maxExclusive - minInclusive;
var normalizedArr = new NormalizedPair[elements];
var normalizedMinInclusive = 0;
var normalizedMaxExclusive = maxExclusive - minInclusive;
var normalizedValues = values
.Select(x => x - minInclusive)
.ToList();
for(var j = 0; j < elements; j++)
{
normalizedArr[j] = new NormalizedPair(j){
Status = NormalizedPair.PairStatus.Free
};
}
foreach(var val in normalizedValues)
normalizedArr[val].Status = NormalizedPair.PairStatus.NotFree;
return normalizedArr
.Where(y => y.Status == NormalizedPair.PairStatus.Free) // take only free elements
.OrderBy(y => _internalRandom.Next()) // shuffle the free elements
.Select(y => y.Value + minInclusive) // project correct values
.First(); // pick first.
}
}
Or, if you're fan of sets:
public static int Next2(this Random random,
int minInclusive,
int maxExclusive,
IList<int> values)
{
var rangeSet = new HashSet<int>(
Enumerable.Range(
minInclusive,
maxExclusive - minInclusive));
// remove gibberish
rangeSet.ExceptWith(new HashSet<int>(values));
// this can be swapped out with
// yates shuffle algorithm
return rangeSet.OrderBy(x => _internalRandom.Next())
.First();
}
Rather than write logic to determine whether the random number has already been selected I prefer to generate a second list with the items in a random order.
That is easy to do with LINQ
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var secondList = originalList.OrderBy(x=>rnd.NextDouble());
The call to rnd.NextDouble returns a random seed that is used by the OrderBy method to sort each int value.
When I need to run thought the randomized items more than once, with a new sort order each time I walk the list, I will use a Queue to store the items. Then dequeue the items as needed. When the queue is empty it's time to refill.
private Queue<int> _randomizedItems;
private void RandomTest()
{
var originalList = new List<int>() { 1, 3, 4, 8, 9 };
Random rnd = new Random();
var temp = originalList.OrderBy(r=>rnd.NextDouble());
_randomizedItems = new Queue<int>(temp);
while (_randomizedItems.Count >0)
{
MessageBox.Show(_randomizedItems.Dequeue().ToString());
}
}
Hello I want to take 6 items from a list with 5 items at all. And I want to start taking the items at a given position. My result should be saved in another list.
For example:
List_1 = 1, 2, 3, 4, 5
6 items needed
start at position 2 {= 3}
List_result = 3, 4, 5, 1, 2, 3
List_1 = 7, 13, 6, 9, 17
2 items needed
start at position 4 {= 17}
List_result = 17, 7
I already tried to loop through the list with for and foreach, but could not find a real solution. Any help is greatly appreciated!
Something like this will do the trick. I wrote it up quickly, so I'm sure you can make it nicer
private IEnumerable<int> DoSomething(IEnumerable<int> set, int start, int num) {
var taken = 0;
var curSet = set.Skip(start);
while (taken < num) {
foreach(var current in curSet)
{
if (taken == num)
yield break;
yield return current;
taken++;
}
curSet = set;
}
}
Use like this:
DoSomething(new int[] { 1,2,3,4,5}, 2, 6);
Yields:
3,4,5,1,2,3
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var data = new List<int>(5){1,2,3,4,5};
var result = new List<int>(5);
for(int i=0;i<5;i++)
{
result.Add(data[(i+2)%data.Count]);
}
for(int i=0;i<result.Count;i++)
{
Console.WriteLine(string.Format("{0}\n",result[i]));
}
}
}
You could use this extension:
public static IEnumerable<T> TakeSpinning<T>(this IEnumerable<T> source, int take, int position = 0)
{
// skip check for invalid input like negative take or position
int skip = position;
int taken = 0;
while (taken < take)
{
foreach (T element in source)
{
if (skip > 0)
{
skip--;
continue;
}
yield return element;
if (++taken == take) break;
}
}
}
Your samples:
var List_1 = new List<int> { 1, 2, 3, 4, 5 };
var List_Result = List_1.TakeSpinning(6, 2).ToList(); // 3,4,5,1,2,3
var List_2 = new List<int> { 7, 13, 6, 9, 17 };
var List_Result2 = List_2.TakeSpinning(2, 4).ToList(); // 17,7
simple,
public static IEnumerable<T> TakeLoop<T>(
this IEnumerable<T> source,
int count,
int start = 0)
{
if (start < 0)
{
throw new ArgumentOutOfRangeException("start");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
using (var m = source.GetEnumerator())
{
for (var i = 0; i < count + start; i++)
{
if (!m.MoveNext())
{
if (i < start)
{
throw new ArgumentOutOfRangeException("start");
}
m.Reset();
m.MoveNext();
}
if (i >= start)
{
yield return m.Current;
}
}
}
}
to be used, like this,
var result1 = (new[] { 1, 2, 3, 4, 5 }).TakeLoop(6, 3);
or this,
var result2 = (new[] { 7, 13, 6, 9, 17 }).TakeLoop(2, 4);
its a simple iteration , you can use a simple loop to do this:
List list;// add values
int itemNeeded; //set item need
int startPostion; //set the start postion
for(int i=0;i<itemNeeded;i++){
add to newList the item at (startPosition++ % length of list)
}
It is all in the title basically. It is simple, but I don't know why my While loop is failing sometimes. Every now and then I would get a list that is of length 2 instead of 3.
Here is my C# code:
public List<int> generateRequiredSecretCode()
{
List<int> placeHolder = new List<int>();
Random random = new Random();
int randomNo = random.Next(0, 10);
while (!placeHolder.Contains(randomNo) && placeHolder.Count != 3)
{
placeHolder.Add(randomNo);
randomNo = random.Next(0, 10);
}
return placeHolder;
}
Summary of my aim: I want a List of integers that is of length 3 and where each number in the list is between 0 and 9 and is unique
You can have a neat LINQ two-liner using
var random = new Random();
return Enumerable.Range(0,10).OrderBy(i => random.NextDouble()).Take(3).ToList();
!placeHolder.Contains(randomNo) is your problem here because the while ends if the list contains the randomNo.
Check that !placeHolder.Contains(randomNo) in an inner if like this:
while (placeHolder.Count != 3)
{
if( !placeHolder.Contains(randomNo) )
placeHolder.Add(randomNo);
randomNo = random.Next(0, 10);
}
A little late to the party, but set arithmetic seems quite elegant so couldn't resist:
private static Random RNG = new Random();
...
public static List<int> RandomNumbers() {
var numbers = new HashSet<int> { RNG.Next(0, 9), RNG.Next(0, 9), RNG.Next(0, 9) };
while (numbers.Count < 3)
{
numbers.Add(RNG.Next(0, 9));
}
return numbers.ToList();
}
It sometimes fails because, in the rare cases when Rand.Next does return an identical number to thise already in the list, !placeHolder.Contains(randomNo) will return false; false && anything = false, so the loop ends. If you'd run it long enough, you'd eventually get a list of length 1 ;)
Possible replacement:
List<int> placeHolder = new List<int>();
Random random = new Random();
int randomNo;
do {
randomNo = random.Next(0, 10);
if (!placeHolder.Contains(randomNo) && placeHolder.Count != 3)
{
placeHolder.Add(randomNo);
randomNo = random.Next(0, 10);
}
} while (placeHolder.Count < 3);
return placeHolder;
[edit]: This thread moved fast... and Animal's solution is much better than mine :(