I am making a tic tac toe game and I am making it to be unbeatable
but first I have to let the computer know the rules.
I'm stuck in a step that is => when it's the computer's turn and we have just started the game so no win case so it's up to the computer to generate a random number that will be the computer's choice ( the block where he mark X or O )
so I need it to generate a number from 1 to 9 but by excluding the already used blocks ( numbers ).
I tried doing that by making a list and adding a number every time the human player used a block but I can't find a way to use those numbers from the list as exclusion for the random choice of the computer.
Here is what I tried and thnx in advance:
//random
List<int> cas = new List<int>();
if (c1 == true)
{
cas.Add(1);
}
if (c2 == true)
{
cas.Add(2);
}
if (c3 == true)
{
cas.Add(3);
}
if (c4 == true)
{
cas.Add(4);
}
if (c5 == true)
{
cas.Add(5);
}
if (c6 == true)
{
cas.Add(6);
}
if (c7 == true)
{
cas.Add(7);
}
if (c8 == true)
{
cas.Add(8);
}
if (c9 == true)
{
cas.Add(9);
}
for (int i = 0; i < cas.Count; i++)
{
random_except_list(cas[]);
}
public static int random_except_list(int[] x)
{
Random r = new Random();
int result = r.Next(1, 9 - );
for (int i = 0; i < x.Length; i++)
{
if (result < x[i])
return result;
result++;
}
return result;
}
Lets have possible places to use:
List<int> possible = Enumerable.Range(1,9).ToList(); // create a list and add 1-9
and used places:
List<int> used = new List<int>();
Random rnd = new Random();
Now everytime we generate a random number in the range of possible list count as index and remove it from there and move it to used:
int index = rnd.Next(0, possible.Count);
used.Add(possible[index]);
possible.RemoveAt(index);
for user its just enough to check if it exists in the used so the acceptable number should be:
!used.Any(x=> x== NumberUserHaveChosen)
So the first time the random number can be 0-8 (as possible.Count==9) and take from it at random index.
the second time the random number can be 0-7 (as possible.Count==8) and take from it at random index.
and so on... while the possible.Count != 0
in this case there is no need to generate random numbers several times that finally it won't exist in our used List.
Several years ago I was working on a Sudoku algorithm, and what I was trying to achieve was to generate a valid solved sudoku table in minimum time possible, i get to the conclusion that I should replace the algorithm that each time I generate a number I have to check some lists to make sure the number was not generated before, as count of numbers were increasing these comparisons would become more and more. for example when only the number 4 is remaining, I should generate random numbers till I get 4. so I used this approach and the result was amazing.
I think you should do something like this:
public static int random_except_list(List<int> x)
{
Random r = new Random();
int result = 0;
while (true)
{
result = r.Next(1, 10);
if (!x.Contains(result))
return result;
}
}
Just trying to use what you have written (more or less), but changing the method to take a List<int> which is what you are building, I would write the method using LINQ like this (except I would create a static Random variable and keep it between calls):
public static int random_except_list(List<int> x) => Enumerable.Range(1, 9).Where(n => !x.Contains(n)).ToList()[new Random().Next(0, 9 - x.Count)];
However, you can implement the same idea in a more explicit way using procedural code:
public static int random_except_list_explicit(List<int> x) {
// First, generate a list of possible answers by skipping the except positions in x
var possibles = new List<int>();
for (int i = 1; i <= 9; i++)
if (!x.Contains(i))
possibles.Add(i);
// now pick a random member of the possible answers and return it
return possibles[new Random().Next(0, possibles.Count)];
}
I believe it is better to work with positions left. So user or computer select from all open positions:
using System;
using System.Collections.Generic;
class app
{
public static int random_except_list(List<int> openPositions)
{
Random r = new Random();
int index = r.Next(openPositions.Count - 1);
int result = openPositions[index];
openPositions.RemoveAt(index);
return result;
}
static void Main()
{
List<int> openPositions = new List<int>();
for (int i = 1; i < 10; i++)
{
openPositions.Add(i);
}
bool turn = false;
while (openPositions.Count > 0)
{
foreach (int value in openPositions)
{
Console.Write(value + " ");
}
Console.WriteLine();
if (!turn)
{
while (true)
{
Console.WriteLine("Choose your Position");
ConsoleKeyInfo key = Console.ReadKey();
int num = (int)key.KeyChar - 48;
if (openPositions.Contains(num))
{
openPositions.Remove(num);
Console.WriteLine();
break;
}
else Console.Write(" is not Valid: ");
}
}
else
{
int compPos = random_except_list(openPositions);
Console.WriteLine("Computer choose: " + compPos);
}
turn = !turn;
}
Console.WriteLine("No positions left");
Console.ReadKey();
}
}
Related
I'm very sorry this is such an easy question, I'm just starting out. I've created code that allows a user to enter a number of random dice rolls, and outputs the sum of those rolls. I've now been asked to create a loop that repeats these steps, including the prompt, until the user types 'quit'. My issue is that my code converts the string to an integer, so typing anything kills the code. Any tips of how to insert the loop and break? My code is:
static void Main(string[] args)
{
Random random = new Random();
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
int numberDice = Convert.ToInt32(numberDiceString);
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.ReadKey();
}
I wouldn't use a "while(true)" statement. As someone pointed out in the comments i would prefer using the right condition in there.
That being said i would do it this way:
static void Main(string[] args)
{
Random random = new Random();
string numberDiceString;
int numberDice;
Console.WriteLine("Enter a number of dice to roll:");
while ((numberDiceString = Console.ReadLine()) != "quit")
{
bool parsed = int.TryParse(numberDiceString, out numberDice);
if (!parsed)
{
//Handle the error. The user input was not a number or "quit" word
break;
}
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.WriteLine("Enter a number of dice to roll:");
}
}
I have to say that i prefer this way because you can easily see when the loop will stop. Also i added an error handling that you should be doing (What happen if the user enters any words that are not numbers?).
Hope this helps.
This change should be fairly simple. What you need to do is to create a while loop, and then a check before you actually parse for an int. The psuedocode for this would be something like.
while(true) {
//Ask for input
//Check if it equals "quit"
//If so -> break;
//If not convert to int
//For Loop for dice rolls
//Print Total
}
I'm sure it could be a little more elegant than this, and you would want to put some more checks to make sure that invalid input doesn't crash the program, but it should get the job done.
This is a very simple solution that shows how to parse the user input.
using System;
namespace Simpleton
{
class Program
{
static public int GetChoice()
{
int choice = 0;
while (true)
{
Console.Write("Enter number of rolls or \"quit\" to finish: ");
var answer = Console.ReadLine();
if (String.Compare(answer, "quit", true) == 0)
{
return 0; // Done
}
if (Int32.TryParse(answer, out choice))
{
return choice;
}
}
}
static void Main(string[] args)
{
var choice = 0;
while ((choice = GetChoice()) > 0)
{
Console.WriteLine($"You'll be looping {choice} times.");
for (int tries = 0; tries < choice; tries++)
{
// Looping
}
}
}
}
}
Try this code:
static void Main(string[] args)
{
Random random = new Random();
while(true)
{
String numberDiceString = "";
int numberDice = 0;
Console.WriteLine("Enter a number of dice to roll:");
numberDiceString = Console.ReadLine();
if (numberDiceString == "quit") { return; }
int total = 0;
if (Int32.TryParse(numberDiceString, out numberDice))
{
total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
}
Console.WriteLine(total);
}
}
I'm not a C# programmer, but you can test for "quit" explicitly and use a goto
BeginLoop:
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
if (numberDiceString == "quit")
{
goto EndLoop;
}
int numberDice = Convert.ToInt32(numberDiceString);
/* Rest of code you want to do per iteration */
goto BeginLoop;
EndLoop:
I'm trying to create something that will be like a basic random password generator including uppercase, lowercase and digits - but for some reason this
static void Main(string[] args)
{
bool validLength = false;
int userDefinedLength = 0;
Console.WriteLine("How many characters would you like your password to be?");
do
{
try
{
userDefinedLength = int.Parse(Console.ReadLine());
validLength = true;
if (userDefinedLength < 3)
{
Console.WriteLine("Please enter something larger than 3.");
validLength = false;
}
}
catch (Exception)
{
Console.WriteLine("Please input a valid integer length.");
}
} while (validLength == false);
char[] passwordArray = new char[userDefinedLength];
int asciiValue = 0;
char asciiChar = ' ';
bool validPassword = false;
Random ranAsciiGroup = new Random();
Random ascValue = new Random();
do
{
for (int i = 0; i < passwordArray.Length; i++)
{
int randomAsc = 0;
randomAsc = ranAsciiGroup.Next(1, 4);
//Console.WriteLine(randomAsc);
if (randomAsc == 1)
{
asciiValue = ascValue.Next(65, 91);
//Console.WriteLine(asciiValue);
}
else if (randomAsc == 2)
{
asciiValue = ascValue.Next(97, 123);
//Console.WriteLine(asciiValue);
}
else if (randomAsc == 3)
{
asciiValue = ascValue.Next(48, 58);
//Console.WriteLine(asciiValue);
}
asciiChar = (char)asciiValue;
passwordArray[i] = asciiChar;
//validPassword = true;
}
bool isDigit = false;
bool isUpper = false;
bool isLower = false;
for (int i = 0; i < passwordArray.Length; i++)
{
if (char.IsDigit(passwordArray[i]))
{
isDigit = true;
}
if (char.IsUpper(passwordArray[i]))
{
isUpper = true;
}
if (char.IsLower(passwordArray[i]))
{
isLower = true;
}
}
if (isDigit == true && isUpper == true && isLower == true)
{
validPassword = true;
}
} while (validPassword == false);
Console.WriteLine("Your password is...");
Console.ForegroundColor = ConsoleColor.DarkGreen;
foreach (char c in passwordArray)
{
Console.Write(c);
}
Console.ReadLine();
}
The password that it produces seems to not be using any numbers that are less than 6. And some of the characters that it produces are quite repeated - e.g. the lower case tend to have characters that appear much more than some others - or some that don't appear at all. I'll leave a 100 character example here.
m9nj88m8GBpF7Hk87E8p9CAE987pEj7pm7j89iHplo7DIpB87B9irlAk9Ik9C8q8i97B9o8l8GDjj88j898Dmk9A69969Ino988I
Seed your RNG
Don't forget to seed your instance of random, e.g.
var random = new System.Random(Environment.TickCount);
Also, one instance should be enough.
Eliminating repetition
If you wish to ensure that all characters are represented, you can use a different random selection technique. For example, you could generate a very very long string that contains all the characters you want, sort it randomly, then take the first n characters. This approach would completely eliminate repeated characters and guarantee that every character gets used eventually. For example:
using System;
using System.Linq;
public class Program
{
static readonly Random _random = new System.Random(Environment.TickCount);
const string dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklpmnopqrstuvwxyz0123456789!##$%^&*()_+-=";
static string GetPassword(int length)
{
return new String
(
dictionary
.OrderBy( a => _random.NextDouble() )
.Take(length)
.ToArray()
);
}
public static void Main()
{
var s = GetPassword(30);
Console.WriteLine(s);
}
}
In this example we treat the string as an Enumerable<char> (yes, this is allowed) and use LINQ methods to sort it randomly and take the first n characters. We then pass the results to the constructor for a new System.String containing the answer.
Sample output:
Run #1:
!#t(hfTz0rB5cvKy1d$oeVI2mnsCba
Run #2:
y7Y(MB1pWH$wO5XPD0b+%Rkn9a4F!_
Run #3:
tH92lnh*sL+WOaTYR160&xiZpC5#G3
Looks pretty random to me.
Controlled repetition
The above solution of course only allows at most one instance of each character in the dictionary. But maybe you want them to be able to appear more than once, but not too much. If you'd like a controlled, limited number of possible repeats, you can make a small change:
static string GetPassword(int length, int maxRepeats)
{
return new String
(
Enumerable.Range(0, maxRepeats)
.SelectMany( i => dictionary )
.OrderBy( a => _random.NextDouble() )
.Take(length)
.ToArray()
);
}
In this example we clone the dictionary maxRepeats times and concatenate them using SelectMany. Then we sort that gigantic string randomly and take the first n characters for the password.
Working code on .NET Fiddle
The System.Random class is not designed to be a strong RNG, it is designed to be a fast RNG. If you want a quality random number generator you need to use one based on the System.Security.Cryptography.RandomNumberGenerator class.
Here is a gist I found that uses a crypto random generator as the internals of the existing random class.
Running it with the new generator gives me
mm77D5EDjO0OhOOe8kppiY0toc0HWQjpo37b4LFj56LvcQvA4jE83J8BS8xeX6zcEr2Od8A70v2xFKiY0ROY3gN105rZt6PE8F2i
which you can see appears to not have the biases you found.
I want to make a function which has an alarm execute at the arbitrary time on everyday... I use c#.
I can not find proper method or code. I think I could use timer or rand method, but it happens regular time.
Here is the code:
class Program
{
static void Main(string[] args)
{
int i, k;
int j;
Console.WriteLine("가위는 0, 바위는 1, 보는 2 선택 => ");
string ReadValue = Console.ReadLine();
j = Convert.ToInt32(ReadValue);
k = new Random().Next() % 3;
if(k == 0 && j == 1 || k == 1 && j == 2 || k == 2 && j == 0)
{
Console.WriteLine("플레이어 승! \n");
}
else if(k == j)
{
Console.WriteLine("무승부! \n");
}
else{
Console.WriteLine("플레이어 패배! \n");
}
}
}
Your question is vague one. There're many possible implementations depending on what you actually want. The simplest one, IMHO, is to wait:
private static Random random = new Random();
static void Main(string[] args)
{
while (true)
{
// from 10 seconds up to 1 day;
int timeToWait = random.Next(10, 86400) * 1000;
Thread.Sleep(timeToWait);
Alarm();
}
}
static void Alarm()
{
Console.WriteLine("Alarm!");
}
You're using the Random in the wrong way. You should have a Random r = new Random(); outside a loop that is executing your method and inside the loop a k=r.Next();.
Random(seed) with the same seed always return the same value. You either have to do what I said above, or modify the seed every execution, but for this, you need a random value!. I recommend you to read the Random reference: https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx
I got a strange C# programming problem. There is a data retrieval in groups of random lengths of number groups. The numbers should be all unique, like:
group[1]{1,2,15};
group[2]{3,4,7,33,22,100};
group[3]{11,12,9};
// Now there is a routine that adds a number to a group.
// For the example, just imagine the active group looks like:
// group[active]=(10,5,0)
group[active].add(new_number);
// Now if 100 were to be added to the active group
// then the active group should be merged to group[2]
// (as that one already contained 100)
// And then as a result it would like
group[1]{1,2,15};
group[2]{3,4,7,33,22,100,10,5,0}; // 10 5 0 added to group[2]
group[3]{11,12,9};
// 100 wasn't added to group[2] since it was already in there.
If the number to be added is already used (not unique) in a previous group.
Then I should merge all numbers in the active group towards that previous group, so I don’t get double numbers.
So in the above example if number 100 was added to the active
group, then all numbers in the group[active] should be merged into group[2].
And then the group[active] should start clean fresh again without any items. And since 100 was already in group[2] it should not be added double.
I am not entirely sure on how to deal with this in a proper way.
As an important criteria here is that it has to work fast.
I will have around minimal 30 groups (upper-bound unknown might be 2000 or more), and their length on average contains five integer numbers, but it could be much longer or only one number.
I kind of feel that I am reinventing the wheel here.
I wonder what this problem is called (does it go by a name, some sorting, or grouping math problem)?, with a name I might find some articles related to such problems.
But maybe it’s indeed something new, then what would be recommended? Should I use list of lists or a dictionary of lists.. or something else? Somehow the checking if the number is already present should be done fast.
I'm thinking along this path now and am not sure if it’s the best.
Instead of a single number, I use a struct now. It wasn't written in the original question as I was afraid, explaining that would make it too complex.
struct data{int ID; int additionalNumber}
Dictionary <int,List<data>> group =new Dictionary<int, List<data>>();
I can step aside from using a struct in here. A lookup list could connect the other data to the proper index. So this makes it again more close to the original description.
On a side note, great answers are given.
So far I don’t know yet what would work best for me in my situation.
Note on the selected answer
Several answers were given here, but I went for the pure dictionary solution.
Just as a note for people in similar problem scenarios: I'd still recommend testing, and maybe the others work better for you. It’s just that in my case currently it worked best. The code was also quite short which I liked, and a dictionary adds also other handy options for my future coding on this.
I would go with Dictionary<int, HashSet<int>>, since you want to avoid duplicates and want a fast way to check if given number already exists:
Usage example:
var groups = new Dictionary<int, HashSet<int>>();
// populate the groups
groups[1] = new HashSet<int>(new[] { 1,2,15 });
groups[2] = new HashSet<int>(new[] { 3,4,7,33,22,100 });
int number = 5;
int groupId = 4;
bool numberExists = groups.Values.Any(x => x.Contains(number));
// if there is already a group that contains the number
// merge it with the current group and add the new number
if (numberExists)
{
var group = groups.First(kvp => kvp.Value.Contains(number));
groups[group.Key].UnionWith(groups[groupId]);
groups[groupId] = new HashSet<int>();
}
// otherwise just add the new number
else
{
groups[groupId].Add(number);
}
From what I gather you want to iteratively assign numbers to groups satisfying these conditions:
Each number can be contained in only one of the groups
Groups are sets (numbers can occur only once in given group)
If number n exists in group g and we try to add it to group g', all numbers from g' should be transferred to g instead (avoiding repetitions in g)
Although approaches utilizing Dictionary<int, HashSet<int>> are correct, here's another one (more mathematically based).
You could simply maintain a Dictionary<int, int>, in which the key would be the number, and the corresponding value would indicate the group, to which that number belongs (this stems from condition 1.). And here's the add routine:
//let's assume dict is a reference to the dictionary
//k is a number, and g is a group
void AddNumber(int k, int g)
{
//if k already has assigned a group, we assign all numbers from g
//to k's group (which should be O(n))
if(dict.ContainsKey(k) && dict[k] != g)
{
foreach(var keyValuePair in dict.Where(kvp => kvp.Value == g).ToList())
dict[keyValuePair.Key] = dict[k];
}
//otherwise simply assign number k to group g (which should be O(1))
else
{
dict[k] = g;
}
}
Notice that from a mathematical point of view what you want to model is a function from a set of numbers to a set of groups.
I have kept it as easy to follow as I can, trying not to impact the speed or deviate from the spec.
Create a class called Groups.cs and copy and paste this code into it:
using System;
using System.Collections.Generic;
namespace XXXNAMESPACEXXX
{
public static class Groups
{
public static List<List<int>> group { get; set; }
public static int active { get; set; }
public static void AddNumberToGroup(int numberToAdd, int groupToAddItTo)
{
try
{
if (group == null)
{
group = new List<List<int>>();
}
while (group.Count < groupToAddItTo)
{
group.Add(new List<int>());
}
int IndexOfListToRefresh = -1;
List<int> NumbersToMove = new List<int>();
foreach (List<int> Numbers in group)
{
if (Numbers.Contains(numberToAdd) && (group.IndexOf(Numbers) + 1) != groupToAddItTo)
{
active = group.IndexOf(Numbers) + 1;
IndexOfListToRefresh = group.IndexOf(Numbers);
foreach (int Number in Numbers)
{
NumbersToMove.Add(Number);
}
}
}
foreach (int Number in NumbersToMove)
{
if (!group[groupToAddItTo - 1].Contains(Number))
{
group[groupToAddItTo - 1].Add(Number);
}
}
if (!group[groupToAddItTo - 1].Contains(numberToAdd))
{
group[groupToAddItTo - 1].Add(numberToAdd);
}
if (IndexOfListToRefresh != -1)
{
group[IndexOfListToRefresh] = new List<int>();
}
}
catch//(Exception ex)
{
//Exception handling here
}
}
public static string GetString()
{
string MethodResult = "";
try
{
string Working = "";
bool FirstPass = true;
foreach (List<int> Numbers in group)
{
if (!FirstPass)
{
Working += "\r\n";
}
else
{
FirstPass = false;
}
Working += "group[" + (group.IndexOf(Numbers) + 1) + "]{";
bool InnerFirstPass = true;
foreach (int Number in Numbers)
{
if (!InnerFirstPass)
{
Working += ", ";
}
else
{
InnerFirstPass = false;
}
Working += Number.ToString();
}
Working += "};";
if ((active - 1) == group.IndexOf(Numbers))
{
Working += " //<active>";
}
}
MethodResult = Working;
}
catch//(Exception ex)
{
//Exception handling here
}
return MethodResult;
}
}
}
I don't know if foreach is more or less efficient than standard for loops, so I have made an alternative version that uses standard for loops:
using System;
using System.Collections.Generic;
namespace XXXNAMESPACEXXX
{
public static class Groups
{
public static List<List<int>> group { get; set; }
public static int active { get; set; }
public static void AddNumberToGroup(int numberToAdd, int groupToAddItTo)
{
try
{
if (group == null)
{
group = new List<List<int>>();
}
while (group.Count < groupToAddItTo)
{
group.Add(new List<int>());
}
int IndexOfListToRefresh = -1;
List<int> NumbersToMove = new List<int>();
for(int i = 0; i < group.Count; i++)
{
List<int> Numbers = group[i];
int IndexOfNumbers = group.IndexOf(Numbers) + 1;
if (Numbers.Contains(numberToAdd) && IndexOfNumbers != groupToAddItTo)
{
active = IndexOfNumbers;
IndexOfListToRefresh = IndexOfNumbers - 1;
for (int j = 0; j < Numbers.Count; j++)
{
int Number = NumbersToMove[j];
NumbersToMove.Add(Number);
}
}
}
for(int i = 0; i < NumbersToMove.Count; i++)
{
int Number = NumbersToMove[i];
if (!group[groupToAddItTo - 1].Contains(Number))
{
group[groupToAddItTo - 1].Add(Number);
}
}
if (!group[groupToAddItTo - 1].Contains(numberToAdd))
{
group[groupToAddItTo - 1].Add(numberToAdd);
}
if (IndexOfListToRefresh != -1)
{
group[IndexOfListToRefresh] = new List<int>();
}
}
catch//(Exception ex)
{
//Exception handling here
}
}
public static string GetString()
{
string MethodResult = "";
try
{
string Working = "";
bool FirstPass = true;
for(int i = 0; i < group.Count; i++)
{
List<int> Numbers = group[i];
if (!FirstPass)
{
Working += "\r\n";
}
else
{
FirstPass = false;
}
Working += "group[" + (group.IndexOf(Numbers) + 1) + "]{";
bool InnerFirstPass = true;
for(int j = 0; j < Numbers.Count; j++)
{
int Number = Numbers[j];
if (!InnerFirstPass)
{
Working += ", ";
}
else
{
InnerFirstPass = false;
}
Working += Number.ToString();
}
Working += "};";
if ((active - 1) == group.IndexOf(Numbers))
{
Working += " //<active>";
}
}
MethodResult = Working;
}
catch//(Exception ex)
{
//Exception handling here
}
return MethodResult;
}
}
}
Both implimentations contain the group variable and two methods, which are; AddNumberToGroup and GetString, where GetString is used to check the current status of the group variable.
Note: You'll need to replace XXXNAMESPACEXXX with the Namespace of your project. Hint: Take this from another class.
When adding an item to your List, do this:
int NumberToAdd = 10;
int GroupToAddItTo = 2;
AddNumberToGroup(NumberToAdd, GroupToAddItTo);
...or...
AddNumberToGroup(10, 2);
In the example above, I am adding the number 10 to group 2.
Test the speed with the following:
DateTime StartTime = DateTime.Now;
int NumberOfTimesToRepeatTest = 1000;
for (int i = 0; i < NumberOfTimesToRepeatTest; i++)
{
Groups.AddNumberToGroup(4, 1);
Groups.AddNumberToGroup(3, 1);
Groups.AddNumberToGroup(8, 2);
Groups.AddNumberToGroup(5, 2);
Groups.AddNumberToGroup(7, 3);
Groups.AddNumberToGroup(3, 3);
Groups.AddNumberToGroup(8, 4);
Groups.AddNumberToGroup(43, 4);
Groups.AddNumberToGroup(100, 5);
Groups.AddNumberToGroup(1, 5);
Groups.AddNumberToGroup(5, 6);
Groups.AddNumberToGroup(78, 6);
Groups.AddNumberToGroup(34, 7);
Groups.AddNumberToGroup(456, 7);
Groups.AddNumberToGroup(456, 8);
Groups.AddNumberToGroup(7, 8);
Groups.AddNumberToGroup(7, 9);
}
long MillisecondsTaken = DateTime.Now.Ticks - StartTime.Ticks;
Console.WriteLine(Groups.GetString());
Console.WriteLine("Process took: " + MillisecondsTaken);
I think this is what you need. Let me know if I misunderstood anything in the question.
As far as I can tell it's brilliant, it's fast and it's tested.
Enjoy!
...and one more thing:
For the little windows interface app, I just created a simple winforms app with three textboxes (one set to multiline) and a button.
Then, after adding the Groups class above, in the button-click event I wrote the following:
private void BtnAdd_Click(object sender, EventArgs e)
{
try
{
int Group = int.Parse(TxtGroup.Text);
int Number = int.Parse(TxtNumber.Text);
Groups.AddNumberToGroup(Number, Group);
TxtOutput.Text = Groups.GetString();
}
catch//(Exception ex)
{
//Exception handling here
}
}
I am writing dice roller program in C# console. I am giving two input
Enter the size of the dice and
Enter how times you want to play.
Suppose dice size is 6 and 10 times i have played.
Output is coming:
1 was rolled 2 times
2 was rolled 7 times
3 was rolled 8 times
4 was rolled 7 times
5 was rolled 4 times
6 was rolled 5 times
Total: 33 (its not fixed for every execution this no will be changed)
But my requirement was this total always should be number of playing times. Here I am playing 10 times so the total should be 10 not 33. It should happen for every new numbers... If I play 100 times sum or total should be 100 only not any other number. rest all will be remain same, in my programing not getting the expected sum. Please somebody modify it. Here is my code:
Dice.cs:
public class Dice
{
Int32 _DiceSize;
public Int32 _NoOfDice;
public Dice(Int32 dicesize)
{
this._DiceSize = dicesize;
}
public string Roll()
{
if (_DiceSize<= 0)
{
throw new ApplicationException("Dice Size cant be less than 0 or 0");
}
if (_NoOfDice <= 0)
{
throw new ApplicationException("No of dice cant be less than 0 or 0");
}
Random rnd = new Random();
Int32[] roll = new Int32[_DiceSize];
for (Int32 i = 0; i < _DiceSize; i++)
{
roll[i] = rnd.Next(1,_NoOfDice);
}
StringBuilder result = new StringBuilder();
Int32 Total = 0;
Console.WriteLine("Rolling.......");
for (Int32 i = 0; i < roll.Length; i++)
{
Total += roll[i];
result.AppendFormat("{0}:\t was rolled\t{1}\t times\n", i + 1, roll[i]);
}
result.AppendFormat("\t\t\t......\n");
result.AppendFormat("TOTAL: {0}", Total);
return result.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter no of dice size");
int dicesize = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("How many times want to play");
int noofplay=Convert.ToInt32(Console.ReadLine());
Dice obj = new Dice(dicesize);
obj._NoOfDice = noofplay;
obj.Roll();
Console.WriteLine(obj.Roll());
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}
It looks to me like you're getting the math backwards... shouldn't it be:
// to capture just the counts
int[] roll = new int[_DiceSize];
for (int i = 0; i < _NoOfDice; i++)
{
roll[rnd.Next(roll.Length)]++;
}
Or if you want the actual rolls:
// to capture individual rolls
int[] roll = new int[_NoOfDice];
for (int i = 0; i < _NoOfDice; i++)
{
roll[i] = rnd.Next(_DiceSize) + 1; // note upper bound is exclusive, so +1
}
You are creating a new Random instance on each iteration. This is not a good thing as it will affect the uniform distribution of results. Keep the Random instance in a field instead of creating a new one every time.
public class Dice {
private Random rnd = new Random();
// ... don't create a new random in `Roll` method. Use `rnd` directly.
}
First of all, the following for-loop is wrong:
for (Int32 i = 0; i < _DiceSize; i++)
{
roll[i] = rnd.Next(1,_NoOfDice);
}
Obviously you switched _DiceSize and _NoOfDice. The correct loop would look like
for (Int32 i = 0; i < _NoOfDice; i++)
{
roll[i] = rnd.Next(1,_DiceSize);
}
Because of that, the line
Int32[] roll = new Int32[_DiceSize];
has to be changed to
Int32[] roll = new Int32[_NoOfDice];
Maybe you should think about renaming these variables, so it's more clearly, which means what.
If you modify your code that way, you will mention that your analisys won't work that way you implemented it. Actually, what you are showing is the result of each throw, which is not what you want, if I understood you right.
UPDATE:
Sorry, I misunderstood you. You do want to show the result for every roll. So, why don't you just move the StringBuilder.AppendFormat to your "rolling-for-loop"?
UPDATE #2:
For me, the following Die-class works exactly the way you want it:
public class Die
{
private int maxValue;
private int numberOfRolls;
private Random random;
public Die(int maxValue, int numberOfRolls)
{
this.maxValue = maxValue;
this.numberOfRolls = numberOfRolls;
this.random = new Random();
}
public string Roll()
{
StringBuilder resultString = new StringBuilder();
for (int i = 0; i < this.numberOfRolls; i++)
{
resultString.AppendFormat("Roll #{0} - Result: {1}" + Environment.NewLine, i + 1, this.random.Next(1, maxValue + 1));
}
return resultString.ToString();
}
}
Hope I could help you.
This is the full code you have to use, according to Mehrdad and Marc Gravell.
Have fun.
public class Dice
{
private Random rnd = new Random();
Int32 _DiceSize;
public Int32 _NoOfDice;
public Dice(Int32 dicesize)
{
if (dicesize <= 0)
{
throw new ApplicationException("Dice Size cant be less than 0 or 0");
}
this._DiceSize = dicesize;
}
public string Roll()
{
if (_NoOfDice <= 0)
{
throw new ApplicationException("No of dice cant be less than 0 or 0");
}
// to capture just the counts
int[] roll = new int[_DiceSize];
for (int i = 0; i < _NoOfDice; i++)
{
roll[rnd.Next(roll.Length)]++;
}
StringBuilder result = new StringBuilder();
Int32 Total = 0;
Console.WriteLine("Rolling.......");
for (Int32 i = 0; i < roll.Length; i++)
{
Total += roll[i];
result.AppendFormat("{0}:\t was rolled\t{1}\t times\n", i + 1, roll[i]);
}
result.AppendFormat("\t\t\t......\n");
result.AppendFormat("TOTAL: {0}", Total);
return result.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter no of dice size");
int dicesize = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("How many times want to play");
int noofplay = Convert.ToInt32(Console.ReadLine());
Dice obj = new Dice(dicesize);
obj._NoOfDice = noofplay;
Console.WriteLine(obj.Roll());
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}