Turn if else into a for loop - c++

I want to choose positions 1, 3, 7, 9.
I made an if else statement that solves the problem. Could this be implemented in a for loop.
int move1 = (rand() % 4) + 1;
if (move1 == 1)
{
move1 = 1;
}
else if (move1 == 2)
{
move1 = 3;
}
else if (move1 == 3)
{
move1 = 7;
}
else if (move1 == 4)
{
move1 = 9;
}

I don't know about a loop, but usually you want to implement these kind of things with a switch statement. Something like this:
int move1;
switch(rand() % 4)
{
case 1:
move1 = 1;
break;
case 2:
move1 = 3;
break;
case 3:
move1 = 7;
break;
case 4:
move1 = 9;
break;
}

Related

Stack smashing detected

#include <iostream>
using namespace std;
int main()
{
int tablica[9];
string inputromanum;
cout << "ROMAN: ";
cin >> inputromanum;
int maxindeks;
bool disablenextcomp = false;
int readysolution = 0;
maxindeks = inputromanum.length() - 1;{}{}
for (int i = 0; i <= maxindeks; i++)
{
if (inputromanum[i] == 'M' || inputromanum[i] == 'm')
{
tablica[i] = 1000;
}
if (inputromanum[i] == 'D' || inputromanum[i] == 'd')
{
tablica[i] = 500;
}
if (inputromanum[i] == 'C'|| inputromanum[i] == 'c')
{
tablica[i] = 100;
}
if (inputromanum[i] == 'L' || inputromanum[i] == 'l')
{
tablica[i] = 50;
}
if (inputromanum[i] == 'X' || inputromanum[i] == 'x')
{
tablica[i] = 10;
}
if (inputromanum[i] == 'V' || inputromanum[i] == 'v')
{
tablica[i] = 5;
}
if (inputromanum[i] == 'I' || inputromanum[i] == 'i')
{
tablica[i] = 1;
}
}
cout<<endl;
for(int i4 = 0; i4 <= maxindeks; i4++)
{
cout<<"tablica["<<i4<<"] = "<<tablica[i4]<<endl;
}
for (int i2 = 0; i2 <= maxindeks; i2++)
{
int i5 = i2 + 1;
if (i5 <= maxindeks)
{
//cout<<endl<<"tablica[i2 + 1] = "<<tablica[i2 + 1];
//cout<<endl<<"tablica[i2] = "<<tablica[i2];
//cout<<endl<<"tablica[i2 + 1] - tablica[i2] = "<<tablica[i2 + 1] - tablica[i2];
if (tablica[i2 + 1] - tablica[i2] > 0 && disablenextcomp == false)
{
//cout<<endl<<"readysolution + (tablica[i2 + 1] - tablica[i2]) = "<<readysolution + (tablica[i2 + 1] - tablica[i2])<<endl;
readysolution = readysolution + (tablica[i2 + 1] - tablica[i2]);
disablenextcomp = true;
}
else
{
if(disablenextcomp == false)
{
//cout<<endl<<"readysolution + tablica[i2] = "<<readysolution + tablica[i2]<<endl;
readysolution = readysolution + tablica[i2];
}
else
{
disablenextcomp = false;
}
}
}
else
{
if(disablenextcomp == false)
{
//cout<<endl<<endl<<"OSTATNI INDEKS";
//cout<<endl<<"tablica[i2] = "<<tablica[i2];
//cout<<endl<<"readysolution + tablica[i2] = "<<readysolution + tablica[i2];
readysolution = readysolution + tablica[i2];
}
}
i5++;
}
cout << endl << readysolution;
}
This is my program. made for decoding roman numerals into arabic ones. It works as intended in most cases, however, one of my colleagues found it to produce this error while inputting MMMCMXCVIII into the program:
*** stack smashing detected ***: terminated
It would refuse to work afterwards.
I wasn't able to find different numbers that would cause this error except MMMMMMMMMMM.
It seems to fail when the index of tablica array exceeds 10. I don't know why it does so, as i am a novice in c++. It should've outputted 3999 instead of the error appearing. The numbers it should process successfully should range from 1 to 5000.
Thanks to folks in the comments, I've found the cause.
The tablica[9] array is supposed to store 9 or less characters.
The length of the input (MMMCMXCVIII in this case) has more characters, therefore it makes the for loop responsible for storing values for each character to cause mentioned above error, as there are no remaining units to store the values in.
I've expanded the storage of tablica to 25 characters.
In modern C++ it is considered bad practice to use C-style arrays and index loops whenever you can avoid this. So, fo example you can rewrite first loop like this:
std::vector<int> tablica;
tablica.reserve(inputromanum.size()); // This line is not necessary, but it can help optimize memory allocations
for (char c : inputromanum)
{
if (c == 'M' || c == 'm')
{
tablica.push_back(1000);
}
if (c == 'D' || c == 'd')
{
tablica.push_back(500);
}
if (c == 'C'|| c == 'c')
{
tablica.push_back(100);
}
if (c == 'L' || c == 'l')
{
tablica.push_back(50);
}
if (c == 'X' || c == 'x')
{
tablica.push_back(10);
}
if (c == 'V' || c == 'v')
{
tablica.push_back(5);
}
if (c == 'I' || c == 'i')
{
tablica.push_back(1);
}
}
And you will avoid your issue completly. Something similar can be done with other loops too. This approach also has benefit of (somewhat) properly handling situations when input line has other symbols, which is not roman number. Try it on your version and you will see what I mean.
One more point. When you need to do something different depending of value of one variable, like you did with all those ifs. There is special statement in C/C++ for this: switch. So instead of those ifs you can do this:
std::vector<int> tablica;
tablica.reserve(inputromanum.size()); // This line is not necessary, but it can help optimize memory allocations
for (char c : inputromanum)
{
switch(c)
{
case 'M':
case 'm':
tablica.push_back(1000);
break;
case 'D':
case 'd':
tablica.push_back(500);
break;
case 'C':
case 'c':
tablica.push_back(100);
break;
case 'L':
case 'l':
tablica.push_back(50);
break;
case 'X':
case 'x':
tablica.push_back(10);
break;
case 'V':
case 'v':
tablica.push_back(5);
break;
case 'I':
case 'i':
tablica.push_back(1);
break;
}
}

Am I using this switch case incorrectly?

So the idea of this program is to get the users input in the form of a Roman Numeral up to 4999. I decided to use a switch case to loop through an string of input. The problem is when I put in a value like 99 which would be XCIX it returns -101. Any help is grateful.
int number = 0, M = 1000, D = 500, C = 100, L = 50, X = 10, V = 5, I = 1;
for (int i = 0; i < roman.length(); i++)
{
switch (roman[i])
{
case 'M': number += 1000; break;
case 'D': if (roman[i + 1] != 'D' && i + 1 < roman.size())
number -= 500;
else
number += 500;
break;
case 'C': if (roman[i + 1] != 'C' && i + 1 < roman.size())
number -= 100;
else
number += 100;
break;
case 'L': if (roman[i + 1] != 'L' && i + 1 < roman.size())
number -= 50;
else
number += 50;
break;
case 'X': if (roman[i + 1] != 'X' && i + 1 < roman.size())
number -= 10;
else
number += 10;
break;
case 'V': if (roman[i + 1] != 'V' && i + 1 < roman.size())
number -= 5;
else
number += 5;
break;
case 'I':
if (roman[i + 1] != 'I' && i + 1 < roman.size())
number -= 1;
else
number += 1;
break;
}
}
return number;
Roman numerals count negative only when they appear before a digit with higher value. Being different is not enough.

Optimisation hint for array of random numbers

To provide context, I'm working through Programming Praxis Bingo Challenge and wanted to see how fast I could make this code run.
static void fisher_yates(T& source) {
const size_t len = source.size();
for(size_t i = 1; i < len;++i) {
std::swap(source[i],source[rand() % (i+1)]);
}
}
std::array<int,25> generate_table() {
std::array<int,25> bingo_grid;
for(int i = 0 ; i < 25;++i) {
switch(i) {
case 0: case 1: case 2: case 3: case 4:
bingo_grid[i] = rand() % 15 + 1;
break;
case 5: case 6: case 7: case 8: case 9:
bingo_grid[i] = rand() % 15 + 16;
break;
case 10: case 11: case 12: case 13: case 14:
bingo_grid[i] = rand() % 15 + 31;
break;
case 15: case 16: case 17: case 18: case 19:
bingo_grid[i] = rand() % 15 + 46;
break;
case 20: case 21: case 22: case 23: case 24:
bingo_grid[i] = rand() % 15 + 61;
break;
}
}
bingo_grid[12] = 0;
return bingo_grid;
}
bool is_bingoed(const std::array<int,25>& grid) {
// Check columns
if(grid[0] == 0) {
if(grid[1] == 0 && grid[2] == 0 && grid[3] == 0 && grid[4] == 0)
return true;
if(grid[0] == 0 && grid[6] == 0 && grid[18] == 0 && grid[24] == 0)
return true;
if(grid[5] == 0 && grid[10] == 0 && grid[15] == 0 && grid[20] == 0)
return true;
}
if(grid[1] == 0) {
if(grid[6] == 0 && grid[11] == 0 && grid[16] == 0 && grid[21] == 0)
return true;
}
if(grid[2] == 0) {
if(grid[7] == 0 && grid[17] == 0 && grid[22] == 0)
return true;
}
if(grid[3] == 0) {
if(grid[8] == 0 && grid[13] == 0 && grid[18] == 0 && grid[23] == 0)
return true;
}
if(grid[4] == 0) {
if(grid[9] == 0 && grid[14] == 0 && grid[19] == 0 && grid[24] == 0)
return true;
if(grid[8] == 0 && grid[16] == 0 && grid[21] == 0)
return true;
}
if(grid[6] == 0) {
if(grid[6] == 0 && grid[7] == 0 && grid[8] == 0 && grid[9] == 0)
return true;
}
if(grid[12] == 0) {
if(grid[10] == 0 && grid[11] == 0 && grid[13] == 0 && grid[14] == 0)
return true;
}
if(grid[18] == 0) {
if(grid[15] == 0 && grid[16] == 0 && grid[17] == 0 && grid[19] == 0)
return true;
}
return false;
}
static bool mark_card(const int card,std::array<int,25>& bingo_grid) {
for(auto &i : bingo_grid)
if(card == i) {
i = 0;
return true;
}
return false;
}
int play_game() {
// Bingo is 5 columns, each column(n) is random permutation of 1-15*n
// Fisher-Yates to generate random permutations
// Create 500 playing cards
const int max = 500;
std::vector<std::array<int,25>> bingo_cards;
bingo_cards.reserve(max);
for(int i = 0; i<max;++i) {
bingo_cards.push_back(generate_table());
//display_bingo(bingo_cards[i]);
}
// Random shuffle 75 cards
auto iter = boost::counting_range(1,76);
std::vector<int> cards(std::begin(iter),std::end(iter));
fisher_yates(cards);
bool is_finished = false;
int counter = 0;
for(auto card : cards) {
for(auto& playing_card : bingo_cards) {
if(mark_card(card,playing_card)) {
//display_bingo(playing_card);
if(is_bingoed(playing_card))
return counter;
}
}
counter++;
}
return counter;
}
int bingo() {
srand(time(NULL));
int total = 0;
for(int i = 0 ; i < 10000;i++) {
total+=play_game();
}
boost::singleton_pool<boost::pool_allocator_tag, sizeof(int)>::release_memory();
return total / 10000;
}
The original version used a boost::multi_array to represent the grid. After profiling, I changed it to a std::array which got me a significant speed up. I then moved from using fisher_yates shuffle to generate bingo cards to using a random number generator.
Then finally I changed the is_bingoed test function to reduce the number of checks per call to speed up the game-over check.
All this has helped. Right now if I profile this code, the generate_table function takes up 72% of the time, mark_card() is 18%, and is_bingoed() about 6%. I'm looking for hints to see what can be done to improve the speed of either.
My first thought with is_bingoed() is to use the SSE intrinsics to do a compare with 0 (maybe use XOR?) but I don't have any ideas on the generate_table() or mark_car(). This is more of a self challenge for fun but wondered what others thought?
Current timing is it takes 4.6s on a 2Ghz Q6660 (down from 35s originally)
Just focussing on your most expensive function, generate_table, you can simplify this part of the code and make it less branchy, which may help:
for(int i = 0 ; i < 25;++i) {
switch(i) {
case 0: case 1: case 2: case 3: case 4:
bingo_grid[i] = rand() % 15 + 1;
break;
case 5: case 6: case 7: case 8: case 9:
bingo_grid[i] = rand() % 15 + 16;
break;
case 10: case 11: case 12: case 13: case 14:
bingo_grid[i] = rand() % 15 + 31;
break;
case 15: case 16: case 17: case 18: case 19:
bingo_grid[i] = rand() % 15 + 46;
break;
case 20: case 21: case 22: case 23: case 24:
bingo_grid[i] = rand() % 15 + 61;
break;
}
}
e.g.
for(int i = 0 ; i < 25;++i) {
int r = rand() % 15 + 1;
bingo_grid[i] = r + (i / 5) * 15;
}
Beyond that I'd look at a faster rand() and also see if you can get rid of the divide and and modulo.
On a separate note, your algorithm may be flawed in that there is nothing to prevent duplicate numbers in bingo_grid.
Changing the is_bingoed() method to use SSE instructions (using Agner Fog's library) and Paul R's generate_table() reduced the time to just 1.05s. And using Intel's fast_rand() function got it down to 0.38s.
So I thought I'd paste the code changes for others who might be interested.
static unsigned int g_seed;
//Used to seed the generator.
inline void fast_srand( int seed )
{
g_seed = seed;
}
//fastrand routine returns one integer, similar output value range as C lib.
inline int fastrand()
{
g_seed = (214013*g_seed+2531011);
return (g_seed>>16)&0x7FFF;
}
bool is_bingoed(const std::array<int,25>& grid) {
// Check columns
Vec8i vec(grid[0],grid[1],grid[2],grid[3],grid[4],0,0,0);
Vec4i vec2(grid[6],grid[18],grid[24],0);
Vec4i vec3(grid[5],grid[10],grid[15],20);
Vec8i vec4(grid[1],grid[6],grid[11],grid[16],grid[21],0,0,0);
Vec4i vec5(grid[2],grid[7],grid[17],grid[22]);
Vec8i vec6(grid[3],grid[8],grid[13],grid[18],grid[23],0,0,0);
Vec8i vec7(grid[4],grid[9],grid[14],grid[19],grid[24],0,0,0);
Vec4i vec8(grid[8],grid[16],grid[21],grid[4]);
Vec4i vec9(grid[6],grid[7],grid[8],grid[9]);
Vec8i vec10(grid[12],grid[10],grid[11],grid[13],grid[14],0,0,0);
Vec8i vec11(grid[18],grid[15],grid[16],grid[17],grid[19],0,0,0);
if(horizontal_and(vec) && horizontal_and(vec2) && horizontal_and(vec3) && horizontal_and(vec4) &&
horizontal_and(vec5) && horizontal_and(vec6) && horizontal_and(vec7) && horizontal_and(vec8)) {
return false;
}
if(horizontal_and(vec9) && horizontal_and(vec10) && horizontal_and(vec11)) {
return false;
}
return true;
}

Confusing of "Access Violation "

I don't Understand with this case but this is really really important for me, Please Help me...
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String masuk, keluar, kosong;
int i, x, j, n = 0;
masuk = Edit2->Text;
keluar = masuk;
kosong = " ";
n = 0;
x = 0;
mulai:
i = 1;
j = 0;
j = j + n;
i = i + j;
if (masuk[i] == 'a')
{
keluar[i] = 't';
}
else if (masuk[i] == 't')
{
keluar[i] = 'a';
}
else if (masuk[i] == 'c')
{
keluar[i] = 'g';
}
else if (masuk[i] == 'g')
{
keluar[i] = 'c';
}
else
{
Application->MessageBoxA("Masukan Anda Salah", "Peringatan", MB_OK | MB_ICONWARNING);
keluar = kosong;
goto end;
}
n = n + 1;
if (i < 10)
goto mulai;
else
goto end;
end:
Memo1->Text = keluar;
}
if I make masukan more than 10 (i<10 (10 as default value)), it is ok but if it less than 10, it will make message exception Class EAccessViolation..
Taking a shot in the dark, but I think what you're actually trying to do might be this. I'm assuming that you're taking a single string of 10 characters which represents one half of a genome and you're generating another string of the pair values.
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String masuk, keluar;
masuk = Edit2->Text;
keluar = masuk;
char kosong = ' ';
for (int i=0; i < 10; i++)
{
switch(masuk[i]) {
case 'a':
keluar[i] = 't';
break;
case 't':
keluar[i] = 'a';
break;
case 'c':
keluar[i] = 'g';
break;
case 'g':
keluar[i] = 'c';
break;
default:
Application->MessageBoxA("Masukan Anda Salah", "Peringatan", MB_OK | MB_ICONWARNING);
keluar[i] = kosong;
break;
}
Memo1->Text = keluar;
}

Poker code cleanup modification from book...not quite right

Working through more book examples- this one is a partial poker program-
This segment deals with straight hand....
First what was given- only relevant parts....will provide entire code if needed...
int suits[5]; //index 1..4- value start at 1
int values[14]; //index 1..13- value same as rank, A = 1, K = 13
cin.get(rankCh);
switch (toUpper(rankCh)) {
case 'A': values = 1; break;
case '2': values = 2; break;
case '3': values = 3; break;
case '4': values = 4; break;
case '5': values = 5; break;
case '6': values = 6; break;
case '7': values = 7; break;
case '8': values = 8; break;
case '9': values = 9; break;
case 'T': values = 10; break;
case 'J': values = 11; break;
case 'Q': values = 12; break;
case 'K': values = 13; break;
default:
badCard = true;
}
Other functions:
bool isFlush(int suits[]) {
for(i = 1; i <= 4; i++)
if (suits[i] == 5) //5 here is Number of Cards
return true;
return false;
}
Yeah, I know about the array declarations but that is how it is defined- nice justification for it in the text...starting to number at 1
I want my straight hand to handle both Ace high and low- right now as define above aces are low...
Two versions: 1st appears not sure correct with low aces...
CODE
bool isStraight(int values[]) //Version one only straight- low aces only
{
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
return false;
}
Now this is the where I need some recommendation: to have a function to handle both ace high and low:
bool isStraight(int values[]) //Version handles both high and low
{
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
// if(i == 1 && values[1] != 0) //Check for high and low
// count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
return false;
}
Would what I have in comments work to handle both ace high and low...
Since i = 1 is represented as ace and not sure what values[1] is correct should it be values[13] or what...maybe something like
if (i == 1)
values[13] //not sure...
Recommendations-
do not want wholesale changes- just to have minor changes with what I have...I do not want to sort or solve by brute force i.e like values[1] == 1 && values [2] ==1 you get the point- the text does that already but I am trying to rewrite it this way...
Thanks...Hope I am getting across my modification I would like...
EDIT: I figured I'd would first answer your question directly. Lets first clear up how the original algorithm worked. Basically it loops from 1 to 13, and each time it sees a card in that slot, it adds to count. If anything ever breaks the sequence, it resets the counter. Finally, if the counter reaches 5, you have a straight.
I can't say off hand if your solution would work, I say give it a go. However, a simple quick patch to the original would probably go something like this:
//Version handles both high and low
bool isStraight(int values[]) {
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
// handle ace high.
if(count == 4 && values[1] != 0) {
return true;
}
return false;
}
Basically what that does is say "if we already have 4 in a row, and we've just looked at the very last card (the loop is over), then check an ace is there, if so, we do have a straight and it is ace high".
ORIGINAL ANSWER:
I think the easiest way to handle ace high and low is to have the "get rank" function have two modes, one which returns ace high, the other which returns ace low. Then just calculate the hand value for each case and take the better one.
Also, your get rank could be way simpler :-P.
int get_rank(char card) {
static const char *cards = "A23456789TJQK";
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
so if you want to have a get_rank which has an ace_high or an ace_low, you could do this:
int get_rank(char card, bool ace_high) {
static const char *cards_high = "23456789TJQKA";
static const char *cards_low = "A23456789TJQK";
const char *cards = ace_high ? cards_high : cards_low;
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
EDIT:
for fun, i've made a quick and dirty program which detects straights (handling both high and low ace). It is fairly simple, but could be shorter (also note that there is no attempt at buffer safety with these arrays, something of production quality should use something safer such as std::vector:
#include <algorithm>
#include <iostream>
#include <cstring>
int get_rank(char card, bool ace_high) {
static const char *cards_high = "23456789TJQKA";
static const char *cards_low = "A23456789TJQK";
const char *cards = ace_high ? cards_high : cards_low;
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
bool is_rank_less_low(int card1, int card2) {
return get_rank(card1, false) < get_rank(card2, false);
}
bool is_rank_less_high(int card1, int card2) {
return get_rank(card1, true) < get_rank(card2, true);
}
bool is_straight(int hand[], bool ace_high) {
std::sort(hand, hand + 5, ace_high ? is_rank_less_high : is_rank_less_low);
int rank = get_rank(hand[0], ace_high);
for(int i = 1; i < 5; ++i) {
int new_rank = get_rank(hand[i], ace_high);
if(new_rank != rank + 1) {
return false;
}
rank = new_rank;
}
return true;
}
bool is_straight(int hand[]) {
return is_straight(hand, false) || is_straight(hand, true);
}
int main() {
int hand1[5] = { 'T', 'J', 'Q', 'K', 'A' };
int hand2[5] = { 'A', '2', '3', '4', '5' };
std::cout << is_straight(hand1) << std::endl;
std::cout << is_straight(hand2) << std::endl;
}
The case where an ace-high straight exists can be found by changing the final test:
if (count == 5 || count == 4 && values[1] == 1) // 2nd case handles ace-high straight
return true;
It's a special case, so it must be handled separately.