Counter goes down by 4 at the time instead of one (C#) - c#

I am new at C# and after learning the basics I've decided that I wanna make a Hangman game. The problem is that a counter that normally counts down from 8 by 1 each time I miss a letter is counting down by 4 and I have no idea why.
static void Main(string[] args)
{
int Chances= 8;
bool key = false;
int N= 10;
char[] Word = { 'P', 'R', 'O', 'G', 'R', 'A', 'M' };
Console.WriteLine("The word is:_ _ _ _ _ _ _");
Console.Write("Please input a letter:");
while (key == false)
{
char letter = Convert.ToChar(Console.Read());
N = Numberofletter(letter);
Console.WriteLine(N);
while (N == 0 && Chances > 0)
{
Chances--;
Console.WriteLine("The letter is incorrect you have " + K + " tries Remaining");
letter = Convert.ToChar(Console.Read());
};
if (Chances == 0)
{
Console.WriteLine("Gameover");
return;
}
static int Numberofletter(char letter)
{
int N = 0;
char[] Word = { 'P', 'R', 'O', 'G', 'R', 'A', 'M' };
if (Word[0] == letter)
{ N = 1; }
else if (Word[1] == letter)
{ N = 2; }
else if (Word[2] == letter)
{ N = 3; }
else if (Word[3] == letter)
{ N = 4; }
else if (Word[5] == letter)
{ N = 6; }
else if (Word[6] == letter)
{ N = 7; }
else { N = 0; }
return N;
}

The problem is in your while loop.
You enter the loop with N = position of the guessed letter = 0.
INSIDE the loop, you ask for another letter, but NEVER calculate its position.
So even if the letter is in the word, you've never re-assigned the value of N. This means the loop will keep running and decrementing chances until chances < 0;
Simply add
N = Numberofletter(letter);
after you read in the next letter.

I don't know if anyone else will have the same problem as me but I will post my mistake here so at least I hope it will not be repeated
instead of letter=Convert.ToChar(Console.Read());
you should use letter=Convert.ToChar(Console.ReadLine());
i don't know why was that the problem but it happend try it out randomly and it worked

Related

How to move chars in char array to the left and to the right in c# sharp

guys! I have this situation: Given a string and two more characters X and Y. Move all X characters to the beginning of the string and all Y characters to the end of the string. The order of the other characters in the string remains unchanged.
I wrote two function MoveCharsLeft and MoveCharsRight to move X to the left and Y to the right, but there is an error System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' on this line of code char toReplace = splitText[charToCheck]; and I don't know how to handle it, in order to solve the exercise.
Can, you guys, help me with that, how should be the functions?
static void Main()
{
string text = Console.ReadLine();
char[] splitText = text.ToCharArray();
string firstLetter = Console.ReadLine();
char[] firstChar = firstLetter.ToCharArray();
string secondLetter = Console.ReadLine();
char[] secondChar = secondLetter.ToCharArray();
char one = firstChar[0];
char two = secondChar[0];
Console.WriteLine(CheckChars(splitText, one, two));
Console.ReadLine();
}
static char[] CheckChars(char[] splitText, char one, char two)
{
for (char letter = 'a'; letter <= 'z'; letter++)
{
if (Array.IndexOf(splitText, one) > -1)
{
MoveCharsLeft(splitText, one);
}
if (Array.IndexOf(splitText, two) > -1)
{
MoveCharsRight(splitText, two);
}
}
return splitText;
}
static void MoveCharsLeft(char[] splitText, char charToCheck)
{
char toReplace = splitText[charToCheck];
char currentLetter = splitText[0];
for (int i = 0; i <= charToCheck; i++)
{
char temporary = splitText[i];
splitText[i] = currentLetter;
currentLetter = temporary;
}
splitText[0] = toReplace;
}
static void MoveCharsRight(char[] splitText, char charToCheck)
{
char toReplace = splitText[charToCheck];
char currentLetter = splitText[-1];
for (int i = 0; i <= charToCheck; i++)
{
char temporary = splitText[i];
splitText[i] = currentLetter;
currentLetter = temporary;
}
splitText[-1] = toReplace;
}
You're not checking your boundaries. I would say CheckChars method is redundant and in MoveCharsLeft and MoveCharsRight you're not checking if you're still inside of splitText.
Here's how I would implement MoveCharsLeft, I hope it'll guide you in the right direction.
char[] MoveCharactersLeft(char[] text, char character) {
var lowerCharacter = char.ToLower(character);
var left = new List<char>();
var right = new List<char>();
foreach (var letter in text) {
if (char.ToLower(letter) == lowerCharacter) {
left.Add(letter);
continue;
}
right.Add(letter);
}
left.AddRange(right);
return left.ToArray();
}
And here's MoveCharactersRight:
char[] MoveCharactersRight(char[] text, char character) {
var lowerCharacter = char.ToLower(character);
var left = new List<char>();
var right = new List<char>();
foreach (var letter in text) {
if (char.ToLower(letter) == lowerCharacter) {
right.Add(letter);
continue;
}
left.Add(letter);
}
left.AddRange(right);
return left.ToArray();
}
Now that you have both you simply call MoveCharsLeft and then the MoveCharactersRight on the result of MoveCharsLeft.
You can swap them in place, although it requires a lot of copying. Here's a function to move a character from one spot to another in an array. You can find several examples of this on the web and SO.
public static void Move(char[] buffer, int from, int too)
{
if (from == too)
return;
char temp = buffer[from];
if (too < from)
{
Array.Copy(buffer, too, buffer, too + 1, from - too);
}
else
{
Array.Copy(buffer, from + 1, buffer, from, too - from);
}
buffer[too] = temp;
}
Then you just have to iterate through the array testing the characters, testing them and moving them to the right spot. Here's a function to do that:
public static void ArrangeChars(char[] buffer, char left, char right)
{
int leftIndex = 0;
int rightIndex = buffer.Length - 1;
int i = 0;
while(i <= rightIndex)
{
char ch = buffer[i];
if (ch == left && i > leftIndex)
Move(buffer, i, leftIndex++);
else if (ch == right && i < rightIndex)
Move(buffer, i, rightIndex--);
else
++i;
}
}
Call it like so:
static void Main(string[] _)
{
char[] data = "test me and move".ToCharArray();
Console.WriteLine(new string(data));
ArrangeChars(data, 'e', 't');
Console.WriteLine("Move 'e' to start, move 't' to end");
Console.WriteLine(new string(data));
}
The usual caveats apply - this has not been well tested and if you use it, you should check all the edge cases.

Checking to see the char equivalent of my int value

Okay i might not have explained it to the best of my ability but i'm a beginner and i would like to make a piece of code that does this :
you have a string and you need to find each vowel in it and multiply each vowel's position in the string by its position in the alphabet and add all the sums together
example : steve: has 2 vowels the first e's position is 3 and its position in the alphabet is 5. and the second's position in the alphabet and the string is 5
so the sum is 5*3 + 5*5 = 40
this is what i did . idk what to do now or how to approach it
var vowels = new char[] {'a', 'e', 'i', 'o', 'u', 'y', 'A','E','I', 'O', 'U','Y'};
var chars = new List<char>();
List<int> indexes = new List<int>();
Console.WriteLine("Write something : ");
var input = Console.ReadLine();
int index;
foreach (var vowel in vowels)
{
if (input.Contains(vowel))
{
index = input.IndexOf(vowel);
indexes.Add(index + 1);
chars.Add(vowel);
}
}
Consider this approach:
using System;
using System.Linq;
using System.Collections.Generic;
namespace Whatever
{
class Program
{
static void Main(string[] args)
{
var vowels = new Dictionary<string, int>(5, StringComparer.OrdinalIgnoreCase) { { "a", 1 }, { "e", 5 }, { "i", 9 }, { "o", 15 }, { "u", 21 } };
Console.WriteLine("Write something : ");
var input = Console.ReadLine();
var sum = input.Select((value, index) => new { value, index })
.Sum(x =>
{
vowels.TryGetValue(x.value.ToString(), out var multiplier);
return (x.index + 1) * multiplier;
});
Console.ReadLine();
}
}
}
The Select projects the original string as an anonymous type with the char and its index included.
The Sum checks if the string is a vowel - and if it is it multiplies the position (index + 1) by the position in the alphabet (from vowels).
vowels is case insensitive so that "A" and "a" are treated the same.
If the compiler complains about the out var then use:
int multiplier = 0;
vowels.TryGetValue(x.value.ToString(), out multiplier);
return (x.index + 1) * multiplier;
instead.
i figured it out right here
for (int i = 0; i < indexes.Count; i++)
{
sumofone += indexes[i] * (char.ToUpper(chars[i]) - 64);
}
You can do this (Reference is from here):
var vowels = new char[] { 'a', 'e', 'i', 'o', 'u' };
Console.WriteLine("Write something : ");
var input = Console.ReadLine().ToLower();
int total = 0;
for (int temp = 1; temp <= input.Length; temp++)
{
if (vowels.Contains(input[temp - 1]))
{
total += temp * (char.ToUpper(input[temp -1]) - 64);
}
}
Console.WriteLine("The length is " + total);

Need to create an array to reveal correct letters

Code works the way I want it to. I am having trouble making an array to replace the *s in Console.WriteLine("The word is *******."); .... The array has to reveal the correct letters in their correct place and I am hopelessly lost.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int correctcounter = 0;
int wrongcounter = 0;
char l1 = 'j';
char l2 = 'o';
char l3 = 'h';
char l4 = 'n';
char l5 = 's';
char[] correctletters = { 'j', 'o', 'h', 'n', 's', 'o', 'n' };
char[] guessedletters = new char[10];
Console.WriteLine("Welcome to the Hangman Game!");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("You have 10 tries to guess the word right.");
Console.WriteLine();
Console.WriteLine();
for (int i = 0; i < 10; i++)
{
Console.WriteLine("The word is *******.");
Console.WriteLine();
Console.WriteLine("Guessed letters: [{0}]", string.Join(",", guessedletters));
Console.WriteLine();
Console.WriteLine("Your total wrong guesses:{0}.", wrongcounter);
Console.WriteLine();
Console.WriteLine("Please enter a letter");
Console.WriteLine();
guessedletters[i] = Convert.ToChar(Console.ReadLine());
if (guessedletters[i] == l1 || guessedletters[i] == l2 || guessedletters[i] == l3 || guessedletters[i] == l4 || guessedletters[i] == l5)
{
Console.WriteLine();
Console.WriteLine("You guessed correctly!");
correctletters[i] = guessedletters[i];
correctcounter++;
}
else
{
Console.WriteLine();
Console.WriteLine("You guessed incorrectly");
wrongcounter++;
}
if (correctcounter == 5)
{
Console.WriteLine();
Console.WriteLine("You guessed the word, [{0}]. You WIN!", string.Join("",correctletters));
break;
}
if (wrongcounter == 10)
{
Console.WriteLine();
Console.WriteLine("You LOSE! The word was [{0}]. You LOSE!", string.Join("", correctletters));
break;
}
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Please hit enter to end the program");
Console.ReadLine();
}
}
}
Okay, let's try to do that slowly, with structures you already know of.
So, to achieve our goal, we will work with an other array, which will hold the word to reveal to the user. We'll call it 'wordToReveal':
char[] wordToReveal = {'*', '*', '*', '*', '*', '*', '*'};
When the user finds a correct letter, we will fill it with the correct letters.
If we move to the first if, we can see you already tried to alter the correctLetters with the guessedLetters:
correctletters[i] = guessedletters[i];
However, what this code is doing is wrong. You are using the index i (which is the turn #) to change the correct letter to what the user guessed. So if we're at the 3rd turn, the user input 'j', you'll end-up with your correct word looking like this : johjson.
Instead of this, we will loop through your current 'correctLetters' and change the "word to reveal" to show the real letters. To loop, we're using an other for loop, with a variable called j (because i is already taken!). This variable will go from 0 up to the end of the array.
In that loop, we'll check if the letter at the index j have been guessed by the user. If it is the case, we'll overwrite the * by the correct letter:
for (int j = 0; j < correctletters.Length; j++)
{
if (guessedletters.Contains(correctletters[j]))
{
wordToReveal[j] = correctletters[j];
}
}
Finally, we need to display the word. To do that, we'll replace your string "The word is *******." with our new word to reveal :
Console.WriteLine("The word is " + string.Concat(wordToReveal) + ".");
By the way, string.Concat is exactly like the string.Join you were using. The difference is that you do not have to specify an empty string as a delimiter, it joins the array together by itself.
The final code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int correctcounter = 0;
int wrongcounter = 0;
char l1 = 'j';
char l2 = 'o';
char l3 = 'h';
char l4 = 'n';
char l5 = 's';
char[] correctletters = { 'j', 'o', 'h', 'n', 's', 'o', 'n' };
char[] wordToReveal = {'*', '*', '*', '*', '*', '*', '*'};
char[] guessedletters = new char[10];
Console.WriteLine("Welcome to the Hangman Game!");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("You have 10 tries to guess the word right.");
Console.WriteLine();
Console.WriteLine();
for (int i = 0; i < 10; i++)
{
Console.WriteLine("The word is " + string.Concat(wordToReveal) + ".");
Console.WriteLine();
Console.WriteLine("Guessed letters: [{0}]", string.Join(",", guessedletters));
Console.WriteLine();
Console.WriteLine("Your total wrong guesses:{0}.", wrongcounter);
Console.WriteLine();
Console.WriteLine("Please enter a letter");
Console.WriteLine();
guessedletters[i] = Convert.ToChar(Console.ReadLine());
if (guessedletters[i] == l1 || guessedletters[i] == l2 || guessedletters[i] == l3 || guessedletters[i] == l4 || guessedletters[i] == l5)
{
Console.WriteLine();
Console.WriteLine("You guessed correctly!");
for (int j = 0; j < correctletters.Length; j++)
{
if (guessedletters.Contains(correctletters[j]))
{
wordToReveal[j] = correctletters[j];
}
}
correctcounter++;
}
else
{
Console.WriteLine();
Console.WriteLine("You guessed incorrectly");
wrongcounter++;
}
if (correctcounter == 5)
{
Console.WriteLine();
Console.WriteLine("You guessed the word, [{0}]. You WIN!", string.Concat(correctletters));
break;
}
if (wrongcounter == 10)
{
Console.WriteLine();
Console.WriteLine("You LOSE! The word was [{0}]. You LOSE!", string.Concat(correctletters));
break;
}
}
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Please hit enter to end the program");
Console.ReadLine();
}
}
}
You can see we declared the new array with the other, changed the Console.Write and added the new loop in the first if.
There's a lot of other ways to achieve it, but I hope this was clear enough for you.
This is one way:
var secretWord = "shmurple"; // the secret word
var mask = new String('*', secretWord.Length); // the mask
When revealing a letter:
var sb = new StringBuilder(mask); // to be able to alter at index
sb[2] = secretWord[2];
mask = sb.ToString();
Example:
var secretWord = "shmurple";
var mask = new String('*', secretWord.Length);
var sb = new StringBuilder(mask);
sb[2] = secretWord[2];
mask = sb.ToString();
Console.WriteLine(String.Format("The word is {0}.", mask)); // **m*****
This is one way... but there are lots more. I gave this a one-minute consideration, so you might find a more efficient way.
Alternatively, secretWord could be a char array, so that you don't have to worry about the whole StringBuilder business. Everything else works the same way.
EDIT:
I see your new code.... Just create a mask array (same length as the secret word) and when you're revealing a letter, replace it with the char from the correct array:
char[] secret = { 'j', 'o', 'h', 'n', 's', 'o', 'n' };
char[] solution = Enumerable.Repeat('*', secret.Length).ToArray(); // mask
solution[2] = secret[2]; // example
Console.WriteLine(solution); // **h****
That way, all your indexes match and your life is a lot simpler. If you need to reveal all matches, just use a loop.

How to print a diamond shape composed of letters? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I want to learn how can I print diamond as follows: I am beginner, so many many thanks for Help
Given a letter print a diamond starting with 'A'
with the supplied letter at the widest point.
For example: print-diamond 'E' prints
A
B B
C C
D D
E E
D D
C C
B B
A
For example: print-diamond 'C' prints
A
B B
C C
B B
A
Actually, your code has two errors (I'm not considering efficiency of your code and algorhims).
First: when you are constructing diamond, for-loop should be not for (int i = 0; i < letter_number + i; i++) but for (int i = 0; i <= letter_number; i++).
Second: when you are drawing diamond - variable j should be placed out of loop, and you should use WriteLine instead of Write.
For example, drawing part of your code can be something like this:
Console.WriteLine();
int jj = 1;
for (int i = 0; i < 2 * letter_number + 1; i++)
{
if (i < letter_number + 1)
Console.WriteLine(diamond[i]);
else
{
Console.WriteLine(diamond[i - 2 * jj]);
jj++;
}
}
Side note: int letter_number; should be initialized as int letter_number = 0; or something like this, because you are assigning it's value under condition and not in every case later in the code, and actually code you've provided even don't compile without this explicit initialization.
Try this. Tested working.
using System;
namespace ConsoleApplication
{
internal class Program
{
private static void Main(string[] args)
{
char[] letter = new char[26]
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z'
};
int letter_number = 0;
//array of strings
string[] diamond = new string[52];
//get the letter
Console.WriteLine("User enters a Letter between A and Z ");
char user_letter = Console.ReadKey().KeyChar;
Console.WriteLine("");
//search for letter number in the array letter
for (int i = 0; i < letter.Length; i++)
{
if (letter[i] == user_letter)
{
letter_number = i;
break;
}
}
//construct diamond
for (int i = 0; i <= letter_number; i++)
{
//add initial spaces
for (int j = 0; j < letter_number - i; j++)
{
diamond[i] += " ";
}
//add letter (first time)
diamond[i] += letter[i];
//add space between letters
if (letter[i] != 'A')
{
for (int j = 0; j < 2*i - 1; j++)
{
diamond[i] += " ";
}
//add letter (second time)
diamond[i] += letter[i];
}
// Draw the first part of the diamond as it's composing.
Console.WriteLine(diamond[i]);
}
for (int i = letter_number - 1; i >= 0; i--)
{
// Draw the second part of the diamond
// Writing the diamondArray in reverse order.
Console.WriteLine(diamond[i]);
}
// Mark a pause
Console.ReadKey();
}
}
}
Output :
User enters a Letter between A and Z
K
A
B B
C C
D D
E E
F F
G G
H H
I I
J J
K K
J J
I I
H H
G G
F F
E E
D D
C C
B B
A

Iterating through the Alphabet - C# a-caz

I have a question about iterate through the Alphabet.
I would like to have a loop that begins with "a" and ends with "z". After that, the loop begins "aa" and count to "az". after that begins with "ba" up to "bz" and so on...
Anybody know some solution?
Thanks
EDIT: I forgot that I give a char "a" to the function then the function must return b. if u give "bnc" then the function must return "bnd"
First effort, with just a-z then aa-zz
public static IEnumerable<string> GetExcelColumns()
{
for (char c = 'a'; c <= 'z'; c++)
{
yield return c.ToString();
}
char[] chars = new char[2];
for (char high = 'a'; high <= 'z'; high++)
{
chars[0] = high;
for (char low = 'a'; low <= 'z'; low++)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Note that this will stop at 'zz'. Of course, there's some ugly duplication here in terms of the loops. Fortunately, that's easy to fix - and it can be even more flexible, too:
Second attempt: more flexible alphabet
private const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
public static IEnumerable<string> GetExcelColumns()
{
return GetExcelColumns(Alphabet);
}
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
foreach(char c in alphabet)
{
yield return c.ToString();
}
char[] chars = new char[2];
foreach(char high in alphabet)
{
chars[0] = high;
foreach(char low in alphabet)
{
chars[1] = low;
yield return new string(chars);
}
}
}
Now if you want to generate just a, b, c, d, aa, ab, ac, ad, ba, ... you'd call GetExcelColumns("abcd").
Third attempt (revised further) - infinite sequence
public static IEnumerable<string> GetExcelColumns(string alphabet)
{
int length = 0;
char[] chars = null;
int[] indexes = null;
while (true)
{
int position = length-1;
// Try to increment the least significant
// value.
while (position >= 0)
{
indexes[position]++;
if (indexes[position] == alphabet.Length)
{
for (int i=position; i < length; i++)
{
indexes[i] = 0;
chars[i] = alphabet[0];
}
position--;
}
else
{
chars[position] = alphabet[indexes[position]];
break;
}
}
// If we got all the way to the start of the array,
// we need an extra value
if (position == -1)
{
length++;
chars = new char[length];
indexes = new int[length];
for (int i=0; i < length; i++)
{
chars[i] = alphabet[0];
}
}
yield return new string(chars);
}
}
It's possible that it would be cleaner code using recursion, but it wouldn't be as efficient.
Note that if you want to stop at a certain point, you can just use LINQ:
var query = GetExcelColumns().TakeWhile(x => x != "zzz");
"Restarting" the iterator
To restart the iterator from a given point, you could indeed use SkipWhile as suggested by thesoftwarejedi. That's fairly inefficient, of course. If you're able to keep any state between call, you can just keep the iterator (for either solution):
using (IEnumerator<string> iterator = GetExcelColumns())
{
iterator.MoveNext();
string firstAttempt = iterator.Current;
if (someCondition)
{
iterator.MoveNext();
string secondAttempt = iterator.Current;
// etc
}
}
Alternatively, you may well be able to structure your code to use a foreach anyway, just breaking out on the first value you can actually use.
Edit: Made it do exactly as the OP's latest edit wants
This is the simplest solution, and tested:
static void Main(string[] args)
{
Console.WriteLine(GetNextBase26("a"));
Console.WriteLine(GetNextBase26("bnc"));
}
private static string GetNextBase26(string a)
{
return Base26Sequence().SkipWhile(x => x != a).Skip(1).First();
}
private static IEnumerable<string> Base26Sequence()
{
long i = 0L;
while (true)
yield return Base26Encode(i++);
}
private static char[] base26Chars = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private static string Base26Encode(Int64 value)
{
string returnValue = null;
do
{
returnValue = base26Chars[value % 26] + returnValue;
value /= 26;
} while (value-- != 0);
return returnValue;
}
The following populates a list with the required strings:
List<string> result = new List<string>();
for (char ch = 'a'; ch <= 'z'; ch++){
result.Add (ch.ToString());
}
for (char i = 'a'; i <= 'z'; i++)
{
for (char j = 'a'; j <= 'z'; j++)
{
result.Add (i.ToString() + j.ToString());
}
}
I know there are plenty of answers here, and one's been accepted, but IMO they all make it harder than it needs to be. I think the following is simpler and cleaner:
static string NextColumn(string column){
char[] c = column.ToCharArray();
for(int i = c.Length - 1; i >= 0; i--){
if(char.ToUpper(c[i]++) < 'Z')
break;
c[i] -= (char)26;
if(i == 0)
return "A" + new string(c);
}
return new string(c);
}
Note that this doesn't do any input validation. If you don't trust your callers, you should add an IsNullOrEmpty check at the beginning, and a c[i] >= 'A' && c[i] <= 'Z' || c[i] >= 'a' && c[i] <= 'z' check at the top of the loop. Or just leave it be and let it be GIGO.
You may also find use for these companion functions:
static string GetColumnName(int index){
StringBuilder txt = new StringBuilder();
txt.Append((char)('A' + index % 26));
//txt.Append((char)('A' + --index % 26));
while((index /= 26) > 0)
txt.Insert(0, (char)('A' + --index % 26));
return txt.ToString();
}
static int GetColumnIndex(string name){
int rtn = 0;
foreach(char c in name)
rtn = rtn * 26 + (char.ToUpper(c) - '#');
return rtn - 1;
//return rtn;
}
These two functions are zero-based. That is, "A" = 0, "Z" = 25, "AA" = 26, etc. To make them one-based (like Excel's COM interface), remove the line above the commented line in each function, and uncomment those lines.
As with the NextColumn function, these functions don't validate their inputs. Both with give you garbage if that's what they get.
Here’s what I came up with.
/// <summary>
/// Return an incremented alphabtical string
/// </summary>
/// <param name="letter">The string to be incremented</param>
/// <returns>the incremented string</returns>
public static string NextLetter(string letter)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (!string.IsNullOrEmpty(letter))
{
char lastLetterInString = letter[letter.Length - 1];
// if the last letter in the string is the last letter of the alphabet
if (alphabet.IndexOf(lastLetterInString) == alphabet.Length - 1)
{
//replace the last letter in the string with the first leter of the alphbat and get the next letter for the rest of the string
return NextLetter(letter.Substring(0, letter.Length - 1)) + alphabet[0];
}
else
{
// replace the last letter in the string with the proceeding letter of the alphabet
return letter.Remove(letter.Length-1).Insert(letter.Length-1, (alphabet[alphabet.IndexOf(letter[letter.Length-1])+1]).ToString() );
}
}
//return the first letter of the alphabet
return alphabet[0].ToString();
}
just curious , why not just
private string alphRecursive(int c) {
var alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
if (c >= alphabet.Length) {
return alphRecursive(c/alphabet.Length) + alphabet[c%alphabet.Length];
} else {
return "" + alphabet[c%alphabet.Length];
}
}
This is like displaying an int, only using base 26 in stead of base 10. Try the following algorithm to find the nth entry of the array
q = n div 26;
r = n mod 26;
s = '';
while (q > 0 || r > 0) {
s = alphabet[r] + s;
q = q div 26;
r = q mod 26;
}
Of course, if you want the first n entries, this is not the most efficient solution. In this case, try something like daniel's solution.
I gave this a go and came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Alphabetty
{
class Program
{
const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static int cursor = 0;
static int prefixCursor;
static string prefix = string.Empty;
static bool done = false;
static void Main(string[] args)
{
string s = string.Empty;
while (s != "Done")
{
s = GetNextString();
Console.WriteLine(s);
}
Console.ReadKey();
}
static string GetNextString()
{
if (done) return "Done";
char? nextLetter = GetNextLetter(ref cursor);
if (nextLetter == null)
{
char? nextPrefixLetter = GetNextLetter(ref prefixCursor);
if(nextPrefixLetter == null)
{
done = true;
return "Done";
}
prefix = nextPrefixLetter.Value.ToString();
nextLetter = GetNextLetter(ref cursor);
}
return prefix + nextLetter;
}
static char? GetNextLetter(ref int letterCursor)
{
if (letterCursor == alphabet.Length)
{
letterCursor = 0;
return null;
}
char c = alphabet[letterCursor];
letterCursor++;
return c;
}
}
}
Here is something I had cooked up that may be similar. I was experimenting with iteration counts in order to design a numbering schema that was as small as possible, yet gave me enough uniqueness.
I knew that each time a added an Alpha character, it would increase the possibilities 26x but I wasn't sure how many letters, numbers, or the pattern I wanted to use.
That lead me to the code below. Basically you pass it an AlphaNumber string, and every position that has a Letter, would eventually increment to "z\Z" and every position that had a Number, would eventually increment to "9".
So you can call it 1 of two ways..
//This would give you the next Itteration... (H3reIsaStup4dExamplf)
string myNextValue = IncrementAlphaNumericValue("H3reIsaStup4dExample")
//Or Loop it resulting eventually as "Z9zzZzzZzzz9zZzzzzzz"
string myNextValue = "H3reIsaStup4dExample"
while (myNextValue != null)
{
myNextValue = IncrementAlphaNumericValue(myNextValue)
//And of course do something with this like write it out
}
(For me, I was doing something like "1AA000")
public string IncrementAlphaNumericValue(string Value)
{
//We only allow Characters a-b, A-Z, 0-9
if (System.Text.RegularExpressions.Regex.IsMatch(Value, "^[a-zA-Z0-9]+$") == false)
{
throw new Exception("Invalid Character: Must be a-Z or 0-9");
}
//We work with each Character so it's best to convert the string to a char array for incrementing
char[] myCharacterArray = Value.ToCharArray();
//So what we do here is step backwards through the Characters and increment the first one we can.
for (Int32 myCharIndex = myCharacterArray.Length - 1; myCharIndex >= 0; myCharIndex--)
{
//Converts the Character to it's ASCII value
Int32 myCharValue = Convert.ToInt32(myCharacterArray[myCharIndex]);
//We only Increment this Character Position, if it is not already at it's Max value (Z = 90, z = 122, 57 = 9)
if (myCharValue != 57 && myCharValue != 90 && myCharValue != 122)
{
myCharacterArray[myCharIndex]++;
//Now that we have Incremented the Character, we "reset" all the values to the right of it
for (Int32 myResetIndex = myCharIndex + 1; myResetIndex < myCharacterArray.Length; myResetIndex++)
{
myCharValue = Convert.ToInt32(myCharacterArray[myResetIndex]);
if (myCharValue >= 65 && myCharValue <= 90)
{
myCharacterArray[myResetIndex] = 'A';
}
else if (myCharValue >= 97 && myCharValue <= 122)
{
myCharacterArray[myResetIndex] = 'a';
}
else if (myCharValue >= 48 && myCharValue <= 57)
{
myCharacterArray[myResetIndex] = '0';
}
}
//Now we just return an new Value
return new string(myCharacterArray);
}
}
//If we got through the Character Loop and were not able to increment anything, we retun a NULL.
return null;
}
Here's my attempt using recursion:
public static void PrintAlphabet(string alphabet, string prefix)
{
for (int i = 0; i < alphabet.Length; i++) {
Console.WriteLine(prefix + alphabet[i].ToString());
}
if (prefix.Length < alphabet.Length - 1) {
for (int i = 0; i < alphabet.Length; i++) {
PrintAlphabet(alphabet, prefix + alphabet[i]);
}
}
}
Then simply call PrintAlphabet("abcd", "");

Categories

Resources