How to skip values in Random.Range? In Unity/C#? - c#

facing issue with randomising the randomLetter for non latin script. in my script, in the unicode characters table, 4 unicode values are non existent. need to skip those characters while Random.Range() is running. what is the workaround? declare an array? or declare a list? or something else? please help.
Working code for Latin script:
{
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 26);
_randomLetter = (char) ('a' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}
Bengali script code:
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 16); //12 vowels in bengali but here 16 as range including non-existent values
_randomLetter = (char) ('অ' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}

easiest way is to build a list of all the allowed characters, and generate a random index into this list. Note that a string can be used like a list of characters.
const string allowedCharacters = "abe";
var randomIndex = UnityEngine.Random.Range(0,allowedCharacters.Length);
var randomCharacter = allowedCharacters[randomIndex];
Another easy way is to use rejection sampling

Related

Why wont this loop end? I've looked at it for ages and can't find the problem

Console.Write("Enter a string to encode: ");
string input = Console.ReadLine();
Random r = new Random();
char[] characters = " ~!##$%^&*()_+=-0987654321`{}|\\][\"';:/?.>,<QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".ToCharArray();
string method = "";
bool f = true;
while (method.Length != characters.Length)
{
string cc = "";
while (method.Contains(cc) || f)
{
cc = characters[r.Next(0, characters.Length - 1)].ToString();
f = false;
// Console.WriteLine(method.Length);
// Console.WriteLine(characters.Length);
}
method = method + cc;
}
I'm trying to make method's value a randomized version of the characters array.
I've looked at this for a while and I haven't found the problem.
Compiling the code and printing the length of the two variables shows that method is always 1 less character than characters's length
It might be obvious to some, although I'm absolutely scrambled.
Any help would be appreciated, thanks.
The second parameter of Random.Next is an exclusive upper bound. You need this:
cc = characters[r.Next(0, characters.Length)].ToString();
Now, just as a side-note, to create a string that is a random shuffle of the array characters you can do it this way:
string method = new string(characters.OrderBy(_ => r.Next()).ToArray());
As enigmativity points out the second argument of Random.Next is an exclusive upper bound, meaning the function Random.Next(0, N) will return a value between 0 and N-1.
Therefore, after numerous random samples your code will eventually be set to method to contain all characters except m because m is the char at index characters.length-1.
To accomplish your task:
Change cc = characters[r.Next(0, characters.Length - 1)].ToString(); to cc = characters[r.Next(0, characters.Length)].ToString();
Also, note that as you have fewer and fewer characters left that you have not yet chose, you will be picking many random characters you have already chose which is inefficient. Worse, the algorithm runs an outer loop which requires an array search to see if you have already chosen the character. This repeats until by random chance a character is selected that has not been chosen.
To address the issues in 2), simply keep a list of unused characters. As you randomly select each characters remove it from the list of unused characters. This will allow your algorithm to complete in 0(N) time where N is the length of total characters.
Here is example code:
Console.Write("Enter a string to encode: ");
string input = Console.ReadLine();
Random r = new Random();
char[] characters = " ~!##$%^&*()_+=-0987654321`{}|\\][\"';:/?.>,<QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".ToCharArray();
string method = "";
bool f = true;
var unused = characters.ToList();
while (method.Length != characters.Length)
{
char cc = unused[r.Next(0, unused.Count)];
method = method + cc;
unused.Remove(cc);
}
https://stackoverflow.com/users/259769/enigmativity

C# encrypt string

I got the following code to encrypt a string.
private void Crypt(int n, int m, int d)
{
n = Convert.ToInt32(n);
m = Convert.ToInt32(m);
d = Convert.ToInt32(d);
// make a block from the string
string invoerstring = invoer.Text;
int stringlength = invoerstring.Length;
var blok = invoer.Text.PadRight(stringlength, ' ').Substring(0, stringlength);
// the letters are shifted d times
char [] buf = invoerstring.ToArray<char>();
foreach (char c in buf)
{
var letter = uitvoer.Text += (char)( c + (char)d);
}
// shift characters inside a block
var shift = String.Concat(invoerstring.Skip(m).Concat(invoerstring.Take(m)));
uitvoer.Text = shift;
}
private void button1_Click(object sender, EventArgs e)
{
Crypt(8,2,1);
}
private void clearbutton_Click(object sender, EventArgs e)
{
invoer.Text = "";
uitvoer.Text = "";
}
}
}
This is the explanation of the exercise:
crypt n m d text
text is padded with spaces until its length is a multiple of n
the characters in text are circulary shifted in the alphabet by the displacement d
example: if d = 1 then 'a' -> 'b' , 'b' -> 'c' .... etc... 'z' -> 'a'
text is divided in blocks of length n characters
inside every block of n the characters are circulary shifted m times to the left
the shifted groups are concatenated
When I run my code the letters aren't shifted d times. For example the string:
"aap noot mies" has to change to "q oppubbjft n" (When Crypt is Crypt(8,2,1)). What do I need to change to get this result?
You have many problems/oddities:
You're Converting a bunch of ints to Int32s, but the former is just syntatic sugar for the latter.
Your PadRight call is going to return the initial string since the length you pass is equal to the length of the string.
Your Substring call is going to return the initial string.
You never use blok.
You never actually split the input into blocks or pad it.
string already implements IEnumerable (a fact you're already implicitly using), so there's no need to convert it to an array just to loop over it.
You never use letter.
(char)( c + (char)d) does not implement the Caeser cipher you're looking for, you'll end up converting some letters into non-letters (except in one degenerate case).
You're concatenating the result of the shift into uitvoer.Text (without clearing it) and then overwriting it later without using it.
You're calling the single parameter static version of Concat (which converts the object it's passed into a string) and passing it a string.
Start by fixing the ones you know how to do and edit the question if you get stuck.

A good way to check a chars 'integrity'

I'm working on making my own password generator; and I want it to create passwords that contain numbers, lowercase-letters, and uppercase-letters.
I am writing the program in C#, using Visual Studio.
Say I use the code below:
Random Rand = new Random();
Char C = Convert.ToChar(Rand.Next(0x30, 0x5A));
How could I make my program check whether (C) is equal to a number or a uppercase-letter?
Use Char.IsDigit (for decimal digits), or Char.IsNumber and Char.IsUpper.
These are all static methods defined on the Char structure.
An example, as requested:
if(Char.IsNumber(C))
{
// Character is marked as a unicode number
}
you can check if:
int ordinal = (int)C;
if(( ordinal >= 65 && ordinal <= 90 ) || (ordinal >= 48 && ordinal <= 57))
{
Console.WriteLine( C + " is an uppercase A-Z or 0-9!" );
}
A better (and standard) way, is to create an 'alphabet' string of allowable characters and then generate a random index into the string, to select an allowable character.
Much better than first generating a random character and then checking if it is allowable.
"0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Note the removed lowercase 'l' (looks like 1). You should remove any others such as zero versus 'O' possibly...or whatever your password rules allow)
Here's an example of using this technique to generate random strings:
public static class RandomUtils
{
private static readonly Random random = new Random();
public static string GenerateRandomAlphaNumericString(int length)
{
const string alpha =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return GenerateRandomString(length, alpha);
}
public static string GenerateRandomString(int length, string alphabet)
{
int maxlen = alphabet.Length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++)
{
sb.Append(alphabet[random.Next(0, maxlen)]);
}
return sb.ToString();
}
}
Probably just use Char.IsNumber and Char.IsUpper methods:
see:
http://msdn.microsoft.com/en-us/library/9s91f3by.aspx
http://msdn.microsoft.com/en-us/library/yk2b3t2y.aspx
if (C.IsNumber || C.IsUpper)
{
// password code!
}
(don't write your own password generator, unless it's just for fun though).

C# : How to generate unique passwords with the length of 7 or 8 characters

I need to repeated generate unique password many times, Ensure that every time the generated passwords are unique, Please help me.
Thanks!
So here is another method which generates cryptedRandom password and a thread safe...
private string CryptedRandomString()
{
lock (this)
{
int rand = 0;
byte[] randomNumber = new byte[5];
RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider();
Gen.GetBytes(randomNumber);
rand = Math.Abs(BitConverter.ToInt32(randomNumber, 0));
return ConvertIntToStr(rand);
}
}
private string ConvertIntToStr(int input)
{
lock (this)
{
string output = "";
while (input > 0)
{
int current = input % 10;
input /= 10;
if (current == 0)
current = 10;
output = (char)((char)'A' + (current - 1)) + output;
}
return output;
}
}
Now you can call this method like this: -
string GeneratedPassword = "";
GeneratedPassword = CryptedRandomString() + CryptedRandomString();
Console.WriteLine(GeneratedPassword.Substring(0,8));
Now you all must be wondering why GeneratedPassword = CryptedRandomString() + CryptedRandomString(); , the reason I called CryptedRamdomString() method twice is just to make sure it returns more then 10 digits so as it will be easier to get eight character passwords otherwise if it is called once then sometimes it will generate less then eight character password.
Well you must consider one thing before using this method that generating random numbers using "RNGCryptoServiceProvider " is bit time consuming then Random.Next. But "RNGCryptoServiceProvider " is much more secure then "Random.Next" .
If you want to generate uniq password every time than
take CurrentTIME and CurrrentDATE in account because by this you can able to create new password.
have look to this resolve your problem : generating a batch of random passwords
Try this
http://www.yetanotherchris.me/home/2009/3/15/c-pronounceable-password-generator.html
I'd define an array of possible characters for the password alphabet, and then generate 7 or 8 random indexes into that array to create a password.
This would need to be refined if you want to guarantee a minimum number of each character type, etc.
Globally unique strings you say?
System.Guid.NewGuid().ToString()

Get the letters (ABCDE) between two letters (AE) using C#

I need to get the letters as an array on passing two letters using C#
For ex.: When i pass "AE", i need to get the {A,B,C,D,E} as an array. and passing "FJ" should return {F,G,H,I,J}.
The Enumerable class can create a range, which makes the looping simple:
public static char[] CharactersBetween(char start, char end) {
return Enumerable.Range(start, end - start + 1).Select(c => (char)c).ToArray();
}
Note: A char value converts implicitly into int, so there is no conversion needed in that direction. You only have to convert the integers back to char.
Edit:
If you want to send in the alphabet to use (to handle language differences), you can use Substring to get a part of that string:
public static char[] CharactersBetween(char start, char end, string alphabet) {
int idx = alphabet.IndexOf(start);
return alphabet.Substring(idx, alphabet.IndexOf(end) - idx + 1).ToCharArray();
}
Do you mean something like
char[] CharactersBetween(char start, char end)
{
List<char> result = new List<char>();
for (char i = start; i <= end; i++)
{
result.Add(i);
}
return result.ToArray();
}
This should work out well
string startandend = "AG";
string result= "";
for( char i = startandend[0]; i <= startandend[1]; i++){
result += i;
}
result will now contain ABCDEFG.
You should probably add some logic to check if startandend actually have a Length of 2 and so on, but this should be a good starting block for you.
If you want the char[] instead of the string representation, simply call result.ToCharArray() at the end.
Use a loop with integer conversion
with
System.Convert.ToInt32(Char);
and
System.Convert.ToChar(Int32);
see http://msdn.microsoft.com/en-us/library/system.convert_methods.aspx
Pretty simple if you use a fixed alphabet,
public static string ALPHABET = "ABCDEFGHIJKLMNOPWRSTUVWXYZ";
public static List<char> GetLetters(string firstLast)
{
List<char> letters = new List<char>();
int start = ALPHABET.IndexOf(firstLast[0]);
int end = ALPHABET.IndexOf(firstLast[1]);
for (int i = start; i <= end; i++)
{
letters.Add(ALPHABET[i]);
}
return letters;
}
Obviously add in your checks for various things, but it does the basic job.
You're going to have to reference whichever alphabet you want to use. English is easy enough as the letters happen to correspond to code-point order, French treats Œ and Æ as letters in their own right sometimes, and not others. Danish and Norwegian place "Æ, Ø, Å" after Z and Swedish does the same with "Å, Ä, Ö". Irish uses "ABCDEFGHILMNOPRSTU" as the alphabet, but does also use J, K, Q, V, W, X, Y & Z in loan words.
And those are relatively easy cases. So there's no one-size-fits-all.
The easiest way to pass an alphabet is to have a string that contains it. So, e.g. the Danish alphabet would have the string "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" while French could either include the ligatures or not as you wish (but do you need to deal with the possibility of receiving them while not using them?).
This done:
public static IEnumerable<char> AlphabetRange(string alphabet, string alphaRange)
{
if(alphaRange == null)
throw new ArgumentNullException();
if(alphaRange.Length < 2)
throw new ArgumentException();
int startIdx = alphabet.IndexOf(alphaRange[0]);
int endIdx = alphabet.IndexOf(alphaRange[1]) + 1;
if(startIdx == -1 || endIdx == 0)
throw new ArgumentException();
while(startIdx < endIdx)
yield return alphabet[startIdx++];
}

Categories

Resources