how to shift down alphabet characters in a cyclic way? - c

i want to find the alphabet charachter that is 7 charachters before mine ,so i wrote this function to do so and it works fine :
char find7_before(char letter){
switch (letter){
case 'g':
return 'z';
break;
case 'f':
return 'y';
break;
case 'e':
return 'x';
break;
case 'd':
return 'w';
break;
case 'c':
return 'v';
break;
case 'b':
return 'u';
break;
case 'a':
return 't';
break;
default:
return (char)(((int)letter) - 7);
}
}
but i think i can do it in a smarter way without all of these cases but i just can't figure it out ! (i figured how to find 7 letters after in a cyclic way ) any help or an idea or a hint ?
thank you :)

Assuming ASCII with continuous ['a' , 'z']...
Simply "mod 26".
letter = ((letter - 'a' - 7) mod 26) + 'a';
Yet C does not have a Euclidean mod operator.
See What's the difference between “mod” and “remainder”?
So create a Euclidean mod function - save for later use.
int modulo_Euclidean(int a, int b) {
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
letter = modulo_Euclidean(letter - 'a' - 7, 26) + 'a';
Alternately code can take advantage that 'a' has a value of 97 and not subtract so much that letter - ('a'%26) - 7 becomes negative.
letter = (letter - ('a'%26) - 7)%26 + 'a';
Pedantic code would not assume continuous ['a' , 'z'] and perform more elaborate code.

subtract 'a' (so now it's in 0-25), subtract 7, and mod 26. Then add 'a' again so it's back to a char.

In my opinion, the clearest and simplest way is to use an if statement:
char find7_before(char letter) {
char value = letter - 7;
if (value < 'a') {
value += 26;
}
return value;
}
The precondition here is the letter is between 'a' and 'z', inclusive.
This technique generalizes as well:
char findn_before(char letter, int n) {
char value = letter - n;
if (value < 'a') {
value += 26;
}
return value;
}
Precondition on letter is the same as before; n must be between 0 and 26, inclusive.

Related

Alphanumeric String to Unique Integer representation

I have an input data of 4 character string (alphanumeric) or 3 character string and I need to convert these ASCII character string to unique float in 2 digits each, separated by decimal.
Ex:
Input string = 5405, output data = 54.05
Input string = 53BC, output data = 53.199 ( B ascii value is ~ 0x42 in hex and C is 0x43 )
Issue is I am seeing the same output when input strings are 560B and 5618, as both results in same output as 56.18.
Is there a way to uniquely generate a float number in these cases?
Max value of float allowed is 99.999.
Simple math tells us that this is not possible. The number of unique alphanumeric strings of length 4 (case-insensitive) is 36^4 = 1,679,616 while the number of non-negative unique floating point numbers with at most 3 fractional digits and less than 100 is 10^5 = 100,000.
If the string were restricted to hexadecimal digits, there would only be 16^4 = 65,536 possibilities in which case a unique encoding would be possible.
Slightly off-topic: when a mapping is needed into a domain which is too small to accommodate the result of a unique mapping, a hash function is the "standard tool", but collisions must be handled.
Your encoding is somewhat confusing, but here is a simple solution:
use 2 digits for the integral part
use 2 digits for fractional parts 00 to 99
use a combination of 1 letter and 1 letter or digit for fractional parts 100 to 999. There are 26*36 = 936 such combinations, enough to cover the 900 possibilities.
all values from 00.00 to 99.999 can be encoded.
some 4 letter and digit combinations are not used.
the encoding is not unique. eg: 53A0 is 53.100, the same number as 53.10 encoded as 5310.
Here is an implementation:
#include <stdib.h>
double fdecode(const char *s) {
char a[7];
a[0] = s[0];
a[1] = s[1];
a[2] = '.';
if (s[2] >= '0' && s[2] <= '9') {
a[3] = s[3];
a[4] = s[4];
a[5] = '\0';
} else {
// assuming uppercase letters
int n = 100 + (s[3] - 'A') * 36;
if (s[4] >= '0' && s[4] <= '9') {
n += s[4] - '0';
} else {
n += 10 + (s[4] - 'A') % 26;
}
snprintf(&a[3], 4, "%d", n);
}
return strtod(a, NULL);
}
int fencode(char *s, double d) {
char a[7];
if (d >= 0 && snprintf(a, 7, "%06.3f", d) == 6) {
s[0] = a[0];
s[1] = a[1];
if (a[5] == '0') {
s[2] = a[3];
s[3] = a[4];
} else {
int n = atoi(a + 3);
s[2] = 'A' + (n / 36);
n %= 36;
if (n < 10) {
s[3] = '0' + n;
} else {
s[3] = 'A' + n - 10;
}
}
s[4] = '\0';
return 4;
} else {
s[0] = '\0';
return -1;
}
}

C - Verify win condition in Connect Four game

This is the verification from a connect four game prototype, but it seems I've done something wrong.
I want that everytime the player is making a move, the function will verify if there he won or not, by verifying vertically, horizontally, and eventually, on the diagonal.
But it seems that it does not verify correctly, because in some cases, even though there are only 2 moves made, the functions returns 1.
int verifyGame(int gamePosition, int gameVariable, char gameArray[HEIGTH][WIDTH])
{
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition + 1][gameVariable] == gameArray[gamePosition + 2][gameVariable] == gameArray[gamePosition + 3][gameVariable]) //verify vertically
return 1;
else
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition][gameVariable - 3] == gameArray[gamePosition][gameVariable - 2] == gameArray[gamePosition][gameVariable - 1]) //verify horizontally
return 1;
else
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition][gameVariable - 2] == gameArray[gamePosition][gameVariable - 1] == gameArray[gamePosition][gameVariable + 1])
return 1;
else
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition][gameVariable - 1] == gameArray[gamePosition][gameVariable + 1] == gameArray[gamePosition][gameVariable + 2])
return 1;
else
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition][gameVariable + 1] == gameArray[gamePosition][gameVariable+ 2] == gameArray[gamePosition][gameVariable + 3])
return 1;
//verify diagonally
else return 0;
};
This is where the function is called. The switch verifies the users input, and then it places the value in the matrix, and then verifies for won
printf("playerPick is : %d\n", playerPick);
fflush(stdout);
switch(playerPick)
{
case 1:
if(gameVariables[0] >0 && gameVariables[0] < 7)
{
--gameVariables[0];
gameArray[gameVariables[0]][0] = (char) 82;
ifWon = verifyGame(gameVariables[0], 0, gameArray);
}
printArray(gameArray);
break;
case 2:
if(gameVariables[1] >0 && gameVariables[1] < 7)
{
--gameVariables[1];
gameArray[gameVariables[1]][1] = (char) 82;
ifWon = verifyGame(gameVariables[1], 1, gameArray);
}
printArray(gameArray);
break;
case 3:
if(gameVariables[2] >0 && gameVariables[2] < 7)
{
--gameVariables[2];
gameArray[gameVariables[2]][2] = (char) 82;
ifWon = verifyGame(gameVariables[2], 2, gameArray);
}
printArray(gameArray);
break;
case 4:
if(gameVariables[3] >0 && gameVariables[3] < 7)
{
--gameVariables[3];
gameArray[gameVariables[3]][3] = (char) 82;
ifWon = verifyGame(gameVariables[3], 3, gameArray);
}
printArray(gameArray);
break;
case 5:
if(gameVariables[4] >0 && gameVariables[4] < 7)
{
--gameVariables[4];
gameArray[gameVariables[4]][4] = (char) 82;
ifWon = verifyGame(gameVariables[4], 4, gameArray);
}
printArray(gameArray);
break;
case 6:
if(gameVariables[5] >0 && gameVariables[5] < 7)
{
--gameVariables[5];
gameArray[gameVariables[5]][5] = (char) 82;
ifWon = verifyGame(gameVariables[5], 5, gameArray);
}
printArray(gameArray);
break;
case 7:
if(gameVariables[6] >0 && gameVariables[6] < 7)
{
--gameVariables[6];
gameArray[gameVariables[6]][6] = (char) 82;
ifWon = verifyGame(gameVariables[6], 6, gameArray);
}
printArray(gameArray);
break;
}
printf("%d %d %d %d %d %d %d\n", gameVariables[0], gameVariables[1], gameVariables[2], gameVariables[3], gameVariables[4], gameVariables[5], gameVariables[6]);
printf("ifwon : %d\n", ifWon);
#Weather Vane's answer is correct. The logic used in your original post is not correct for a verification.
One reason you may not have caught it yourself may be the complicated way it was written. Try simplifying the user input verification code: (Range checking the user input values is all that is necessary.)
//User input range checking:
if((gamePosition >= x)&& //where `x` is minimum for gamePosition
(gamePosition <= y)&& //where `y` is maximum for gamePosition
(gameVariable >= z)&& //where `z` is minimum for gameVariable
(gameVariable <= w)) //where `w` is maximum for gameVariable
{//continue }
else
{
printf("Invalid value. Please re-enter");
return -1;
}
Another opportunity for simplification is to note that each of your case statements contain identical code, with the exception of the value of the case. Because of this the entire switch(...){...} can be replaced with a single if statement:
//assuming playerPick >= 1
if(gameVariables[playerPick-1] >0 && gameVariables[playerPick-1] < 7)
{
--gameVariables[playerPick-1];
gameArray[gameVariables[playerPick-1]][playerPick-1] = (char) 82;
ifWon = verifyGame(gameVariables[playerPick-1], playerPick-1, gameArray);
}
printArray(gameArray);
Also note that although the statement:
gameArray[gameVariables[0][0] = (char) 82; //what is 82?
is perfectly legal, the variable gameArray[0][0] is just a char, so casting the value 82 is not necessary. Also, C syntax provides a way to pull out the ASCII decimal value of the character by surrounding it with the graves symbol, allowing the following form, which is more readable:
gameArray[gameVariables[0]][0] = `R`; //intuitive
You cannot chain equality testing as you are attempting. The code will execute, but not as you suppose. Your code
if(gameArray[gamePosition][gameVariable] ==
gameArray[gamePosition + 1][gameVariable] ==
gameArray[gamePosition + 2][gameVariable] ==
gameArray[gamePosition + 3][gameVariable])
must be split up into individual tests, such as:
if(gameArray[gamePosition][gameVariable] == gameArray[gamePosition + 1][gameVariable] &&
gameArray[gamePosition][gameVariable] == gameArray[gamePosition + 2][gameVariable] &&
gameArray[gamePosition][gameVariable] == gameArray[gamePosition + 3][gameVariable])
and on the other lines too.

Switch/String in c

I am trying to get this function to return a string.
char * vergleich(int random) {
char *erg;
switch(random) {
case 1: erg = "Siccor" ; break;
case 2: erg = "Paper" ; break;
case 3: erg = "Rock" ; break;
case 4: erg = "Lizard" ; break;
case 5: erg = "Spock" ; break;
default: break;
return erg;
}
}
int main() {
srand(time(NULL));
int p1 = rand() % 4;
int p2 = rand() % 4;
printf("player1 shows %s\n", vergleich(p1));
printf("\n\tif Player 2 plays %s or %s Player1 wins\n", vergleich(p1+1), vergleich(p1+3));
if(p2 == p1 + 1 || p2 == p1 +3) {
printf("player1 wins");
}else {printf("player2 wins");}
return 0;
}
}
I think the initialisation of the function is wrong, but I dont really know how to deal with strings, please help.
If I run the program it just crashes if case > 2. and the strings are not displayed right.
The crash happens since the function vergleich() can be called with argument 0 (when p1 is 0) and 6 when p1 is 3. Zero and six are not handled in the switch, so pointer erg points to junk.
So, I suggest to enumerate your items starting from 0 to 4. To avoid overflow during additions you should also use modulo operation %, for example (p1 + 3) % 5, (p1 + 1) % 5.
To generate random from 0 to 4 you can use rand() % 5;.

Convert single Character (hex number) to Integer in C

So for an assignment I have to convert a character (0-F) to an integer (0-15), 0-9 works fine, but if any letter is given, it prints a random number: For C for instance, it gives 19, for D is returns 20.
This is my method:
int char2int(char digit) {
int i = 0;
if (digit == 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9)
i = digit - '0';
else
if (digit == 'A' || 'B' || 'C' || 'D' || 'E' || 'F')
i = digit - '9';
else
i = -1;
return i;
}
At first my if statements were like this:
if (digit => 0 && =< 9)
if (digit => A && =< F)
But that gave a number of errors. You can tell I don't know C very well. My current If statement works but I'm sure it's unnecessarily long.
if (digit == 0 || 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9)
This is not how conditional expressions work in C.
You either need to compare digit against each of the numbers individually
if (digit == '0' || digit == '1' || digit == '2' ...
or do it the clever way:
if(digit >= '0' && digit <= '9')
^^ not =<
Notice that I put ' around the numbers because you want to compare the digit with the letter 0 and not the number (which is not the same see here for all the ASCII character values).
You were on the right path when you started, but wandered off a bit. try this
#include <ctype.h>
int char2int(char d) {
if (!isxdigit(d)) {
return -1;
}
if (isdigit(d)) {
return d - '0';
}
return (tolower(d) - 'a') + 10;
}
If you'd prefer an approach closer to your range testing, you could do it like this:
int char2int(char d) {
if (d >= '0' && d <= '9') {
return d - '0';
}
d = tolower(d);
if (d >= 'a' && d <= 'f') {
return (d - 'a') + 10;
}
return -1;
}
Assuming ASCII the following converts from a character (0-9, a-f, A-F) to the associated unsigned integer (0-15). Any other character will also be converted to... some random value in the 0-15 range. Garbage in, garbage out.
unsigned hexToUnsigned(char ch) {
return ((ch | 432) * 239'217'992 & 0xffff'ffff) >> 28;
}
CPUs with 32-bit integers will generally be able to elide the 0xffff'ffff masking. On my machine the compiler turns this function into:
hexToUnsigned PROC
movsx eax, cl
or eax,1B0h
imul eax, eax, 0E422D48h
shr eax, 1ch
ret 0
hexToUnsigned ENDP
Another common way to do this has fewer apparent operations (just three), returns total garbage on invalid characters (which is probably okay), but also requires division (which takes it out of the top spot):
return ((ch | ('A' ^ 'a')) - '0') % 39;
To illustrate how compilers feel about division, they (at least on x64) change it into a multiply of the reciprocal to get the product and then one more multiply and subtract if you need the remainder:
hexToUnsigned PROC
; return ((ch | ('A' ^ 'a')) - '0') % 39;
movsx r8d, cl
mov eax, -770891565
or r8d, 32
sub r8d, 48
imul r8d
add edx, r8d
sar edx, 5
mov ecx, edx
shr ecx, 31
add edx, ecx
imul ecx, edx, 39
sub r8d, ecx
mov eax, r8d
ret 0
hexToUnsigned ENDP
The return value is not random. Every ascii character is represented in the memory by a value. The value of each ascii character can be found in the
Ascii Table.
The other responses tell you what you are doing wrong with the conditional expressions, but another mistake is that if the character is A, B, C, D, E or F you need to convert it to int like this i = ( digit - 'A' ) + 10 which means take the value of A, B, C, D, E or F subtract the min value which is A and add to that 10.
Moreover, you can see that if you don't need the exact value of a character you can do without the ascii table, using the property that letters are continuous.
If you are willing to make assumptions such as char are encoded as ASCII and 2's complement, the following is quite efficient.
This code is not meant for readability. Use other solutions if that is a concern. This is for tight encoding. With a given processor, it is about 10 instructions. Your results will vary.
Subtract 1. This shifts the char values down 1. In particular, A-Z is now 64-89 and a-z in the range 96-121.
Test if a bit (64's place) is clear: in the range of '0' - '9'. If so, increment by 7 and mask to keep that bit (64's place) cleared.
Otherwise mask a bit to fold a-z into the A-Z range.
Now '0' to '9' and 'A' to 'Z' are in a continues range. Just subtract 54. All unsigned char values other than 0-9, A-Z and a-z will have a value > 35. This is useful for any base use to base 36.
int Value(char ch) {
if (!(--ch & 64)) { // decrement, if ch in the '0' to '9' area ...
ch = (ch + 7) & (~64); // move 0-9 next to A-Z codes
} else {
ch &= ~32;
}
ch -= 54; // -= 'A' - 10 - 1
if ((unsigned char)ch > 15) {
; // handle error
}
return (unsigned char)ch;
}
In redis
https://github.com/antirez/redis/blob/3.2.8/src/sds.c#L892
int hex_digit_to_int(char c) {
switch(c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return 0;
}
}

Shift a letter down the alphabet?

I.E., you enter the number 5, and the character A and the output would yield F. I have no idea how to even start to go about this, any give me a push in the right direction?
Individual characters are represented by numbers according to the ASCII code (usually). In C, if you add a number to a character, you're shifting the character down. Try:
char c = 'A';
int n = 5;
printf("%c\n", c + n);
Look at the ASCII table and note the values of the characters.
Try this:
#include <stdio.h>
char shift_char(char val, char shift)
{
val = toupper(val);
assert(isupper(val));
char arr[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return arr[ ( (toupper(val) - 'A' + shift) % 26) ];
}
You can get a little fancier if you want to preserve the case of the character. It also assumes, but does not verify shift is non-negative. That case may cause problems with the modulus operation you will need to guard against... or better yet prevent. Still, since this is tagged as homework, that's the sort of thing you should work through.
If you can assume ASCII, it is easier.
Characters are no more than simple numbers: only the interpretation of said numbers changes. In ASCII all letters are sequential; so the number for 'A' + 5 is the number for 'F'; 'F' - 1 is 'E' ..., ...
int ch = 'J';
ch -= 2; putchar(ch);
ch -= 3; putchar(ch);
ch += 7; putchar(ch); putchar(ch);
ch += 3; putchar(ch);
puts("");
Just pay attention to wrapping!
If you can't assume ASCII, you need to convert characters yourself. Something like:
char charr[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int ndx = 9; /* charr[9] is 'J' */
ndx -= 2; putchar(charr[ndx]);
ndx -= 3; putchar(charr[ndx]);
ndx += 7; putchar(charr[ndx]); putchar(charr[ndx]);
ndx += 3; putchar(charr[ndx]);
puts("");
Do not forget the wrapping
Other people have pointed out that you can use ASCII.
An easy way to handle wrapping is with modulus arithmetic:
char result, ch;
int offset;
... // Populate ch with the letter to be changed and offset with the number.
result = ch - 'a';
result = (result + offset) % 26; // 26 letters in the alphabet
result += 'a';
char shift_char(char c, char shift)
{
if(isalpha(c)) {
if (c>='A' && c<='Z') {
return 'A' + ( (c - 'A' + shift) % 26);
} else if(c>='a' && c<='z') {
return 'a' + ( (c - 'a' + shift) % 26);
}
}
return c;
}

Resources