Related
I'm trying to count the cats and dogs in a string. So,
for example:
if the string is "cc+dd-cd",:
I want to count 2 positive cats, 2 positive dogs, 1 negative cat, 1 negative dog (yes I know this is a weird way to count, but it's part of my assignment).
I thought about doing a for loop where I iterated over the string, then nested inside the for loop, I'd have a while loop that would run until a '-', then run until a '+' or the end. I started the code, and without even getting that far into it, it created an infinite loop.
Question: How can I fix it?
Thanks!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
while (k != '-'){
pdc = pdc + 1; //positive dog count
pcc = pcc + 1; //positive cat count
}
while (k != '+') {
ndc = ndc + 1;
ncc = ncc + 1;
}
}
The immediate issue is that the while loops check k's value, but don't modify it. So once you entered one of them you'll be stuck there infinitely as k doesn't change inside the loop's body.
I wouldn't bother with nested loops - I'd just go over the entire string in one loop, and evaluate each character in its turn. A neat way to accomplish this is to keep a state of whether you're adding or subtracting (according to whether you last encountered a + or a - sign:
bool positive = true;
string animalparkString = "cc+dd-cd";
for (int k = 0; k < animalparkString.size(); k++) {
char ch = animalparkString[k];
switch (ch) {
case '+':
positive = true;
break;
case '-':
positive = false;
break;
case 'c':
if (positive) {
pcc++;
} else {
ncc++
}
break;
case 'd':
if (positive) {
pdc++;
} else {
ndc++
}
break;
}
}
This post describes iterating all characters is a string.
This is a simple solution using modern C++:
int sign = 1;
int dogs_count = 0, cats_count = 0;
std::string animalparkString = "-cccccc+dddd-cd";
for (const char& ch : animalparkString)
{
switch (ch) {
case '+':
sign = 1;
continue;
case '-':
sign = -1;
continue;
case 'c':
cats_count += sign;
continue;
case 'd':
dogs_count += sign;
continue;
}
}
std::cout <<"dogs: " << dogs_count << " cats: " <<cats_count;
A couple of suggestions to help you get started:
1. Use online c++ compilers to quickly test code
2. If your code doesn't behave as expected, use step-by-step debugging in your IDE or print our variables as you go using std::cout
3. Explicitly stating namespace is considered good practice. i.e:
// preferable:
std::string myString;
// avoid:
using namespace std;
string myString
To make your code work without too many changes , you can simply replace the while() condition with an if(). Moreover, instead of checking the iterator value k, you should compare the kth string element animalparkString[k].
Then you might start wondering if the code you wrote is actually doing what you expect. Possible questions you could try to answer is "how do I distinguish between positive or negative counts" and, then, "how do I distinguish between cats and dogs "? You will probably need to check also for cs and ds, not only for the operation sign!
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}
Note that if you write while( k != '-'), it will always evaluate true and, therefore, you will be stuck there. If it is the first time working with for-loops, consider printing the iterator value, to understand when and where you are stuck.
string animalparkString = "cc+dd-cd"
for (int k = 0; k != animalparkString.size(); k++)
{
std::cout << "for-loop iteration number: " << k << std::endl;
if(animalparkStrink[k] != '-'){
// Now you know, there will be a pos count. Dog or Cat?
}
if(animalparkString[k] != '+') {
// Now you know, there will be a neg count. Dog or Cat?
}
}
for and while together approach is unnecessarily complicated. Here's a simpler solution:
#include <concepts>
#include <iostream>
int main() {
auto const& str{"cc+dd-cd"};
std::boolean auto isPositive = 1;
std::integral auto pdc{0}, pcc{0}, ndc{0}, ncc{0};
for (char const ch : str) {
switch (ch) {
case 'c': {
pcc += isPositive;
ncc += !isPositive;
break;
}
case 'd': {
pdc += isPositive;
ndc += !isPositive;
break;
}
case '+': {
isPositive = true;
break;
}
case '-': {
isPositive = false;
break;
}
}
}
std::cout << "pcc: " << pcc << '\n'
<< "ncc: " << ncc << '\n'
<< "pdc: " << pdc << '\n'
<< "ndc: " << ndc << '\n';
}
LIVE
I've developed a program that reads numbers from .txt file where it will store into a vector to undergone a series of combinations and calculations to determine whether the result matches the number that I've wanted. These process will be done in multiple threads, where each thread will be in charge of handling various number of iterations within the parallel for loop.
Long story short, the processing time varies a lot when it comes to large number (e.g. 9 numbers) where the processing time could be as short as 3 minutes or it could be more than 10 minutes.
Here's the benchmark that I've tried so far:
8 numbers serial : 18.119 seconds
8 numbers multithread (first-try): 10.238 seconds
8 numbers multithread (second-try): 18.943 seconds
9 numbers serial : 458.980 seconds
9 numbers multithread (first-try): 172.347 seconds
9 numbers multithread (second-try): 519.532 seconds //Seriously?
//Another try after suggested modifications
9 numbers multithread (first-try): 297.017 seconds
9 numbers multithread (second-try): 297.85 seconds
9 numbers multithread (third-try): 304.755 seconds
9 numbers multithread (fourth-try): 396.391 seconds
So the question is, is there any possible way to improve the program (multi-thread) so that it only requires the least amount of time to shuffle/calculate the numbers?
Here's a portion of the code where parallel for loop occurs (Updated with slight modifications):
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <Windows.h>
#include <omp.h>
#define OPERATORSIZE 3
using namespace std;
int cur_target;
ofstream outFile;
string get_operator(int i) {
switch (i) {
case 0:
return "+";
case 1:
return "-";
case 2:
return "*";
case 3:
return "/";
default:
return "";
}
}
int prev_num_pos(vector<int> &cur_equation, int count) {
for (int i = count - 1; i >= 0; i--) {
if (cur_equation[i] != -1) return i + 1;
}
return 0;
}
bool nextoperator(int k, vector<int> &operator_array) {
for (int i = k - 2; i >= 0; i--) {
if (operator_array[i] < OPERATORSIZE) {
operator_array[i] += 1;
break;
}
else
operator_array[i] = 0;
switch (i) {
case 0:
return false;
}
}
return true;
}
void vector_combination(vector<int> int_list) { // Generate the number combinations from the number list
bool div_remainder = false;
int count = 0;
#pragma omp parallel for schedule(dynamic) firstprivate(div_remainder) reduction(+:count)
for (int i = 0; i < int_list.size(); ++i) {
vector<int> cur_equation, cur_temp, cur_list, operator_array;
auto list = int_list;
rotate(list.begin(), list.begin() + i, list.begin() + i + 1);
do
{
cur_list.clear();
operator_array.clear();
for (auto x : list)
cur_list.push_back(x);
for (int i = 0; i < cur_list.size() - 1; i++)
operator_array.push_back(0);
do
{
div_remainder = false;
count = 0;
cur_equation = operator_array;
cur_temp = cur_list;
for (int i = 0; i < cur_equation.size(); ++i) { // Check for equation priorities
if (cur_equation[i] == 3) {
count = i;
if (cur_temp[count] % cur_temp[count + 1] != 0) {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
count = -1;
if (cur_equation[i] == 2 || cur_equation[i] == 3) {
count = prev_num_pos(cur_equation, i);
}
else
continue;
if (cur_equation[i] == 2) {
cur_temp[count] *= cur_temp[i + 1];
cur_equation[i] = -1;
}
else if (cur_equation[i] == 3) {
if (cur_temp[i + 1] != 0) {
cur_temp[count] /= cur_temp[i + 1];
cur_equation[i] = -1;
}
else {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
switch (cur_equation[i]) {
case 0: {
cur_temp[0] += cur_temp[i + 1]; // Addition
cur_equation[i] = -1;
break;
}
case 1: { // Subtraction
cur_temp[0] -= cur_temp[i + 1];
cur_equation[i] = -i;
break;
}
}
}
if (cur_temp[0] == cur_target) {
#pragma omp critical
{
for (int i = 0; i < cur_list.size(); ++i) {
outFile << cur_list[i];
if (i < cur_list.size() - 1) { outFile << get_operator(operator_array[i]); }
}
outFile << "\n";
}
}
} while (nextoperator(cur_list.size(), operator_array));
// Send to function to undergone a list of operator combinations
} while (next_permutation(list.begin() + 1, list.end()));
}
}
int main(void) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
vector<int> int_list;
string line;
ifstream myfile("Problem.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
int num = stoi(line);
int_list.push_back(num);
cur_target = num;
}
}
else
cout << "Unable to open file." << endl;
myfile.close();
int_list.pop_back();
sort(int_list.begin(), int_list.end());
outFile.open("answer.txt");
vector_combination(int_list);
outFile.close();
int answer_count = 0;
myfile.open("answer.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
++answer_count;
if (answer_count > 1)
break;
}
}
myfile.close();
if (answer_count == 0) {
outFile.open("answer.txt");
outFile << "-1" << endl;
}
outFile.close();
return 0;
}
As for the sample input, create a .txt file named "Problem.txt" with random numbers like so (The last number is the targeted result)(Updated with current sample input used for benchmark):
28
55
78
77
33
65
35
62
19
221
The hardware/software specification that the program runs on:
Processor: i5 Sandy Bridge 2500K,
Ram: 8GB,
OS: Windows 10 Professional,
IDE: Visual Studio 2015 Enterprise Edition,
Move the #pragma omp critical inside the if condition. Since cur_temp is thread private and cur_target is global read only, it is not necessary to protect the condition with a critical section.
This change drastically minimizes the direct interaction between the threads and, on my system, speeds up the parallel version consistently.
I would weakly guess the performance variations were influenced by the (seemingly random) phase shift between the loops running on different threads.
If performance variation persists, try enabling thread binding. Check the documentation of your OpenMP implementation, look for OMP_PROC_BIND, "thread pinning", "binding", or "affinity".
Apparently the runtime variance was caused by the vectors. I've checked it using performance analyzer and noticed the time spent on copying the values between vectors was not consistent. I've modified it to pointer array instead and the runtime is now improved tremendously and consistent.
A problem has risen in my OpenGL code which looked so simple but it doesn't seem to work like I expected it to be.
The code is as follows:
int x = 0, y = 0, z = 0, TP = 1;
bool initiate_placement = true;
float trans[3][3][2] = {{{-16.0,16.0},{0.0,16.0},{16.0,16.0}},
{{-16.0,0.0},{0.0,0.0},{16.0,0.0}},
{{-16.0,-16.0},{0,-16.0},{16.0,-16.0}}};
vector<tiles> Place;
tiles VER, HOR, NOREA, NORWE, SOUEA, SOUWE, TNOR, TSOU, TEA, TWE, CRO;
void Tile_Placement()
{
int A = rand() % 10 + 1;
if (TP <= 9)
{
switch (A)
{
case 1:
VER.vertical(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(VER);
break;
case 2:
HOR.horizontal(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(HOR);
break;
case 3:
NOREA.north2east(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(NOREA);
break;
case 4:
NORWE.north2west(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(NORWE);
break;
case 5:
SOUEA.south2east(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(SOUEA);
break;
case 6:
SOUWE.south2west(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(SOUWE);
break;
case 7:
TNOR.T_north(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(TNOR);
break;
case 8:
TSOU.T_south(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(TSOU);
break;
case 9:
TEA.T_east(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(TEA);
break;
case 10:
TWE.T_west(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(TWE);
break;
case 11:
CRO.cross(trans[x][y][z],trans[x][y][z + 1]);
Place.push_back(CRO);
break;
}
cout << trans[x][y][z] << " , " << trans[x][y][z + 1] << endl;
}
}
void Tile_LoopZ()
{
if (z < 1)
{
Tile_Placement();
TP++;
z++;
Tile_LoopZ();
}
z = 0;
}
void Tile_LoopY()
{
if (y < 3)
{
Tile_LoopZ();
y++;
Tile_LoopY();
}
y = 0;
}
void Tile_LoopX()
{
if (initiate_placement == true)
{
if (x < 3)
{
Tile_LoopY();
x++;
Tile_LoopX();
x = 0;
}
}
initiate_placement = false; //<<< problem is focused here
x = 0, y = 0, z = 0, TP = 1;
}
void gameScene()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLineWidth(2.0);
glColor3f(1.0, 1.0, 1.0);
Tile_LoopX();
glutSwapBuffers();
}
The code here tells me that in the recursive function Tile_LoopX();, once initiate_placement == true, a code happens that pushes back nine tiles. Once the nine tiles are pushed back, it makes initiate_placement false, that way if gameScene() is called again, Tile_LoopX(); wont be able to run its code.
The things that I know so far is that gameScene() is an infinite loop. Removing initiate_placement = false; makes the tiles randomly spaz out because it's called over and over again. Placing initiate_placement = false; sounds like a good solution but the tiles were never pushed back at all. To test that the code passes through, I added a cout and it actually passes through.
If anything, I might have missed something completely simple and I really need help for it.
UPDATE 4/16/15:
The vectors do get pushed back as I cout'ed the vector's size (which is 9). The problem now lies that the objects within the vector were never visually shown in the program, or even able to use its code within the program.
I'm doing a poker game and have hit a wall. Any help would be great.
I have 12 card values. The values are chars either 2-9 or TJQKA (enumed below). I need to pass them to an int array such that their value is what gets passed (whether int value or enum value) instead of their ASCII.
for the example below, I want:
val[5] = {2,5,10,12,11}
instead of:
val[5] = {50,53,84,81,74}
enum cardvalues {T=10 , J , Q , K , A}
int val[5];
string value = "25TQJ";
for (int i = 0; i < 5; i++)
{
val[i] = value[i];
}
I would highly recommend using a map rather than an enum.
map<char,int> myCardMap;
myCardMap['T'] = 10;
...
val[i] = myCardMap[value[i]];
You'll need a conversion function:
int to_card(const char v)
{
switch(v)
{
case '2': return 2;
case '3': return 3:
// etc...
case 'T': return 10;
case 'J': return 11;
// etc...
}
Then in your loop:
val[i] = to_card(value[i]);
Make an std::map with ascii values in key and enum values in value
std::map<char, int> asciiMap;
asciiMap['T'] = 10;
asciiMap['J'] = 11;
//etc....
and then match the characters with the map
Generally you would need to convert the values from char to int. Here's the easiest way.
int convert_from_char(char c) {
if (c >= '2' && c <= '9') return (int)(c - '0');
else {
switch(c) {
case 'T': return (int)T;
case 'J': return (int)J;
case 'Q': return (int)Q;
case 'K': return (int)K;
case 'A': return (int)A;
default:
/* your program is borked. */
exit(1);
}
}
}
Then change your loop
for (int i = 0; i < 5; ++i)
val[i] = convert_from_char(value[i]);
I would suggest reconsidering using enums to represent cards, though. It will be easier in the long run just to make your own type, or use integers.
There is no way to directly convert from an enum symbol to the corresponding integer in C++ at runtime (obviously the compiler can do this at compile time). You may need to write a small helper function:
int card_value(char c) {
if (isdigit(c)) {
return c - '0';
} else {
switch (c) {
case 'T': return 10;
case 'J': return 11;
case 'Q': return 12;
case 'K': return 13;
case 'A': return 14;
default:
// whatever error handling here, such as:
return -1;
}
}
}
I suggest a switch:
switch (value[i]) {
case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
val[i] = atoi(value[i]);
break;
case 'T':
val[i] = 10;
break;
case 'J':
val[i] = 11;
break;
case 'Q':
val[i] = 12;
break;
case 'K':
val[i] = 13;
break;
case 'A':
val[i] = 14;
break;
default:
printf("Invalid character passed\n");
}
Create a function that will take a char argument (the ASCII card value, such as 'J') and return its numerical value. You might find the isdigit function and switch statement helpful.
If im understanding you correctly, you want to convert the string into card values (although for some reason you have the ace as 13 - id be tempted to say use 1 as the ace, although i can see you logic for it in a poker game).
Just using an enum wont help as at runtime you dont really have the information you need. An enum is a compile time concept mainly to assist the programmer and to handle checking.
There are many way to do what you want, you could have an array of index to char or a two entry array of char and value. For ease of alterations i would go with the following
typedef struct
{
char m_cCharacter;
int m_nValue;
} LOOKUP;
LOOKUP lookup_data[] = {
{ "2", 2 },
{ "3", 3 },
{ "4", 4 },
{ "5", 5 },
{ "6", 6 },
{ "7", 7 },
{ "8", 8 },
{ "9", 9 },
{ "T", 10 },
{ "J", 11 },
{ "Q", 12 },
{ "K", 13 },
{ "A", 14 }
};
int GetCharacter(char c)
{
int retval = -1; // Invalid
for(int i = 0; i < 13; i++)
{
if ( lookup_data[i].m_cCharacter == c )
{
retval = lookup_data[i].m_nValue;
break;
}
}
return retval;
}
for (int i = 0; i < 5; i++)
{
val[i] = GetCharacter(value[i]);
}
There are better ways with STL, and you should have more error checking and length of array detections, but hopefully you get the idea. You could use the enum in the lookup such as
{ "T", T },
If you preferred. Btw - i havent compiled this code so it probably wont build ;)
Try building a static array of size 256 such that the following gives the right answer:
for (int i = 0; i < 5; i++)
{
val[i] = AsciiToInt[value[i]];
}
That is,
AsciiToInt['2'] == 2
AsciiToint['T'] == 10,
AsciiToInt['J'] == 11
etc, but all invalid entries are zero.
I have 8 different arrays, and each array has 8 characters in it,
std::string str_v1 = v1.to_string();
char arr_v1[9] = {0};
std::copy(str_v1.begin(), str_v1.end(), arr_v1); // from str_v1 to str_v8
std::string str_v8 = v8.to_string();
char arr_v8[9] = {0};
std::copy(str_v8.begin(), str_v8.end(), arr_v8);
how to convert this into 8x8 matrix? I want to put these values column by column, like, each array is converted to one column of the matrix, like array1 to column1, array2 to column2, and so on, like array1 values will be placed like matrix[0][0], matrix[1][0], matrix[2][0] and so on..
I think, something like this needs to be done:
char matrix[8][8];
for( int y=0;y<8;y++)
{
matrix[y][0] = arr_v1[y];
matrix[y][1] = arr_v2[y];
matrix[y][2] = arr_v3[y];
matrix[y][3] = arr_v4[y];
matrix[y][4] = arr_v5[y];
matrix[y][5] = arr_v6[y];
matrix[y][6] = arr_v7[y];
matrix[y][7] = arr_v8[y];
}
for( int y=0;y<8;y++)
{
for( int z=0;z<8;z++)
{
switch(y)
{
case 0:
matrix[z][y] = arr_v1[z]; //Be pretty sure, possibly you are better than you believe
break; // I've placed y before z as y is the outer loop, hence it
case 1: // should be responsible for ROWS and z for COLUMNS
matrix[z][y] = arr_v2[z]; // Goes in matrix[0][1],[1][1],[2][1],[3][1]...[7][1]
break;
case 2:
matrix[z][y] = arr_v3[z]; // Goes in matrix[0][2],[1][2],[2][2],[3][2]...[7][2]
break;
case 3:
matrix[z][y] = arr_v4[z]; // Goes on
break;
case 4:
matrix[z][y] = arr_v5[z]; // And on
break;
case 5:
matrix[z][y] = arr_v6[z]; // And on
break;
case 6:
matrix[z][y] = arr_v7[z];
break;
case 7:
matrix[z][y] = arr_v8[z];
break;
}
} // Finally all 8 1x8 arrays stored into single 8x8 matrix
}
There you have it then your ways,each 1x8 coming as a COLUMN instead of a row as in previous one :)
char *matrix[9];
for (int i = 0; i < 9; ++i) {
matrix[i] = new char[9];
std::copy(your_ith_string.begin(), your_ith_string.end(), matrix[i]);
}
//Finish your work with the matrix
for (int i = 0; i < 9; ++i) {
delete[] matrix[i];
}
You yourself were quite correct :
for( int y=0;y<8;y++)
{
for( int z=0;z<8;z++)
{
switch(y)
{
case 0:
matrix[y][z] = arr_v1[z]; //Be pretty sure, possibly you are better than you believe
break; // I've placed y before z as y is the outer loop, hence it
case 1: // should be responsible for ROWS and z for COLUMNS
matrix[y][z] = arr_v2[z]; // Goes in matrix[1][0],[1][1],[1][2],[1][3]...[1][7]
break;
case 2:
matrix[y][z] = arr_v3[z]; // Goes in matrix[2][0],[2][1],[2][2],[2][3]...[2][7]
break;
case 3:
matrix[y][z] = arr_v4[z]; // Goes on
break;
case 4:
matrix[y][z] = arr_v5[z]; // And on
break;
case 5:
matrix[y][z] = arr_v6[z]; // And on
break;
case 6:
matrix[y][z] = arr_v7[z];
break;
case 7:
matrix[y][z] = arr_v8[z];
break;
}
} // Finally all 8 1x8 arrays stored into single 8x8 matrix
}
Hope this helps, if it doesn't just let me know, I'd be happy to help.
char matrix[8][8];
char *arr[8] = {arr_v1, arr_v2, arr_v3, arr_v4, arr_v5, arr_v6, arr_v7, arr_v8};
for( int y=0;y<8;y++) {
for (int i = 0; i < 8; ++i) {
matrix[y][i] = arr[i][y];
}
}