I am trying to Display Cards in Canvas programmatically from Script onClick. I have Successfully shuffled my cards and stored in player1 and player2 Array (26 random card to each player). I have create a basic players zone for player1 and player2. My approach is when i click the button the cards get distributed in their respective zones with images, stored in cards
I am new to unity and have no idea to render images to Canvas, I tried creating gameObject Canvas with help of google and stackoverflow question but i didn't solve my problem. I have store my full project on dropbox LINK: https://www.dropbox.com/sh/ofx9m6kaljpiecz/AAC7q7ufgAK1jlPHOfsGJWkPa?dl=0.
Canvas Image: https://www.dropbox.com/s/y118yboj9hx0i52/Screenshot%20%2833%29.png?dl=0
Here my main HelloWord.cs file
public class HelloWorld : MonoBehaviour
{
Sprite sprite;
List<string> player1 = new List<string>();
List<string> player2 = new List<string>();
public static string[] suits = new string[] { "spades", "hearts", "clubs", "diamonds" };
public static string[] values = new string[] { "ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "jack", "queen", "king" };
public List<string> deck;
Texture2D myTexture;
public void PlayCards()
{
deck = GenerateDeck();
Shuffle(deck);
}
public void distributeCard()
{
for (var x = 1; x <= 26; x++)
{
player1.Add(deck[x]);
foreach (var item in player1)
{
print("Player 1 Cards:" + item.ToString());
}
}
for (var y = 26; y <= 52; y++)
{
player2.Add(deck[y]);
foreach (var item in player2)
{
print("Player 2 Cards:" + item.ToString());
}
}
}
public void onClick()
{
PlayCards();
distributeCard();
}
public static List<string> GenerateDeck()
{
List<string> newDeck = new List<string>();
foreach(string s in suits)
{
foreach(string v in values)
{
newDeck.Add(v +"_of_" + s);
}
}
return newDeck;
}
void Shuffle<T>(List<T> list)
{
System.Random random = new System.Random();
int n = list.Count;
while (n > 1)
{
int k = random.Next(n);
n--;
T temp = list[k];
list[k] = list[n];
list[n] = temp;
}
}
}
There is a UI Element called "RawImage". That is just a single Texture to be shown in your UI layer on your canvas. It can be added from the editor in UI -> Raw Image .
You can assign a material or a texture.
The element UnityEngine.UI.RawImage has a property 'material' that you can assign anytime. You can use that to assign materials you have prepared, one for each card.
When using a material, be sure to set the shader "Unlit/Color" or "Unlit/Transparent", because normal shaders using light will show a black image on the UI layer.
Related
This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 1 year ago.
I have this card war game; the game starts with each player flipping over 1 card and whomever has the highest card wins. If there is a tie, the next three cards in the deck are played face down and the 4th card dealt face up, whomever has the highest card wins. The game is played until 1 player has all of the cards; however, I haven’t been able to finish it correctly, it crashes every time that I hit enter after the statement "lets flipping cards," and I haven’t been able to make the players to get the 4th card because when using a third variable r3, it crashes likewise.
using System;
using System.Collections.Generic;
namespace PTCB12WARGAME2
{
class Card
{
public string Name;
public int Value;
public string Suit;
public override string ToString() { return string.Format("{0} of {1}", Name, Suit); }
}
class DeckOfCards
{
static void Main(string[] args)
{
List<Card> DeckOfCards = new List<Card>();
var names = new[] { "Ace", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
var suits = new[] { "Hearts", "Clubs", "Diamonds", "Spades" };
var cards = new List<Card>();
// Populate our deck of cards with two nested loops
foreach (var suit in suits)
{
// We use a 'for' loop here instead of 'foreach' so we can use the index to
// populate the Value (which is always one more than the index of the name)
for (int i = 0; i < names.Length; i++)
{
cards.Add(new Card { Name = names[i], Value = i + 1, Suit = suit });
}
}
//Display deck of 52 cards
Console.WriteLine("Each player is flipping over 1 card and whomever has the highest card wins");
Console.ReadLine();
for (int i = 0; i < DeckOfCards.Count; i++)
{
Console.WriteLine(DeckOfCards[i]);
}
Console.WriteLine();
// create just ONCE the random object
Random random = new Random();
List<Card> deckOfPlayer1 = new List<Card>();
List<Card> deckOfPlayer2 = new List<Card>();
do
{
Console.WriteLine("Let's flip cards");
string userAnswer = Console.ReadLine();
if (userAnswer == "quit")
break;
// pick a random card for player 1
int r1;
r1 = random.Next(0, DeckOfCards.Count);
Card c1 = DeckOfCards[r1];
deckOfPlayer1.Add(c1);
// pick a random card for player 2
int r2;
r2 = random.Next(0, DeckOfCards.Count);
Card c2 = DeckOfCards[r2];
deckOfPlayer2.Add(c2);
Console.WriteLine("Player1 has: {0}", c1);
Console.WriteLine("Player2 has: {0}", c2);
// now compare the cards
if (c1.Value == c2.Value )
{
Console.WriteLine("Its a tie! Next three cards in deck are played face down, " +
"4th card face up, whoever has the highest card wins");
int r3;
r3 = random.Next(0, DeckOfCards.Count);
Card c3 = DeckOfCards[3];
deckOfPlayer1.Add(c3);
Console.WriteLine(deckOfPlayer1[3]);
Console.WriteLine(deckOfPlayer2[3]);
if (c1.Value > c2.Value && c2.Value != 1)
{
deckOfPlayer1.Add(c2);
deckOfPlayer2.Remove(c2);
Console.WriteLine("Player1 wins");
}
else
{
Console.WriteLine("Player2 wins");
deckOfPlayer2.Add(c1);
deckOfPlayer1.Remove(c1);
}
}
else if (c1.Value == 1 || (c1.Value > c2.Value && c2.Value != 1))
{
deckOfPlayer1.Add(c2);
deckOfPlayer2.Remove(c2);
Console.WriteLine("Player1 wins");
}
else
{
Console.WriteLine("Player2 wins");
deckOfPlayer2.Add(c1);
deckOfPlayer1.Remove(c1);
}
} while (deckOfPlayer1.Count < 52 || (deckOfPlayer2.Count < 52));
}
}
}
First, please learn how to use interactive debugging. If all you know is "it crashed", then you're going to struggle to find and eliminate bugs in your code. Here's one tutorial you can start with.
In this instance, the problem is likely due to your use of two lists:
List<Card> DeckOfCards = new List<Card>(); // One here
var names = new[] { "Ace", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
var suits = new[] { "Hearts", "Clubs", "Diamonds", "Spades" };
var cards = new List<Card>(); // And one here
You are populating the second one with cards.Add, but you are trying to access the first one everywhere else, for example with these lines:
r1 = random.Next(0, DeckOfCards.Count);
Card c1 = DeckOfCards[r1];
Remove one of the lists, replace it with the other instance, and your code will have a better chance of running (disclaimer: I haven't compiled it to check for other issues)
I'm working on a small C# Winforms application that replicates several visual experiments concerning cognitive psychology. Instead of using premade images, I was trying to create them programmatically to train my skills.
Now I'm working on the Stroop Effect and I'm attempting to reproduce the following image:
I prepared two distinct arrays, one containing the colors and one containing the name of the colors:
Color[] colors =
{
Color.Blue,
Color.Red,
Color.Black,
Color.Green
};
String[] names =
{
"BLUE",
"RED",
"BLACK",
"GREEN"
};
The first step is easy. All I have to do is to draw the strings using their respective ForegroundColor, such that names[0] will be printed using colors[0], names[1] will be printed using colors[1] and so on...
And here comes the hard part of the task. Once the string array has been shuffled:
Random r = new Random();
String[] namesRandom = names.OrderBy(x => r.Next()).ToArray();
I have to shuffle the colors array too. But this must be achieved making sure that no color is being matched with its correct name. So, for example, this will be correct:
"BLACK" Color.Green
"GREEN" Color.Red
"RED" Color.Blue
"BLUE" Color.Black
and this will be wrong:
"BLACK" Color.Black -> Matching Color/Name
"GREEN" Color.Red
"RED" Color.Blue
"BLUE" Color.Green
Any idea about how to accomplish this efficiently? I would like to avoid the shuffle until condition is met approach.
P.S. = drawing strings on a Bitmap is not a problem and I don't need help on this development task.
[EDIT]
For 10k-ers that downvote for not being able to associate the concept of shuffle until condition is met with a few lines of code or because they think I'm trying to get my work done while I play Tetris, here is a quick implementation of my current algorithm:
public class Program
{
private static Random s_Random = new Random();
public static void Main(String[] args)
{
Color[] colors =
{
Color.Blue,
Color.Red,
Color.Black,
Color.Green
};
String[] names =
{
"BLUE",
"RED",
"BLACK",
"GREEN"
};
while (MatchingPairs(colors, names))
{
colors = Shuffle(colors);
names = Shuffle(names);
}
for (Int32 i = 0; i < colors.Length; ++i)
Console.WriteLine(colors[i].Name.ToUpperInvariant() + " | " + names[i]);
}
private static Boolean MatchingPairs(Color[] colors, String[] names)
{
for (Int32 i = 0; i < colors.Length; ++i)
{
if (colors[i].Name.ToUpperInvariant() == names[i])
return true;
}
return false;
}
private static T[] Shuffle<T>(T[] array)
{
return array.OrderBy(x => s_Random.Next()).ToArray();
}
}
So, as you can see, I can use my fingers to type code. I'm just wondering if there is a better approach to obtain the same result.
This is maybe not the best approach, but it should work fine. One way to solve this would be to assign random names until you have only two left (where index i == Count - 2). At that point, if the name of the item at index i + 1 is one of the remaining choices, use that for the item at index i.
Here's some sample code that uses a console application (and ConsoleColor), but the concept is the same. I've used a class that combines a ConsoleColor and a string, so if you want to use arrays it would need some modification.
First the class:
class NamedColor
{
public ConsoleColor Color { get; set; }
public string Name { get; set; }
public NamedColor(ConsoleColor color, string name)
{
Color = color;
Name = name;
}
}
And a method that prints out a list of these objects to the Console:
static void PrintColors(IEnumerable<NamedColor> colors)
{
Console.BackgroundColor = ConsoleColor.Gray;
Console.Write(new string(' ', 80));
foreach (var color in colors)
{
Console.ForegroundColor = color.Color;
Console.Write(color.Name + " ");
}
Console.Write(new string(' ', 139)); // Ugly, hard-coded length for simplicity
}
Then we can create a method that will take a list of these objects, shuffle all the names between them, and return that new list:
static NamedColor[] ShuffleNames(NamedColor[] colors)
{
var names = colors.Select(c => c.Name).ToList();
var shuffled = new NamedColor[colors.Length];
for (int i = 0; i < colors.Length; i++)
{
string name;
// If there are only two items left, and our list of names contains
// the *next* item's name, then we must take that name for this item
if (i == colors.Length - 2 && names.Contains(colors[i + 1].Name))
{
name = colors[i + 1].Name;
}
else
{
// Choose a random name from all names except this item's name
var candidateNames = names.Where(n => !n.Equals(colors[i].Name)).ToList();
name = candidateNames[rnd.Next(candidateNames.Count)];
}
shuffled[i] = new NamedColor(colors[i].Color, name);
names.Remove(name);
}
return shuffled;
}
Then we can shuffle our list, then shuffle the names, and then print out the list like so:
private static Random rnd = new Random();
static void Main(string[] args)
{
var correctColors = new NamedColor[]
{
new NamedColor(ConsoleColor.Blue, "BLUE"),
new NamedColor(ConsoleColor.Black, "BLACK"),
new NamedColor(ConsoleColor.Red, "RED"),
new NamedColor(ConsoleColor.Green, "GREEN"),
};
PrintColors(correctColors);
for (int count = 0; count < 10; count++)
{
// Shuffle the items, then shuffle the names
var shuffledColors = correctColors.OrderBy(c => rnd.NextDouble()).ToArray();
shuffledColors = ShuffleNames(shuffledColors);
PrintColors(shuffledColors);
}
Console.ResetColor();
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output
You could do the following:
Implement a rule of valid colors for each name:
Func<string, IEnumerable<Color>> validColorsRule = s =>
{
switch (s)
{
case "BLUE": return colors.Except(new[] { Color.Blue });
case "RED": return colors.Except(new[] { Color.Red });
case "BLACK": return colors.Except(new[] { Color.Black });
case "GREEN": return colors.Except(new[] { Color.Green });
default: throw new NotSupportedException();
}
};
Build the shuffled Color array with Enumerable.Aggregate:
Color[] colorRandom =
namesRandom.Aggregate(Enumerable.Empty<Color>(),
(acc, n) =>
acc.Concat(new[] {
validColorsRule(n).Except(acc)
.OrderBy(x => r.Next())
.FirstOrDefault() }))
.ToArray();
You could reformulate as a pseudo-random problem.
Generate a random integer between 1 and n-1(say i) and shift the color array(use a copy of it) by that i
Now generate a random sequence between 0 and n-1 without replacement and print the name and color
static void Main(string[] args)
{
ConsoleColor[] colors =
{
ConsoleColor.Blue,
ConsoleColor.Red,
ConsoleColor.Black,
ConsoleColor.Green
};
String[] names =
{
"BLUE",
"RED",
"BLACK",
"GREEN"
};
Random r = new Random();
int i = 0;
while(i==0)
i=r.Next() % (names.Length-1);
List<int> rndList = Enumerable.Range(0,names.Length).OrderBy(x => r.Next()).ToList();
Console.BackgroundColor = ConsoleColor.White;
foreach(int j in rndList)
{
int k = (j+i) % (colors.Length);
Console.ForegroundColor = colors[k];
Console.Write(names[j] + " ");
}
}
I think that you are trying to create a random derangement. A web search for this finds a paper about the efficient generation of such things at http://epubs.siam.org/doi/pdf/10.1137/1.9781611972986.7 - "Generating Random Derangements" by Martinez, Panholzer, and Prodinger. However the paper also shows that, even as n gets possibly very large, the chance of a randomly chosen permutation being a derangement remains very close to 1/e, so the simple solution of just generating a random permutation and checking to see if it is a derangement, repeating until this is true, may in practice be efficient enough for most purposes.
I have a class called Players that holds various player attributes. I want to use a loop to initialize a list of Players based on certain user input. I will then use the list to play a card game with each of the players. I guess the List needs to be global in scope.
I can't figure out how to initialize the list since I can't seem to user a var
in the name field when trying to create a new Player.
Thanks
class Players
{
public string name;
public double bank;
public Hands playerHands; //A List of hands played
public Players ()
{
name = "Unknown";
bank = 0.0;
playerHands = null;
}
public Players(string name, double bank, Hands playerHands)
{
this.name = name;
this.bank = bank;
this.playerHands = playerHands;
}
}
class Program
{
private static int numOfPlayers;
private static int numOfDecks;
private static List<Cards> shoe;
public static void Main()
{
Console.OutputEncoding = Encoding.UTF8; //required to display special characters
Hands playerHands = new Hands();
Hands dealerHands = new Hands();
SetUpTable();
//Initilize Players
Players player = new Players("Ken", 100.00, playerHands);
Players dealer = new Players("Dealer", 0.0, dealerHands);
int dealerScore = 0, playerScore = 0;
//Deal initial cards
//The deal starts with the dealer who gets the first card face down
Cards dealerUpCard = null;
Hand dealerHand = new Hand();
Hand playerHand = new Hand();
dealer.playerHands.addHand(dealerHand);
player.playerHands.addHand(playerHand);
for (int iii = 1; iii < 3; iii++)
{
//Deal dealer's hand
dealerHand.addCard(shoe[0]);
dealerScore += shoe[0].value;
if (iii == 2) { dealerUpCard = shoe[0]; }
shoe.RemoveAt(0);
//Deal Player's aHand
playerHand.addCard(shoe[0]);
playerScore += shoe[0].value;
shoe.RemoveAt(0);
}
//Print out the test hands
displayHand(dealer);
displayHand(player);
Console.Read();
}
static void displayHand(Players player)
{
//Print out the test hands
for (int i = 0; i < player.playerHands.hands.Count; i++)
{
Console.Write("{0}'s hand: ", player.name);
for (int j = 0; j < player.playerHands.hands[i].hand.Count; j++)
{
Console.Write(" {0}{1} ", player.playerHands.hands[i].hand[j].rank, (char)player.playerHands.hands[i].hand[j].suit);
}
Console.WriteLine();
}
}
static void SetUpTable()
{
//Create players
numOfPlayers = validateUserInput("How many players (1-6)?",1,6);
for (int i = 0; i<numOfPlayers; i++)
{ //get player elements
//initiliz a new unique player in the Players list
//ie: Players player = new Players("Ken", 100.00, playerHands);
}
//Create shoe of cards
numOfDecks = validateUserInput("How many decks of cards (1-8)?", 1, 8);
shoe = Deck.createDeck(numOfDecks);
Deck.shuffleDeck(shoe, numOfDecks);
}
}
public List<Players> ListOfPlayers=new List<Players>();
static void SetUpTable()
{
//Create players
numOfPlayers = 6;
for (int i = 0; i<numOfPlayers; i++)
{
ListOfPlayers.Add(new Players());
//or with initial values with ctor:
ListOfPlayers.Add(new Players("Ken", 100.00, playerHands));
//or
ListOfPlayers.Add(new Players(){name="Ken", bank=100.00, playerHands=_playerHands});
//ie: Players player = new Players("Ken", 100.00, playerHands);
}
}
I'm trying to create a deck of 52 cards with the 4 suits: spades, hearts, clubs, and diamonds. I tried to create this for loop in my Deck class but seem to be running into some problems regarding actually getting the program to do what I want. I'm thinking maybe I could do 4 for loops as the assignment hinted at, but is it possible to use if/else-ifs to create 4 suits within the deck?
class Deck
{
private Card[] cards;
public Deck()
{
cards = new Card[52];
int check = 0;
for (int suitVal = 1; suitVal < 4; suitVal++)
{
for (int rankVal = 1; rankVal < 14; rankVal++)
{
if(suitVal == 1)
{
cards[check] = new Card(rankVal, "Spades");
}
else if (suitVal == 2)
{
cards[check] = new Card(rankVal, "Hearts");
}
else if (suitVal == 3)
{
cards[check] = new Card(rankVal, "Clubs");
}
else if (suitVal == 4)
{
cards[check] = new Card(rankVal, "Diamonds");
}
}
}
}
Yes, it is possible.
There are 13 cards and 4 suits. The idea is that for each suit, you create 13 cards with of said suit. The pseudo code is pretty much what you have already got:
for each of the four suits
loop 13 times for said suit
Here are the problems with your code:
1- Your check variable is never incremented, so you always overwrite the card on the position 0; It should increment after every card inserted (inner loop)
2- Your outter loop only runs 3 times (i = 1, i = 2, i = 3), and there are 4 suits.
Let me know if you need more help.
You could do it these ways:
class Deck
{
private Card[] cards;
public Deck()
{
cards =
new [] { "Spades", "Hearts", "Clubs", "Diamonds", }
.SelectMany(
suit => Enumerable.Range(1, 13),
(suit, rank) => new Card(rank, suit))
.ToArray();
}
}
Or:
class Deck
{
private Card[] cards;
public Deck()
{
var query =
from suit in new [] { "Spades", "Hearts", "Clubs", "Diamonds", }
from rank in Enumerable.Range(1, 13)
select new Card(rank, suit);
cards = query.ToArray();
}
}
Or:
class Deck
{
private Card[] cards;
public Deck()
{
cards = new Card[52];
var index = 0;
foreach (var suit in new [] { "Spades", "Hearts", "Clubs", "Diamonds", })
{
for (var rank = 1; rank <= 13; rank++)
{
cards[index++] = new Card(rank, suit);
}
}
}
}
I want to create a highscore board for my game.
the score board contain the top 5 scores in the text file
the text file are something like this:
alpha, 3500
beta, 3600
gamma, 2200
delta, 3400
epsilon, 2000
and this is my codes :
[Serializable]
public struct HighScoreData
{
public string[] PlayerName;
public int[] Score;
public int Count;
public HighScoreData(int count)
{
PlayerName = new string[count];
Score = new int[count];
Count = count;
}
}
static HighScoreData highScores;
this codes for reading data from text file and already add sorting in it:
try
{
using (StreamReader sr = new StreamReader("highscore.txt"))
{
string line;
int i = 0;
//file = new StreamReader(filePath);
while ((line = sr.ReadLine()) != null)
{
string[] parts = line.Split(',');
highScores.PlayerName[i] = parts[0].Trim();
highScores.Score[i] = Int32.Parse(parts[1].Trim());
i++;
Array.Sort(highScores.Score);
}
}
}
this is how I draw it :
for (int i = 0; i < 5; i++)
{
spriteBatch.DrawString(spriteFont, i + 1 + ". " + highScores.PlayerName[i].ToString()
, new Vector2(200, 150 + 50 * (i)), Color.Red);
spriteBatch.DrawString(spriteFont, highScores.Score[i].ToString(),
new Vector2(550, 150 + 50 * (i)), Color.Red);
}
the problem is when I run the game, it only sorting the scores and not the player name. and also, the first and secod scores in text file are identified as "0". it displayed like this :
alpha 0
beta 0
gamma 2000
delta 2200
epsilon 3400
what must I do, so the program can sorting all the data in the text file, not only the score...?
Another option without comparers using LINQ based on Blau's sample:
struct PlayerScore
{
public string Player;
public int Score;
public int DataYouWant;
}
then a sample of populating the list and sorting it:
List<PlayerScore> scores = new List<PlayerScore>();
Random rand = new Random();
for (int i = 0; i < 10; i++)
{
scores.Add(new PlayerScore()
{
Player = "Player" + i,
Score = rand.Next(1,1000)
});
}
scores = (from s in scores orderby s.Score descending select s).ToList();
foreach (var score in scores)
{
Debug.WriteLine("Player: {0}, Score: {1}", score.Player, score.Score);
}
Make a struct named PlayerScore
struct PlayerScore
{
public string Player;
public int Score;
public int DataYouWant;
public static int Compare(PlayerScore A, PlayerScore B)
{
return A.Score - B.Score;
}
}
and then to Sort call only one time, (outside the while) to the sort method this way:
Array.Sort<PlayerScore>( yourArray, PlayerScore.Compare );
Do you really need to have more than HighScoreData instance? I think that no.. so you store your highscores this way:
static PlayerScore[] highScores = new PlayerScore[MaxHighScorePlayers];