How to initialize static member array with a result of a function? - c++

I'm translating such fragment of this Python file to C++:
SIDE = 3
LINES = []
for y in range(SIDE):
row = tuple((x, y) for x in range(SIDE))
LINES.append(row)
for x in range(SIDE):
col = tuple((x, y) for y in range(SIDE))
LINES.append(col)
LINES.append(tuple((x, x) for x in range(SIDE)))
LINES.append(tuple((SIDE - x - 1, x) for x in range(SIDE)))
LINES holds (x, y) coordinates of possible lines in Tic Tac Toe game. So for SIDE = 3 it holds:
[((0, 0), (1, 0), (2, 0)),
((0, 1), (1, 1), (2, 1)),
((0, 2), (1, 2), (2, 2)),
((0, 0), (0, 1), (0, 2)),
((1, 0), (1, 1), (1, 2)),
((2, 0), (2, 1), (2, 2)),
((0, 0), (1, 1), (2, 2)),
((2, 0), (1, 1), (0, 2))]
SIDE value can change.
What I've tried
Performance is crucial (that's why I reached for C++), so I would like to calculate LINES only once. Thus, I've chosen to implement LINES as a static member of the class TicTacToeState.
I started with such code:
static char init_lines() {
return 'a';
}
class TicTacToeState {
static char LINES;
};
char TicTacToeState::LINES = init_lines();
It works. How to change LINES to an array? Maybe vector will be better? With pairs?
Maybe static member is not the best choice, maybe there is an easier way?
How would you translate it to C++?
We know the size of LINES, it's always 2 * SIDE + 2.
Special requirement
All C++ code must be in one .cpp file, no headers. Why? Because this is fragment of a library for bot competitions and it's typical that you can submit only one file.

In C++ you can initialize static array members using group initialization
static int a[10] = {5}; //this will initialize first position item with 5 and rest with 0s
static char b[2] = {'b', 'b'};
static int c[2][2] = { {1,1}, {1,2} };
int main()
{
cout<< a[0] << endl; //output: 5
cout<< a[1] << endl; //output: 0
cout<< b[0] << endl; //output: b
cout<< c[0][1] << endl; //output: 1
}
Although the fact is you need to know size of the array not like in Python's list that are dynamically
If you need to insert to the table values calculated dynamically the best way to do this is to create factory method
static int** fact(int width, int height)
{
int** a;
a = new int*[width]; //we can do it when it is DYNAMIC array!
a[0] = new int[height];
a[1] = new int[height];
for(int i = 0; i < width; i++)
for(int k = 0; k < height; k++)
a[i][k] = i*k;
return a;
}
static int** c = fact(2, 2); //you can call it with your SIDE var
int main()
{
cout<< c[1][1] << endl; //output: 1
}
Of course you can process it in loops
The same approach will be proper when you will decide to use std Vector class which is equvalent of Python's dynamic list

I suppose you could do this using a lambda function like this:
#include <vector>
#include <iostream>
const auto SIDE = 3U;
struct coord
{
unsigned x;
unsigned y;
coord(unsigned x, unsigned y): x(x), y(y) {}
};
static const auto lines = [] // lambda function
{
// returned data structure
std::vector<std::vector<coord>> lines;
for(auto y = 0U; y < SIDE; ++y)
{
lines.emplace_back(); // add a new line to back()
for(auto x = 0U; x < SIDE; ++x)
lines.back().emplace_back(x, y); // add a new coord to that line
}
for(auto x = 0U; x < SIDE; ++x)
{
lines.emplace_back();
for(auto y = 0U; y < SIDE; ++y)
lines.back().emplace_back(x, y);
}
lines.emplace_back();
for(auto i = 0U; i < SIDE; ++i)
lines.back().emplace_back(i, i);
lines.emplace_back();
for(auto i = 0U; i < SIDE; ++i)
lines.back().emplace_back(SIDE - i - 1, i);
return lines;
}(); // NOTE: () is important to run the lambda function
int main()
{
for(auto const& line: lines)
{
std::cout << "(";
for(auto const& coord: line)
std::cout << "(" << coord.x << ", " << coord.y << ")";
std::cout << ")\n";
}
}
Output:
((0, 0)(1, 0)(2, 0))
((0, 1)(1, 1)(2, 1))
((0, 2)(1, 2)(2, 2))
((0, 0)(0, 1)(0, 2))
((1, 0)(1, 1)(1, 2))
((2, 0)(2, 1)(2, 2))
((0, 0)(1, 1)(2, 2))
((2, 0)(1, 1)(0, 2))

Related

Implement OpenGl-like MIRRORED_REPEAT

I am supposed to implement a MIRRORED_REPEAT for my raytracing textures. I looked at how it's defined in OpenGL https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf page 260 and then I tried it myself, first with a 1-dimesional array. The behaviour should be:
Basically it repeats the index into the array ( modulo ) but mirrors the input based on wether or not the offset is even or odd. ( 2nd image below )
#include <iostream>
int main() {
int values[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
const auto mod = [](const int a, const int n) noexcept
{
return (a % n + n) % n;
};
const auto mirror = [](const int a) noexcept
{
return a >= 0.f ? a : -(1 + a);
};
const auto mirrored_repeat = [&](const int x) noexcept {
return (10 - 1) - mirror(mod(x, 2 * 10)) - 10;
};
for(int i = -5; i < 6; ++i) {
std::cout << values[mirrored_repeat(i)] << std::endl;
}
}
This doesn't work however, but gives me nice undefined-behaviourish output instead x) Can someone tell me how I can do it properly?
If you replace the line
std::cout << values[mirrored_repeat(i)] << std::endl;
with
std::cout << mirrored_repeat(i) << std::endl;
you'll see that the indices returned by mirrored_repeat are clearly wrong (they are negative, to begin with).
I believe the formula in the spec is a bit wrong, for it has one mismatched bracket. If we rewrite the line
return (10 - 1) - mirror(mod(x, 2 * 10)) - 10;
like this
return (10 - 1) - mirror(mod(x, 2 * 10) - 10);
the code starts producing something more reasonable.
For anyone interested, I derived a shorter solution while working on Blender:
C++
#include <iostream>
int main() {
const auto mirrored_repeat = [&](int x, const int size) noexcept {
x = std::abs(x + (x < 0)) % (2 * size);
return x >= size ? 2 * size - x - 1 : x;
};
for (int i = -6; i < 5; ++i) {
std::cout << mirrored_repeat(i, 10) << std::endl;
}
}
JavaScript demo
function mirrored_repeat(x, size) {
x = Math.abs(x + (x < 0)) % (2 * size);
return x >= size ? 2 * size - x - 1 : x;
}
for (let i = -6; i < 5; ++i) {
console.log(mirrored_repeat(i, 10));
}
I wanted to reduce the number of modulo calls, so I used the symmetry of C++ modulo for odd sections and the if statement for even sections.
For information on how I derived it, see my explanation here.

Why does the second variable not change in the field?

I'm testing some programms for my lectures. I'm creating classes and use a paramterlist to initalize a field but the second variable doesn't change.
#include <iostream>
using namespace std;
class Punkt {
int x;
int y;
public:
Punkt(int a = 0, int b = 0)
{
x = a;
y = b;
}
void printXY()
{
cout << "x= " << x << " y= " << y << endl;
}
};
int main() {
Punkt pFeld[] = { (1, 1), (2, 2), (3, 3) };
for (int i = 0; i < 3; i++)
pFeld[i].printXY();
cin.get();
};
No error messages. Expected result was that x and y change, while actual result is that only x changes and y stays 0.
This
(1, 1)
is an expression with the comma operator.
In fact this initialization
Punkt pFeld[] = { (1, 1), (2, 2), (3, 3) };
is equivalent to
Punkt pFeld[] = { 1, 2, 3 };
So the constructor with the second default argument equal to 0 is called three times.
Use instead
{ 1, 1 }
Here is your updated code
#include <iostream>
using namespace std;
class Punkt {
int x;
int y;
public:
Punkt(int a = 0, int b = 0)
{
x = a;
y = b;
}
void printXY()
{
cout << "x= " << x << " y= " << y << endl;
}
};
int main() {
Punkt pFeld[] = { {1, 1}, {2, 2}, {3, 3} };
for (int i = 0; i < 3; i++)
pFeld[i].printXY();
cin.get();
}
Its output is
x= 1 y= 1
x= 2 y= 2
x= 3 y= 3
Pay attention to that the semicolon after the function main is redundant.
Passing (1, 1) to the constructor of Punkt, the comma operator will return the 2nd operand as the result (the 1st operand is discarded), so you're only passing one int with value 1 to the constructor. That's why y is always initialized as 0.
What you want should be
Punkt pFeld[] = { {1, 1}, {2, 2}, {3, 3} }; // list initialization since C++11
or
Punkt pFeld[] = { Punkt(1, 1), Punkt(2, 2), Punkt(3, 3) };

Robot Motion - Dynamic Programming

Given a 1D world of infinite length (x),
and available moves (y) of, for example [1, 2, 3, -1, -2, -3],
and a destination (d) (ie 15), write a function that returns
the smallest number of moves (result) needed to reach d.
For example if d = 15, result = 5
since the most optimal move is 3, and it can be done 5 times.
This problem is very similar to this: https://www.youtube.com/watch?v=Y0ZqKpToTic
except that negative values are allowed.
I have the code below that only works for positive number. Any ideas to make it work for mixed positive and negative values?
class Solution {
public:
int Robotmotion(vector<int> &moves, int &d) {
if (d == 0) return 0;
if (d < 0) {
d = -d;
for (auto &move : moves) move *= -1;
}
sort(moves.begin(), moves.end());
vector<int> dp(d + 1, d + 1);
dp[0] = 0;
for (int i = 1; i <= d; i++) {
for (int j = 0; j < moves.size(); j++) {
if (moves[j] <= i) {
dp[i] = min(dp[i], dp[i - moves[j]] + 1);
}
}
}
return dp[d] == d + 1 ? -1 : dp[d];
}
};
int main() {
Solution s;
vector<int> moves = {1,2,3};
int d = 15;
int min_steps = s.Robotmotion(moves, d);
cout << "Mim steps:" << endl << min_steps << endl;
return 0;
}
I don't think dynamic programming can solve the problem. Instead, you should view the number as vertices in a graph and use BFS to solve the problem. You can even use a bidirectional BFS to speed up the process.

Converting a char in a string array to float

I'm working on a project which takes a string input from the user of coordinates.
example of input:
"Polygons = [(1, 1), (4, 1), (4, 5), (3,5), (1, 5); (5,3), (3, 4), (6, 4), (6, 12), (3, 12)]"
One of the functions that I am making is checking the minimum/maximum X, which is clearly any number after a "(", however the problem that's bugging me is converting what's after the ( into a float to use it in calculations and number comparisons.
#include <iostream>
#include "string"
#include <stdlib.h>
#include <cstdlib>
using namespace std;
//Using a constant string for testing
string Polygon_Input = "Polygons = [(1, 1), (4, 1), (4, 5), (3,5), (1, 5); (5,3), (3, 4), (6, 4), (6, 12), (3, 12)]";
string Operation;
float Min_X = 9999;
int main()
{
getline(cin, Operation);
if (Operation == "Minimum_X")
{
for (int i; i <= Polygon_Input.length(); i++)
{
if (Polygon_Input[i] == '(')
{
float X = Polygon_Input[i + 1];
if (X < Min_X)
{
Min_X = X;
}
}
}
cout << Min_X;
}
That's not working, it always prints out 49 as Min_X
I also tried the same code with one modification, but still doesn't work.
if (Polygon_Input[i] == '(')
{
string X_As_String = Polygon_Input.substr(i + 1, i + 1);
float X = atof(X_As_String.c_str());
if (X < Min_X)
{
Min_X = X;
}
First of all, there are several problems in your code.
float Min_X = 9999;
The minimum value must be in the list. Initialize the first element as the minimum value and compare it with the rest.
if (X < Min_X)
The value X is int whereas Min_X is float. Don't compare int with float. Declare both as float and then cast if you would like an integer number.
for (int i=0; i <= Polygon_Input.length(); i++)
Pay attention to <=. It should be <.
Now the solution for your problem is
//#include <limits> // no need for this
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdlib>
using namespace std;
//Using a constant string for testing
string Polygon_Input = "Polygons = [(1, 1), (4, 1), (4, 5), (3,5), (1, 5); (5,3), (3, 4), (6, 4), (6, 12), (3, 12)]";
string Operation("Minimum_X");
//float Min_X = 9999; ?????? Why
float Min_X;
bool flag(true);
int main()
{
//getline(cin, Operation); // commented out for test
if (Operation == "Minimum_X")
{
for (int i=0; i < Polygon_Input.size(); i++)
{
if ( Polygon_Input[i] == '(' )
{
// extract X values (i.e. the first co-ordinate of a point )
std::string temp = Polygon_Input.substr(i+1, Polygon_Input.find_first_of(",",i)-i-1 );
// convert strig to float
float X = std::stof(temp);
// store first element and compare it with the rest
if(flag){
Min_X = X;
flag=false;
}
// int X = Polygon_Input[i + 1] - '0'; ????? What is this?
if (X < Min_X)
{
Min_X = X;
}
}
}
cout << Min_X << endl;
}
return 0;
}
The output is
1
which the minimum X value in the list. This code handles float values as well (i.e. (3.45, 4)). Try different values for checking.

Convert 2D array of points into 1D array

I am struggling to convert a 2D array of points in a 1D array of ints. I wrote a wrapper class to do that for me (Array3D), which does the mapping for me with filling the underlying buffer, but it looks like the indexing is totally wrong, since when I print my 2D array and in comparison the buffer, it gives me different outputs.
The 2D point array has dimensions steps × number_of_robots. Therefore, the 1D buffer has
a length of steps × number_of_robots × 2.
Idea is that
buffer[index(x,y,0)] corresponds to points[index(x,y)].x
buffer[index(x,y,1)] corresponds to points[index(x,y)].y
The output is wrong, since it should be identical when I print out the 2D point array and the 1D buffer. I read the row of points from a file, and therefore, they totally should be identical.
The points are derived from the input read by a file. How that is done seems unimportant. Fact is, that the output of main.cpp is:
(0, 4) (0, 5) (1, 5) (2, 5) (2, 4) (3, 4) (2, 4) (2, 3) (2, 2)
(4, 0) (4, -1) (4, 0) (4, 1) (3, 1) (4, 1) (4, 2) (3, 2) (2, 2)
(0, 2) (0, 3) (1, 2) (2, 2) (2, 2) (3, 3) (2, 2) (2, 2) (2, 2)
(1, 2) (2, 2) (2, 2) (3, 3) (2, 2) (2, 2) (2, 2) (3, 3) (2, 2)
point.cpp
Point::Point(int a, int b) {
x = a;
y = b;
}
Array3D.cpp
template<class T>
int Array3D<T>::index(int x,int y, int z) {
return (x * ydim + y) * zdim + z;
}
template<class T>
T Array3D<T>::get( int x, int y, int z) {
return buffer[index(x,y,z)];
}
template<class T>
void Array3D<T>::set( int x, int y, int z ,T n) {
buffer[index(x,y,z)] = n;
}
Harvester.cpp
int Harvester::index(int t, int n) {
return t*number_of_robots + n;
}
void Harvester::extract(Array3D<int> *array) {
Point p;
for(int t = 0; t < steps; t++ ) {
for(int n = 0; n < number_of_robots; n++) {
p = data[index(t,n)];
array->set(t,n,0,p.x);
array->set(t,n,1,p.x);
}
}
}
void Harvester::read_points(string filename) {
string line;
ifstream input;
input.open(filename.c_str());
input >> number_of_robots;
int x, y;
for(int n = 0; n < number_of_robots; n++) {
if(input >> x >> y) {
data[index(0,n)].x = x;
data[index(0,n)].y = y;
//cout << x << " " << y << endl;
} else {
cout << "Your file is bad, and you should feel bad!";
return;
}
}
}
void Harvester::print_harvest() {
for (int n = 0; n < number_of_robots; n++) {
for (int t = 0; t < steps; t++) {
data[index(t,n)].dump();
}
cout << endl;
}
cout << endl;
}
robots_002.txt
2
0 4
4 0
main.cpp
int main() {
int mission_time;
int number_of_robots;
Point goal;
string path;
bool print = true;
int choice = 2;
mission_time = 8;
number_of_robots = 2;
goal.x = 2;
goal.y = 2;
path = "robots_002.txt";
int steps = mission_time + 1;
Harvester h(mission_time, number_of_robots, goal);
h.read_points("fixtures/" + path);
h.run();
int *buffer = new int[steps * number_of_robots * 2];
Array3D<int> arr(steps, number_of_robots, 2, buffer);
h.extract(&arr);
h.print_harvest();
for (int n = 0; n < number_of_robots; n++) {
for (int t = 0; t < steps; t++) {
printf("(%d, %d)\t", arr.get(t, n, 0), arr.get(t, n, 1));
}
cout << endl;
}
return 0;
}
still looking through but quick observation. In Harverster::extract, you are setting both to p.x
void Harvester::extract(Array3D<int> *array) {
Point p;
for(int t = 0; t < steps; t++ ) {
for(int n = 0; n < number_of_robots; n++) {
p = data[index(t,n)];
array->set(t,n,0,p.x);
array->set(t,n,1,p.x); //<-- im thinking you want this to be p.y
}
}
}