Hi guys just carrying on working on my first app, done mainly to learn and nothing else. I want the user to be able to type in 2d6+4 OR 2d6, you should be able to substitute those numbers for any number. I'm getting errors parsing the information and I think it has something to do with the array containing more or less values than I anticipated, or it for some reason left the delimiter in. typing 2d6+4 or 2d6 +4 works fine, 2d6 however does not, which is what I thought the if statement should guard against. Any ideas?
Console.WriteLine("Please type the roll you would like to perform, for example - 2d6+4");
var rollLine = Console.ReadLine();
var diceLine = rollLine.Split(new Char[] { 'd', '+' }, StringSplitOptions.RemoveEmptyEntries);
diceCount = int.Parse(diceLine[0]);
diceType = int.Parse(diceLine[1]);
if (rollLine.Length > 2)
{
bonus = int.Parse(diceLine[2]);
}
else
{
bonus = 0;
}
It looks like you are just using the wrong variable for the length comparison. You are comparing the length of the string, not the length of the split array. It should be:
if (diceLine.Length > 2)
When user entered "2d6", the string length is 3, i.e. following rule is true
if (rollLine.Length > 2)
However, as per your logic you will get array of 2 items in the diceLine, i.e. diceLine[0] and diceLine[1] but after condition with length you call diceLine[2] that does not exist.
I.e. either change condition to
if (rollLine.Length == 5) // 2d6+4
or check for the length of the array
if (diceLine.Length > 2)
You want your IF to check if the rollLine length is greater than 3, not 2.
As the smallest thing you'll type in is, for example, 2d6, you want to check for the bonus only when the rollLine is more than 3 characters.
if (rollLine.Length > 3)
{
bonus = int.Parse(diceLine[2]);
}
Related
Please help me with this interview question I faced recently, every help will be appreciated.
Please implement in C# the function that increments a string based on below rules:
It should take the string of unknown length and increment the numeric ending of that string by 1.
If numeric ending is overflown it must be reset
Don't use regular expressions.
Examples:
000002 ▶ 000003
DRI000EDERS0RE99999 ▶ DRI000EDERS0RE00000
Few ways to skin this cat. I think I would actually rely on c# ability to treat char like int, and manipulate the characters rather than trying to parse an int out of it, increment it then format it back
string s = "abcd999";
string ca = s.ToCharArray();
for(int i = ca.Length - 1; i>= 0 && char.IsDigit(ca[i]); i--){
if(ca[i] == '9')
ca[i] = '0';
else {
ca[i]++;
break;
}
}
return new string(ca);
We turn the string into a char array for easy manipulation then skip backwards over it from end to start. We want to stop looping when we hit a non digit or the string start. Then the logic is simple counting like a kid does. If we are on 9 we go back to 0 (the "bump up the next one will maybe be done by the next pass of the loop), otherwise we increment the char by one and quit:
4 becomes 5,
19 becomes 10 becomes 20,
abc9999 becomes abc9990 then abc9900 then abc9000 then abc0000 then the loop quits on the non digit c
I'm using a 2 step regex to extract the value of the first occurance of a specific marker inside a list of strings:
Regex regexComplete = new Regex(
#"MyNumberMarker"
+ #"[\d]+"
+ #"[\s]+Endmarker"
);
Regex regexOnlyNumber = new Regex(
#"MyNumberMarker"
+ #"[\d]+"
);
int indexmyNumber = eintraegeListe.FindIndex(
5,
10000,
x => regexComplete.IsMatch(x)
);
if (indexmyNumber >= 0)
{
int myNumber = 0;
string myNumberString = regexOnlyNumber.Match(regexComplete.Match(eintraegeListe[indexmyNumber]).Value).Value;
myNumberString = myNumberString.Replace("MyNumberMarker", "").Replace("\n", "").Replace("\r", "").Trim();
if (Int32.TryParse(myNumberString, out myNumber))
{
return myNumber;
}
}
As one can see the value I really want is located between "MyNumberMarker" and "Endmarker". It is in a specific part of the list which I search through with the findIndex command. Then I use regex to extract the complete value + tag and reduce it to "just" the begin tag and the value and then manually cut away the begin tag and all could be white spaces (including \n and \r).
Now this works quite fine as intended but if I do this a couple of thousand times it is quite slow in the end. Thus my question.
Is there any better (faster) way to do this?
As a note: eintraegeListe can have between 100 and 30000 entries.
For example if I have the following small list:
[0]This is a test
[1]22.09.2015 01:00:00
[2]Until 22.09.2015 03:00:00
[3]................................
[4]................................
[5]........ TESTDATA
[6]...............................
[7]................................
[8]MyNumberMarker519 Endmarker
[9]This is a small
[10]Slice of Test data with
[11]520 - 1 as data.
I would expect 519 to be returned.
Since you are returning a single item, the performance of code past FindIndex is irrelevant: it is executed only once, and it takes a single string, so it should complete in microseconds on any modern hardware.
The code that takes the bulk of CPU is in x => regexComplete.IsMatch(x) call. You can tell that this code is returning false most of the time, because the loop is over the first time it returns true.
This means that you should be optimizing for the negative case, i.e. returning false as soon as you can. One way to achieve this would be to look for "MyNumberMarker" before employing regex. If there is no marker, return false right away; otherwise, fall back on using the regex, and start from the position where you found the marker:
int indexmyNumber = eintraegeListe.FindIndex(
5,
10000,
x => {
// Scan the string for the marker in non-regex mode
int pos = x.IndexOf("MyNumberMarker", StringComparison.Ordinal);
// If the marker is not there, do not bother with regex, and return false
return pos < 0
? false
// Only if the marker is there, check the match with regex.
: regexComplete.IsMatch(x, pos);
}
);
You can actually merge the two regexps into 1 containing a capturing group that will let you access the sequence of digits directly via the group name (here, "number").
Regex regexComplete = new Regex(#"MyNumberMarker(?<number>\d+)\s+Endmarker");
Now, you do not need regexOnlyNumber.
Then, you can add a non-regex condition as in the other answer. Maybe this will be enough (the .Contains will be executed first and the whole expression should evaluate to false if the first condition is not met - see "short-circuit" evaluation) (IndexOf with StringComparison.Ordinal looks preferable anyway):
int indexmyNumber = eintraegeListe.FindIndex(5, 10000, x => x.Contains("MyNumberMarker") && regexComplete.IsMatch(x));
And then:
if (indexmyNumber >= 0)
{
int myNumber = 0;
string myNumberString = regexComplete.Match(eintraegeListe[indexmyNumber]).Groups["number"].Value;
if (Int32.TryParse(myNumberString, out myNumber))
{
return myNumber;
}
}
I have an array of repeating letters:
AABCCD
and I would like to put them into pseudo-random order. Simple right, just use Fisher-Yates => done. However there is a restriction on the output - I don't want any runs of the same letter. I want at least two other characters to appear before the same character reappears. For example:
ACCABD
is not valid because there are two Cs next to each other.
ABCACD
is also not valid because there are two C's next to each other (CAC) with only one other character (A) between them, I require at least two other characters.
Every valid sequence for this simple example:
ABCADC ABCDAC ACBACD ACBADC ACBDAC ACBDCA ACDABC ACDACB ACDBAC ACDBCA
ADCABC ADCBAC BACDAC BCADCA CABCAD CABCDA CABDAC CABDCA CADBAC CADBCA
CADCAB CADCBA CBACDA CBADCA CDABCA CDACBA DACBAC DCABCA
I used a brute force approach for this small array but my actual problem is arrays with hundreds of elements. I've tried using Fisher-Yates with some suppression - do normal Fisher-Yates and then if you don't like the character that comes up, try X more times for a better one. Generates valid sequences about 87% of the time only and is very slow. Wondering if there's a better approach. Obviously this isn't possible for all arrays. An array of just "AAB" has no valid order, so I'd like to fail down to the best available order of "ABA" for something like this.
Here is a modified Fisher-Yates approach. As I mentioned, it is very difficult to generate a valid sequence 100% of the time, because you have to check that you haven't trapped yourself by leaving only AAA at the end of your sequence.
It is possible to create a recursive CanBeSorted method, which tells you whether or not a sequence can be sorted according to your rules. That will be your basis for a full solution, but this function, which returns a boolean value indicating success or failure, should be a starting point.
public static bool Shuffle(char[] array)
{
var random = new Random();
var groups = array.ToDictionary(e => e, e => array.Count(v => v == e));
char last = '\0';
char lastButOne = '\0';
for (int i = array.Length; i > 1; i--)
{
var candidates = groups.Keys.Where(c => groups[c] > 0)
.Except(new[] { last, lastButOne }).ToList();
if (!candidates.Any())
return false;
var #char = candidates[random.Next(candidates.Count)];
var j = Array.IndexOf(array.Take(i).ToArray(), #char);
// Swap.
var tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
lastButOne = last;
last = #char;
groups[#char] = groups[#char] - 1;
}
return true;
}
Maintain a link list that will keep track of the letter and it's position in the result.
After getting the random number,Pick it's corresponding character from the input(same as Fisher-Yates) but now search in the list whether it has already occurred or not.
If not, insert the letter in the result and also in the link list with its position in the result.
If yes, then check it's position in the result(that you have stored in the link list when you have written that letter in result). Now compare this location with the current inserting location, If mod(currentlocation-previouslocation) is 3 or greater, you can insert that letter in the result otherwise not, if not choose the random number again.
Question is I have to make a console application where i input a number and it writes out symbol "|" as many i inserted. Example if i insert number 6 it writes out ||||||. And it keeps asking until I insert 0 and it closes. So far the input has been made like this :
int input;
Console.Write("\n\n Insert an number ---> ");
input = Convert.ToInt32(Console.ReadLine());
I have tried with char array but no use.
There is actually a constructor on string that initializes a string with the given character a certain number of times:
string s = new string('|', 10);
s will be the string "||||||||||"
Loops are so 2012 :)
using System;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
Enumerable.Range(0, Int32.MaxValue)
.Select(i => Int32.TryParse(Console.ReadLine(), out i) ? i : -1)
.Where(i => i >= 0)
.TakeWhile(i => i > 0)
.Select(i => {
Console.WriteLine(String.Join("", Enumerable.Repeat("|", i)));
return 0;})
.Count();
}
}
Description (even the answer is very non-serious):
Enumerable.Range is to allow semi-infinite (as Chris Sinclair pointed out it is only 2,147,483,647 times) enumerable to have most of the code in single statement.
First Select reads input line by line and convert valid input to integers, the rest to -1 (note that in this sample -1 is possible value for "invalid input", normally one would return Tuple<int, bool> or int? to signify invalid values
Where filters out "invalid" inputs (correctly entered negative numbers as well all non-numbers that where reported as -1 by previous Select).
TakeWhile provides termination condition for 0.
Second Select prints result. Note that to construct string from multiple copies of the same character one should use proper new String("|", count) constructor, but it less fun.
finally Count forces immediate iteration of the query.
pseudo code
is read line a number
until read line is 0
for 1 to the number
print |
is read line a number
if not a number go back at asking the number saying it is not a number
if not a number go back at asking the number saying it is not a number
now have fun doing your homework
tow basic concepts you should know
the for loop:
for(int i=0; i<input; i++)
{
// do stuff
}
This is a common patter for doing something input times, so if input is equal to 6, than it will //do stuff 6 times.
Console.Write
Console.Write('|');
Console.Write writes the text to the console without adding adding a new line at the end.
I'm sure that you can combine some of these language features somehow, to fulfill your requirement.
Implement an algorithm that takes two strings as input, and returns the intersection of the two, with each letter represented at most once.
Algo: (considering language used will be c#)
Convert both strings into char array
take the smaller array and generate a hash table for it with key as the character and value 0
Now Loop through the other array and increment the count in hash table if that char is present in it.
Now take out all char for hash table whose value is > 0.
These are intersection values.
This is an O(n), solution but is uses extra space, 2 char arrays and a hash table
Can you guys think of better solution than this?
How about this ...
var s1 = "aabbccccddd";
var s2 = "aabc";
var ans = s1.Intersect(s2);
Haven't tested this, but here's my thought:
Quicksort both strings in place, so you have an ordered sequence of characters
Keeping an index into both strings, compare the "next" character from each string, pick and output the first one, incrementing the index for that string.
Continue until you get to the end of one of the strings, then just pull unique values from the rest of the remaining string.
Won't use additional memory, only needs the two original strings, two integers, and an output string (or StringBuilder). As an added bonus, the output values will be sorted too!
Part 2:
This is what I'd write (sorry about the comments, new to stackoverflow):
private static string intersect(string left, string right)
{
StringBuilder theResult = new StringBuilder();
string sortedLeft = Program.sort(left);
string sortedRight = Program.sort(right);
int leftIndex = 0;
int rightIndex = 0;
// Work though the string with the "first last character".
if (sortedLeft[sortedLeft.Length - 1] > sortedRight[sortedRight.Length - 1])
{
string temp = sortedLeft;
sortedLeft = sortedRight;
sortedRight = temp;
}
char lastChar = default(char);
while (leftIndex < sortedLeft.Length)
{
char nextChar = (sortedLeft[leftIndex] <= sortedRight[rightIndex]) ? sortedLeft[leftIndex++] : sortedRight[rightIndex++];
if (lastChar == nextChar) continue;
theResult.Append(nextChar);
lastChar = nextChar;
}
// Add the remaining characters from the "right" string
while (rightIndex < sortedRight.Length)
{
char nextChar = sortedRight[rightIndex++];
if (lastChar == nextChar) continue;
theResult.Append(nextChar);
lastChar = nextChar;
}
theResult.Append(sortedRight, rightIndex, sortedRight.Length - rightIndex);
return (theResult.ToString());
}
I hope that makes more sense.
You don't need to 2 char arrays. The System.String data type has a built-in indexer by position that returns the char from that position, so you could just loop through from 0 to (String.Length - 1). If you're more interested in speed than optimizing storage space, then you could make a HashSet for the one of the strings, then make a second HashSet which will contain your final result. Then you iterate through the second string, testing each char against the first HashSet, and if it exists then add it the second HashSet. By the end, you already have a single HashSet with all the intersections, and save yourself the pass of running through the Hashtable looking for ones with a non-zero value.
EDIT: I entered this before all the comments on the question about not wanting to use any built-in containers at all
here's how I would do this. It's still O(N) and it doesn't use a hash table but instead one int array of length 26. (ideally)
make an array of 26 integers, each element for a letter of the alphebet. init to 0's.
iterate over the first string, decrementing one when a letter is encountered.
iterate over the second string and take the absolute of whatever is at the index corresponding to any letter you encounter. (edit: thanks to scwagner in comments)
return all letters corresponding to all indexes holding value greater than 0.
still O(N) and extra space of only 26 ints.
of course if you're not limited to only lower or uppercase characters your array size may need to change.
"with each letter represented at most once"
I'm assuming that this means you just need to know the intersections, and not how many times they occurred. If that's so then you can trim down your algorithm by making use of yield. Instead of storing the count and continuing to iterate the second string looking for additional matches, you can yield the intersection right there and continue to the next possible match from the first string.