Grouping data in a File C++ - c++

I have the following text file strucutre:
<Game Draw> <Ticket ID> <Ticket Numbers>*6
<Game Draw> <Ticket ID> <Ticket Numbers>*6
Example:
123 ABACD T1245 5 8 10 13 25 63
123 ABACD T1245 6 7 9 12 61 63
252 FYHGO T9736 8 9 10 11 12 13
252 GTGOH T5436 10 11 12 13 14 15
Each Line is for a A lottery Ticket. - A Ticket can have multiple Lines - and a Draw can have multiple tickets.
I am wanting to do a filter on all of the results for a particular draw. Obviously, All of the players are not going to be in every draw - and a draw can have multiple tickets in (with multiple ticket Lines). IS it therefore possible to group all of the tickets into multiple layers (A Map - within a Map?) so that I can easily process this information. Or Am I best off just processing this all line by line and putting it into a structure of some description.
Many thanks,

I think you may need to use regular expression and a user-define structure for processing as well.
This code is just a little code snippet.
//Originally, each data is from txt file.
//but, this is just sample.
struct Ticket_Info
{
int first_number;
string game_draw;
string ticket_id;
int ticket_numbers[MAX_TICKET_NUMBER];
} tickets[] =
{
{123, "ABACD", "T1245", {5, 8, 10, 13, 25, 63}}
, {123, "ABACD", "T1245", {6, 7, 9, 12, 61, 63}}
, {252, "FYHGO", "T9736", {8, 9, 10, 11, 12, 13}}
, {252, "GTGOH", "T5436", {10, 11, 12, 13, 14, 15}}
};
std::regex match_draw_key("FYHGO");
for_each(std::begin(tickets), std::end(tickets), [&](const Ticket_Info &ticket)
{
std::cout << ticket.ticket_id << ": " << std::regex_match(ticket.game_draw, match_draw_key) << '\n';
});
I hope this will help you a little.

Related

Construct cv::Mat via C++ 1D array

I took over a program, which use 1d array to construct cv::Mat. I'm confuse about it, and I make a demo:
int main()
{
short data[] = {
11, 12, 13, 14,
21, 22, 23, 24,
31, 32, 33, 34,
43, 42, 43, 44
};
cv::Mat m{ 4, 4, CV_8U, data};
cv::imwrite("test.png", m);
return 0;
}
I expect the output is
11 12 13 14
21 22 23 24
31 32 33 34
43 42 43 44
But I open the img in MATLAB:
11 0 12 0
13 0 14 0
21 0 22 0
23 0 24 0
The 3rd parameter in the constructor you used for cv::Mat (CV_8U) specifies the format of the data buffer.
Your data is an array of short, i.e. each entry is 2 bytes. When you use values small values like you did, it means one of the bytes for each short will be 0.
When you use this buffer to initialized a cv::Mat of type CV_8U you tell opencv to treat the buffer as containing unsigned chars (1 byte elements). So each short is interpreted as 2 unsigned char bytes.
This is why you get the zeroes in the output.
Eaither change the type of the data buffer to unsigned char [], or change the cv::Mat data type to e.g. CV_16S. The 2 should usually match.
You can do it e.g. like this:
unsigned char data[] = {
11, 12, 13, 14,
21, 22, 23, 24,
31, 32, 33, 34,
43, 42, 43, 44
};
cv::Mat m{ 4, 4, CV_8U, data };
You can see the list of opencv data types here (in the Data types section):
https://docs.opencv.org/3.4/d1/d1b/group__core__hal__interface.html

Opencv image to array issue

Im having an issue using opencv trying to convert an image to an array. The conversion works however i seem to have incorrect dimensions in the resulting array:
#include <opencv2/opencv.hpp>
int main()
{
auto img = cv::imread("test.jpg", CV_LOAD_IMAGE_COLOR);
std::cout << "img cols: " << img.cols << " img rows: "
<< img.rows << " channels: " << img.channels() << std::endl;
std::vector<float> array2;
if (img.isContinuous()) {
array2.assign((float*)img.ptr(0), (float*)(img.ptr(img.rows - 1)) + img.cols);
std::cout << array2.size() << "\n";
}
return 0;
}
The output from the first print line results in :
img cols: 416 img rows: 416 channels: 3
Which is correct, however after assigning the data to the array the dimensions are : 518336 , when they should be 519168 (416*416*3).
Could anyone possibly suggest what exactly is causing the resulting array to be smaller than expected?
There are several problems with your code:
First of all, cv::imread("test.jpg", CV_LOAD_IMAGE_COLOR); will (on success) return a cv::Mat with datatype CV_8UC3, however you're accessing the elements as floats. This means that the values you will read will be garbage, and you will also end up reading past the end of the pixel buffer.
If you want floats, then you need to do some conversion/casting, either before or during the act of copying.
The second problem lies in your calculation of the "end" pointer, where you seem to forget that you're dealing with a multi-channel cv::Mat. In case of a CV_8UC3 matrix, each pixel is represented by 3 bytes, hence there are cols*channels bytes per row. (That's why you're short by 2*416 elements)
Not really a problem, but a limitation -- your code only works for continuous Mats.
I would take a somewhat different approach, and take advantage of functionality provided by OpenCV.
Option 1
Use cv::Mat::copyTo, since OutputArray can wrap a std::vector<T>. However, for this to work, the source Mat needs to have 1 channel and 1 row. We can achieve this efficiently using cv::Mat::reshape, but the Mat needs to be continuous, so that limitation stays.
std::vector<uchar> to_array_v1(cv::Mat3b const& img)
{
std::vector<uchar> a;
if (img.isContinuous()) {
img.reshape(1, 1).copyTo(a);
}
return a;
}
Option 2
Use MatIterators which we can get using cv::Mat::begin and cv::Mat::end. The iterators will work correctly even on a non-continuous Mat, however we need them to iterate over bytes, so we need to reshape the matrix to a single channel one. Since we're not changing the number of rows, the reshape will also work on a non-continuous Mat.
std::vector<uchar> to_array_v2(cv::Mat3b const& img)
{
cv::Mat1b tmp(img.reshape(1));
return std::vector<uchar>(tmp.begin(), tmp.end());
}
Option 3
The approach suggested by Silencer, using the rather poorly documented cv::Mat::datastart and cv::Mat::dataend members. The documentation of cv::Mat::locateROI sheds some more light on the meaning of those member variables:
However, each submatrix contains information (represented by datastart and dataend fields) that helps reconstruct the original matrix size and the position of the extracted submatrix within the original matrix.
This means that this approach has 2 limitations: it needs a continous matrix, and it won't work correctly for a submatrix, even if it's continuous. (Specifically, for a continuous submatrix, it would return the entire buffer of the "parent" matrix)
std::vector<uchar> to_array_v3(cv::Mat3b const& img)
{
std::vector<uchar> a;
if (img.isContinuous() && !img.isSubmatrix()) {
a.assign(img.datastart, img.dataend);
}
return a;
}
Test Code
#include <opencv2/opencv.hpp>
#include <iostream>
#include <numeric>
#include <vector>
// Paste implementations from the answer here
cv::Mat3b test_image()
{
cv::Mat1b m(4, 4);
std::iota(m.begin(), m.end(), 0);
cv::Mat3b img;
cv::merge(std::vector<cv::Mat1b>{ m * 3, m * 3 + 1, m * 3 + 2 }, img);
return img;
}
void print(cv::Mat3b const& img)
{
std::cout << "Continuous: " << (img.isContinuous() ? "yes" : "no") << '\n';
std::cout << "Submatrix: " << (img.isSubmatrix() ? "yes" : "no") << '\n';
std::cout << img << "\n";
}
void print(std::vector<uchar> const& a)
{
if (a.empty()) {
std::cout << "empty";
} else {
for (auto n : a) {
std::cout << int(n) << ' ';
}
}
std::cout << "\n";
}
void test(cv::Mat3b const& img)
{
print(img);
print(to_array_v1(img));
print(to_array_v2(img));
print(to_array_v3(img));
}
int main()
{
cv::Mat3b img(test_image());
test(img);
cv::Mat3b img2(img(cv::Rect(0, 0, 3, 3)));
test(img2);
cv::Mat3b img3(img(cv::Rect(1, 1, 3, 1)));
test(img3);
return 0;
}
Running this program will produce the following output:
Continuous: yes
Submatrix: no
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11;
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23;
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35;
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
Continuous: no
Submatrix: yes
[ 0, 1, 2, 3, 4, 5, 6, 7, 8;
12, 13, 14, 15, 16, 17, 18, 19, 20;
24, 25, 26, 27, 28, 29, 30, 31, 32]
empty
0 1 2 3 4 5 6 7 8 12 13 14 15 16 17 18 19 20 24 25 26 27 28 29 30 31 32
empty
Continuous: yes
Submatrix: yes
[ 15, 16, 17, 18, 19, 20, 21, 22, 23]
15 16 17 18 19 20 21 22 23
15 16 17 18 19 20 21 22 23
empty
Mat img = imread("test.png");
std::vector<uchar> arr;
// convert Mat of CV_8UC3 to std::vector<uchar> if continuous
if(img.isContinuous()){
arr.assign(img.datastart, img.dataend);
}

C++ Armadillo Access Triangular Matrix Elements

What would be the most efficient (i.e. balance memory and speed) way to access the upper or lower triangular elements of an Armadillo matrix? I know I could provide a vector of integers for the elements but as matrices become very large I would like avoid carrying around another large vector. Or is there an efficient way to quickly create the lower/upper triangular indices?
For example with a 5x5 matrix
// C++11 Initialization
arma::mat B = { 1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
16, 17, 18, 19, 20,
21, 22, 23, 24, 25 };
B.reshape(5,5);
// the matrix
//1 6 11 16 21
//2 7 12 17 22
//3 8 13 18 23
//4 9 14 19 24
//5 10 15 20 25
I would like to pull the elements in the lower triangle where the result vector would be:
2 3 4 5 8 9 10 14 15 20
The only solution I can think of right now is using a uvec object. For example:
arma::uvec idx {1,2,3,4,7,8,9,13,14,19);
arma::vec lower_elems = B.elem(idx);
The final object doesn't need to be a vector. I just need to be able to access the elements for various comparisons. As a simple example let's say I would want to check if they all equal 0.
To check if all the elements in the lower triangle are equal to zero:
bool all_zero = all( X.elem(find(trimatl(X))) == 0 );
Armadillo 9.900 has the functions trimatu_ind() and trimatl_ind(). These functions provide the indices of the upper and lower triangular portions of a matrix. These indices can be used with .elem() to access the elements in upper/lower triangular portions.
There are also the functions .is_trimatu() and .is_trimatl() which check if a matrix is upper/lower trinagular.

Powerball number generator

To win the Powerball lottery (an extremely unlikely event so don't waste your time) you have to pick six numbers correctly. The first five numbers are drawn from a drum containing 53 balls and the sixth is drawn from a drum containing 42 balls. The chances of doing this are 1 in 120,526,770.
The output needs to be in the form:
Official (but fruitless) Powerball number generator
How many sets of numbers? 3
Your numbers: 3 12 14 26 47 Powerball: 2
Your numbers: 1 4 31 34 51 Powerball: 17
Your numbers: 10 12 49 50 53 Powerball: 35
import random
#Powerball
print "Offical Powerball number generaor"
x = int(raw_input("How many sets of numbers? "))
z = range(1,42)
z1 = random.choice(z)
def list1():
l1=[]
n=1
while n<=5:
y = range(1,53)
y1 = random.choice(y)
l1.append(y1)
n +=1
print sorted(l1)
i=1
while i<=x:
# print "Your numbers: " + list1() + "Powerball: "+ str(z1)
print list1()
raw_input("Press<enter>")
My code's output goes on a infinite loop. I have to kill it. And the message is:
None
[2, 7, 22, 33, 42]
None
[15, 19, 19, 26, 48]
None
[1, 5, 7, 26, 41]
None
[7, 42, 42, 42, 51]
None
..... etc ....
while i<=x: - you never increment i, so it is stuck in your last loop...
To avoid such things and remove the noise of i+=1 lines in your code I suggest using for loops for i in range(x) and for n in range(5).
Better yet, the following expression can replace list1:
[random.choice(range(1,53)) for x in xrange(5)]
At least, that does the same as your code. But what you probably really want (to avoid the same ball being chosen twice) is:
random.sample( range(1,53), 5 )

How to pull information from an external source into a game

I am trying to find a way to import stat data into a game in progress Via spread sheets? Here's what I am working with:
Right now for example.. The spells, in order to name them, set stats, ect and be able to call them via Number I Have something like this going on in the actual code:
void spell(int & eMoney, int eSpell[10])
{
using namespace std;
char spellname[10][25] = {"Minor Heal", "Fire Shard", "Lightening Shard", "Ice Shard", "Magic Barrier", "Essence Of Life",
"Earth Shard", "Wind Shard", "Insigma", "Weaken"};
int spellcost[10] = {50, 80, 80, 80, 100, 100, 80, 80, 120, 80};
Which is all fine and dandy, it works... But it's an issue now and later.. I want to be able to use a spread sheet, like a CSV file, so I can have a spread sheet for like just spells, just swords, just clubs... I plan to have a very large selection, it's more ideal to be able to edit a single file in columns and rows and have the actual game pull the information from an external file when it's needed... But I am not able to figure out how to go about this? I am open to any ideas..
Here is an example of how I call on a spell's info now:
case 2:
do
{
cout << "Which spell would you like to cast?\n\n";
for(x=0;x<10;x++)
cout << x+1 << ". " << spellname[x] << ": " << eSpell[x] << " left" << endl;
cout << "11. Leave\n\n>> ";
cin >> decision;
system("cls");
}
while((decision<1)&&(decision>11)||(eSpell[decision-1]==0));
switch(decision)
and here is an example of the spread sheet I have in mind basically? Starting at A1:
Type sName mDmg sPrice
Spell 1 Minor Heal 10 100
Spell 2 Fire Shard 12 100
Spell 3 Lightening Shard 12 200
Spell 4 Ice Shard 12 150
Spell 5 Magic Barrier 10 130
Spell 6 Essence Of Life 15 10
Spell 7 Earth Shard 12 120
Spell 8 Wind Shard 12 230
Spell 9 Insigma 12 90
Spell 10 Weaken 12 100
Another Example:
Current Code:
char monsters[16][25] = {"Wolf", "Bear", "Bandit", "Traveler", "Gargoyle", "Knight", "Warlock", "Mammoth", "Cyclops", "Unicorn", "Dragon", "Your Mother", "Demon", "Jesus", "Satan", "God"};
//monster strengths
int monsterdamagemax[16] = {32, 42, 53, 53, 65, 65, 75, 75, 85, 85, 90, 90, 95, 95, 110, 110};
int monsterdamagemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int monsterdefensemax[16] = {2, 7, 13, 13, 20, 20, 25, 25, 35, 35, 40, 40, 45, 45, 55, 55};
int monsterdefensemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int monsterhealth[16] = {32, 52, 73, 73, 95, 95, 118, 118, 142, 142, 167, 167, 193, 193, 220, 220};
int monsterspeed[16] = {7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15};
int monstergold[16] = {20, 30, 41, 41, 53, 53, 66, 66, 80, 80, 95, 95, 110, 110, 125, 125};
Ideally, I want to be able to get all that from a CSV file like:
mID mName mDmgMax mDmgMin mDefMax mDefMin mHp mSpeed mGold
1 Wolf 32 0 2 0 32 7 20
2 Bear 42 0 7 0 52 8 30
3 Bandit 53 0 13 0 73 9 41
4 Traveler 53 0 13 0 73 9 41
5 Gargoyle 65 0 20 0 95 10 53
6 Knight 65 0 20 0 95 10 53
7 Warlock 75 0 25 0 118 11 66
8 Mammoth 75 0 25 0 118 11 66
9 Cyclops 85 0 35 0 142 12 80
10 Unicorn 85 0 35 0 142 12 80
11 Dragon 90 0 40 0 167 13 95
12 Your Mother 90 0 40 0 167 13 95
13 Demon 95 0 45 0 193 14 110
14 Jesus 95 0 45 0 193 14 110
15 Statan 110 0 55 0 220 15 125
16 God 110 0 55 0 220 15 125
How about writing a small command based application that creates records for you, and in your "main" program that is game, you just have to read these records.
A sample structure -
struct monster
{
int mID;
char mName[25]; //from your code
int mDmgMax;
//and these as well mDmgMin mDefMax mDefMin mHp mSpeed mGold
};
in this "helper" program read each data item (like the mName) in a record one by one, and insert in this structure. Write the structure to monsters.dat file
std::ofstream fout;
fout.open("monsters.dat", std::ios::app | std::ios::binary);
fout.write( (char*) &monsterInstance, sizeof(monsterInstance) );
fout.close();
This will simply append records. (I have skipped error checking and reading data.)
For greater ease, this program should be able to show current monsters, add monster, delete monster (by entering mID).
Reading such records in your main program should be a easy task.
If you're going to have a lot of table-based data to keep around, you might look into using SQLite. It has some interesting costs and benefits.
On the down side (maybe), it's SQL. It can be a bit more complex and depending on your searching algorithm, could be slower. It also can't be edited by hand, you need something to open the database (there are free tools available).
On the up side, you get all the sorting and filtering power of a database (anything you'll need, like spell='fireball' AND damage < 5), and SQLite is fast (easily enough to store game data in, and very possibly faster than your own code). You can store all your data in a single file for easy deployment or modding, with unique tables for each type (weapons, spells, characters, etc), and no server involved (SQLite is a single DLL).
Relational databases excel at working with consistently-formed tables of data, which is exactly what you have in a game environment (each object type has a few fields, not much variation, maybe some blanks, with various data types). SQLite, despite being the smallest database, can handle thousands of rows with excellent time, so you won't have to worry about your game data becoming unwieldy (which happens very quickly with pure text table files, like NWN(2)'s 2DA format).
There is a learning curve to it, but you do gain some simplicity in the future (adding a new object type is a new table and queries, not a whole lot of code) and a very stable data format and load/save library. Depending on your needs, it may be worth a shot.
As pointed in question comments, you should go for <fstream> if you really want to deal with CSV files. Using that approach, getline should be enough for what you need.
This thread in C++.com and this question should point you some directions on how to handle CSV.
I use Boost to parse the CSV files I work with. Here's a simple example.
I agree with peachykeen though, SQLite may suit you better, but maybe this will help you get started.
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/tokenizer.hpp>
#include <boost/token_functions.hpp>
typedef std::vector<std::string> csvLine;
typedef std::vector<csvLine> csvLines;
typedef boost::tokenizer<boost::escaped_list_separator<char> > csvTokenizer;
csvLines ReadCSVFile(const std::string& fileName)
{
csvLines retVec;
std::ifstream inFile(fileName.c_str());
if(inFile)
{
std::string fileLine;
while(std::getline(inFile, fileLine))
{
csvTokenizer lineTokens(fileLine);
retVec.push_back(csvLine(lineTokens.begin(), lineTokens.end()));
}
inFile.close();
}
return retVec;
}
int main(int argc, char** argv)
{
csvLines lines(ReadCSVFile(argv[1]));
for(csvLines::iterator lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
{
for(csvLine::iterator tokenIt = (*lineIt).begin(); tokenIt != (*lineIt).end(); ++tokenIt)
{
std::cout << *tokenIt << " ";
}
std::cout << std::endl;
}
return 0;
}