I'm currently working on a small game to play in the console. I'm trying to make player movement, but when I try to replace a certain element within the level array, it deletes the rest of the array.
The only movement in the code right now is moving right (type 2 in the console to move right)
#include <iostream>
using namespace std;
#define con std::cout <<
#define newline std::cout << '\n'
#define text std::cin >>
#define end return 0
#define repeat while (true)
int width, height;
int rprog;
int x, y, z;
int playerpos;
int input;
double level[] =
{1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1,
1, 0, 2, 0, 0, 1,
1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1};
const char *display[] = {" ", "[ ]", "[X]"};
int render () {
x = 1;
y = 1;
while (x < 37) {
z = level[x - 1];
con display[z];
x = x + 1;
y = y + 1;
if (y == 7) {
y = 1;
newline;
}
}
end;
}
int player () {
con "Please make your next move : w: 1, a: 2, s: 3, d: 4";
newline;
con "Current position: " << playerpos;
newline;
text input;
if (input == 2) {
level[playerpos] = 0;
playerpos = playerpos - 1;
level[playerpos] = 3;
}
end;
}
int main() {
playerpos = 15;
while (true) {
render ();
player ();
}
end;
}
I'm using this website for coding currently: https://www.programiz.com/cpp-programming/online-compiler/
This is the output:
[ ][ ][ ][ ][ ][ ]
[ ] [ ]
[ ] [X] [ ]
[ ] [ ]
[ ] [ ]
[ ][ ][ ][ ][ ][ ]
Please make your next move : w: 1, a: 2, s: 3, d: 4
Current position: 15
2
[ ][ ][ ][ ][ ][ ]
[ ] [ ]
[ ]
And then it cuts off rendering the level.
I'm confused. What am I doing wrong?
Arrays
Array indices start with 0 in C++.
You set the item at the new position to 3:
level[playerpos] = 3;
However, your array for the display types has only 3 elements (0, 1, 2):
const char *display[] = {" ", "[ ]", "[X]"};
Thus, you encounter undefined behaviour, as you have an out of bounds access.
Note also, that your initial array correctly uses a 2 for the player position, and thus works.
However, it also has a off-by-1 error: Your initialize the playerpos = 15, but place the 2 at index 14. Thus, the initial rendering is wrong. So the first movement will not be correct, and seem to stay on the same position.
Types
As #RemyLebeau mentions, why do you use a double array for the game state? Not only would other types be more appropriate, especially double can lead to serious, hard to debug probles. Not all integers are perfectly representable by a double, and type conversions could lead to different results.
Just for an example: if you add states 4 and 5, and imagine a double could not represent 5 exactely, but store it as 4.99999999999999999 instead. When accessing the array, integer conversion could render a state 4 instead.
Check this question and answer for details
Defines
As #KarenMelikyan mentioned in a comment, those #defines are a bad idea. It makes your code much harder to read for others, and is a bad a habit to develop. Better get aquainted with correct C++ syntax and use it.
Related
In book i found example
static int categoryTable[ 2 ][ 2 ][ 2 ] = {
//!b!c !bc b!c bc
0, 3, 2, 2, //!a
1, 2, 1, 1 // a
};
category = categoryTable[ a ][ b ][ c ]
There is mistake, right?
Right variant is
static int categoryTable[ 2 ][ 2 ][ 2 ] = {
//!b!c !bc b!c bc
{{0, 3}, {2, 2}}, //!a
{{1, 2}, {1, 1}} // a
};
Or original is right and I don't understand something?
As Beefster said both ways are correct and will compile.
Multidimensional arrays are just plain single-dimension arrays for the compiler but for programmers they are a nice sugar syntax for complex pointer arithmetics.
Because the multidimensional array is in the reality a single dimension array with syntax improvements then there's no point to disallow initialization with single initializer list.
Expression
a[0][2][3] = x;
is equivalent of *(a+(0*DIM_1+2)*DIM_2+3) = x;
What's not a part of your question but also interesting that because it's just pointer arithmetics you could write:
3[a]
That is equivalent of array subscription:
a[3]
So as a fun fact - you can do similar stuff with multidimensional arrays:
#include <stdio.h>
static int categoryTable[ 2 ][ 2 ][ 2 ] = {
//!b!c !bc b!c bc
0, 3, 2, 2, //!a
1, 2, 1, 1 // a
};
int main() {
// This two printf's are equivalent
printf("%d\n", 0[0[categoryTable][1]]);
printf("%d\n", categoryTable[0][1][0]);
return 0;
}
This is rather an ugly never-do-it thing, but funny anyway.
So you can think about subscription as some kind of mathematical expression to access single plain array - nothing special really.
Both are correct. You can use any one of them.
Assuming you have an array of n games, I want to write a script that receives the number of games being played and returns a multidimensional array of all possible combinations.
Keep in mind that a game can either end in Home Win (1), draw (0) or Away Win (-1).
Example
When n = 2,
Games Outcomes
Game 1 => Q vs B: - Q wins (1) - Draw (0) - B Wins (-1)
Game 2 => C vs D: - C Wins (1) - Draw (0) - D wins (-1)
When given 2 games, you will end up with the following combinations:
{1,1}
{1,0}
{1,-1}
{0,1}
{0,0}
{-1,1}
{-1,0}
{-1,-1}
I will give you an equivalent in Java. I know this is an interview question for Infama Limited Kenya
`package com.oluoch.code;
import java.util.Arrays;
import java.util.Scanner;
public class TWODArray {
public static void main(String[] args) {
int arr[][] = { { 1, 1 }, { 1, 0 }, { 1, -1 }, { 0, 1 }, { 0, 0 }, { -1, 1 }, { -1, 0 }, { -1, -1 } };
for (int i = 0; i < 8; ++i)
{
for (int j = 0; j < 2; ++j)
System.out.print(arr[i][j] + " ");
}
}
}
`
I would like to implement a local thresholding algorithm and I require your expertise.
my images are resized to 600x400, grayscale.
Basic Thought process on localizing:
Segment the images using a 9x9 ROI taken at each pixel and calculating the maximum intensity in the region.
create a 9x9 Kernel.
condition:
if the center pixel of the mask is above 50% of the maximum intensity, set the center pixel true.(apply mask)
my question to you:
How should I pick my kernel/mask ?
cv::Mat ROI;
cv::Mat mask(input.size(),CV_8UC1, cv::Scalar::all(0)); // create mask of 0s at first
const int kerneldepth = 1;
const int kernelsize = 9;
cv::Mat kernel = cv::Mat::ones( kernelsize, kernelsize, CV_8UC1 );
//take ROI of 9x9 and apply a threshold
for( double x = 9; x < input.cols -9; x++ ){
for( double y = 9 ; y < input.rows - 9 ; y++ ){
try{
double x_left = x - 4;
double x_right = x + 4;
double y_up = y + 4;
double y_down = y - 4;
double maxVal;
double minVal;
cv::Point anchor(kernelsize/2,kernelsize/2);
cv::Rect ROI = cv::Rect(x_left,y_down,9,9);
cv::Mat ROI_Mat = input(ROI); // a new matrix for ROI
cv::Scalar avgPixelIntensity = cv::mean( ROI_Mat ); // calculate mean
cv::minMaxLoc(ROI_Mat,&minVal,&maxVal);
if( input.at<uchar>(x,y) >= 0.5*maxVal){
cv::filter2D(input,mask,-1,kernel,anchor,0);
} else { break;}
}
catch (cv::Exception &e){
e.what();
}
}
*****************************UPDATED CODE: ******************************************
applyLocalThresh(cv::Mat &src, cv::Mat& out){
double maxVal, minVal;
cv::Mat output;
int top, bottom, left , right;
int borderType = cv::BORDER_CONSTANT;
cv::Scalar value;
top = (int) (9); bottom = (int) (9);
left = (int) (9); right = (int) (9);
output = src;
out = src;
value = 0;
cv::copyMakeBorder(src,output,top,bottom,left,right,borderType,value);
for(int y = 9; y < src.rows; y++) {
for(int x = 9; x < src.cols; x ++) {
cv::Mat ROI = src(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9)));
cv::minMaxLoc(ROI,&minVal,&maxVal);
if(src.at<uchar>(cv::Point(x-4,y-4)) >= 0.6*maxVal){
out.at<uchar>(cv::Point(x-4,y-4)) = 255;
}else{
out.at<uchar>(cv::Point(x-4,y-4));
}
}
}
}
You can do this with a dilation followed by a comparison in OpenCV;
im = load image here;
di = dilate im with a 9x9 kernel;
bw = im > (di * 0.5); // in OpenCV, pixels of bw are set to 255 or 0
A simple example to illustrate this with a 4x6 image and a 3x3 kernel in Matlab/Octave:
im =
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
di =
3 4 5 6 7 7
4 5 6 7 8 8
5 6 7 8 9 9
5 6 7 8 9 9
th = di * .5
th =
1.5000 2.0000 2.5000 3.0000 3.5000 3.5000
2.0000 2.5000 3.0000 3.5000 4.0000 4.0000
2.5000 3.0000 3.5000 4.0000 4.5000 4.5000
2.5000 3.0000 3.5000 4.0000 4.5000 4.5000
bw = im > th
bw =
0 0 1 1 1 1
0 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
I fear this approach is not entirely correct. Let me explain: for operations involving a kernel, one must be careful to place the center of the kernel on top of the pixel that is going to be transformed. That's because a 3x3, 5x5, 7x7, 9x9 (...) kernel just computes the value for one pixel in the image, which is the one positioned at the center [0,0] of the kernel.
If you think about how to compute the value for the first pixel of the image, the center of a 9x9 kernel is going to be placed at coordinate [0,0]. That means that 3/4 of the kernel are going to be placed at negative coordinates, i.e. coordinates that refers to pixels that don't exist:
[-4,-4][-3,-4][-2,-4][-1,-4][ 0,-4][ 1,-4][ 2,-4][ 3,-4][ 4,-4]
[-4,-3][-3,-3][-2,-3][-1,-3][ 0,-3][ 1,-3][ 2,-3][ 3,-3][ 4,-3]
[-4,-2][-3,-2][-2,-2][-1,-2][ 0,-2][ 1,-2][ 2,-2][ 3,-2][ 4,-2]
[-4,-1][-3,-1][-2,-1][-1,-1][ 0,-1][ 1,-1][ 2,-1][ 3,-1][ 4,-1]
[-4, 0][-3, 0][-2, 0][-1, 0][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
[-4, 1][-3, 1][-2, 1][-1, 1][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
[-4, 2][-3, 2][-2, 2][-1, 2][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
[-4, 3][-3, 3][-2, 3][-1, 3][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
[-4, 4][-3, 4][-2, 4][-1, 4][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]
This is always going to happen with pixels near the border of the image. So for the computation of the first pixel, we would have to restrict the computation to 1/4 of the kernel, which refers to valid coordinates in the target image:
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
[ ][ ][ ][ ][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
[ ][ ][ ][ ][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
[ ][ ][ ][ ][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
[ ][ ][ ][ ][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]
So the problem with your current approach is that at some point you will setup a ROI that is going to have negative coordinates, and when these instructions are executed you will see a nice crash:
cv::Mat ROI_Mat = input(ROI); // crash
The solution is not to use a ROI and just implement that algorithm yourself. I just can't see this custom computation working with cv::filter2D(). Here's a little something to help you get started:
void local_threshold(const cv::Mat& input, cv::Mat& output)
{
if (input.channels() != 1)
{
std::cout << "local_threshold !!! input image must be single channel" << std::endl;
return;
}
output = cv::Mat(input.rows, input.cols, CV_8UC1);
double min_val = 0, max_val = 0;
for (int i = 0; i < input.rows; i++)
for (int j = 0; j < input.cols; j++)
{
cv::Mat kernel = Mat::zeros(9, 9, output.type());
// Implement logic to fill the 9x9 kernel with
// values from the input Mat, respecting boundaries.
cv::Scalar avg_intensity = cv::mean(kernel);
cv::minMaxLoc(kernel, &min_val,&max_val);
if (input.at<uchar>(i,j) > (max_val / 2))
output.at<unsigned char>(i,j) = 255;
else
output.at<unsigned char>(i,j) = 0;
}
}
After further thinking and finding out how to utilize my basic knowledge in programming, I came up with this code that isn't the most efficient but gets the job done.
What was the main problem with my approach? :
Boundary pixels where one of the main problems and the whole indexing operation between kernel and mask caused a slight headache.
What was my approach in solving that matter?:
My threshold says it needs a relative high intensity level to set true pixels. Therefore I filled the image with some imaginary negative pixels and made my algorithm start at the first pixel of the original. And saved the results to a mask.
Result:
SUCCESS!
Code:
double maxVal, minVal;
cv::Mat output;
int top, bottom, left , right;
int borderType = cv::BORDER_CONSTANT;
cv::Scalar value;
top = (int) (4); bottom = (int) (4);
left = (int) (4); right = (int) (4);
output = src;
out = src;
value = 0;
cv::copyMakeBorder(src,output,top,bottom,left,right,borderType,value);
for(int y = 4; y < output.rows - 4; y++) {
for(int x = 4; x < output.cols - 4; x ++) {
// apply local ROI
cv::Mat ROI = output(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9)));
cv::minMaxLoc(ROI,&minVal,&maxVal); // extract max intensity values in the ROI
if(src.at<uchar>(cv::Point(x-4,y-4)) >= 0.5*maxVal){ // apply local threshold w.r.t highest intensity level
out.at<uchar>(cv::Point(x-4,y-4)) = 255; // change pixel value in mask if true
}else{
out.at<uchar>(cv::Point(x-4,y-4)) = 0;
}
}
}
}
it needs some clean up I know but hopefully this would help others to get some idea.
I am trying to perform image erosion with OpenCV. I want to do it like this: Suppose I have four different elements
S1 = [ 0 1 0, 0 1 0, 0 1 0 ]
S2 = [ 0 0 0, 1 1 1, 0 0 0 ]
S3 = [ 0 0 1, 0 1 0, 1 0 0 ]
S4 = [ 0 1 0, 1 1 1, 0 1 0 ]
And I want to perform four different erosions with these elements on original image:
E1 = I & S1
E2 = I & S2
E3 = I & S3
E4 = I & S4
where "I" is the original image, and I used "&" to denote erosion for simplicity. Then I want to obtain the final erosion with the addition of these four:
E = E1 + E2 + E3 + E4
But when implementing these with opencv, I've encountered difficulties in early stages. I declared the elements like this:
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
int S2[3][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 0, 0, 0 } };
int S3[3][3] = { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } };
int S4[3][3] = { { 0, 1, 0 }, { 1, 1, 1 }, { 0, 1, 0 } };
Then for using "cv::erode" I have difficulties with these elements since they are not the acceptable type. How can I use these elements to obtain my desired erosion mentioned above? Thank you in advance.
You'll probably need to create a cv::Mat from your desired kernel shapes, these are known as Structuring elements, and OpenCV provides the getStructuringElement function to create a few common shapes.
Alternatively, you can form your own by creating a new matrix from your data directly using something like:
cv::Mat S1 = (cv::Mat_<uchar>(3,3) << 0, 1, 0, 0, 1, 0, 0, 1, 0);
You can confirm whether this is correct by displaying it in the terminal:
std::cout << S1 << std::endl;
Once you've found your matrices, they can also be easily combined by simple arithmetic operations such as:
cv::Mat E = E1 + E2 + E3 + E4;
Use a Mat-oject as your kernel. InputArray and OutputArray (see the erode docu) can either be Mats or std::vector objects in most cases.
I think you could initialize it like this (not tested):
int S1[3][3] = { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } };
Mat mat1 = Mat(3, 3, CV_32SC1, S1);
I've got a lower triangular MatrixXd and I want to copy its lower values to the upper side as it'll become a symmetric matrix. How can I do it?
So far I've done:
MatrixXd m(n,n);
.....
//do something with m
for(j=0; j < n; j++)
{
for(i=0; i<j; i++)
{
m(i,j) = m(j,i);
}
}
Is there a fastest way to do it? I was thinking of some internal method that is able to "copy" the lower triangular matrix to the upper.
Say I've got this matrix, we call m:
1 2 3
4 5 6
7 8 9
what I need to obtain in m is :
1 4 7
4 5 8
7 8 9
I also know you can get the upper or the lower part of the matrix to do something:
MatrixXd m1(n,n);
m1 = m.triangularView<Eigen::Upper>();
cout << m1 <<endl;
1 2 3
0 5 6
0 0 9
But I can't yet get what I want...
I assume here that you are referring to working with the Eigen3 c++ library. This is not clear from your question. if not, you should consider it. In any case, within Eigen, there is no need to actually copy the triangular part, to get a selfadjoint matrix. Eigen has the concept of views, and you can use a self adjoint view in order to perform an operation like e.g.
using namespace Eigen;
MatrixXd m(m,n);
...
(generate uppper triangular entries in m)
...
VectorXd r(n), p(n);
r = m.selfadjointView<Upper>() * p;
here is a small example to illustrate using fixed size matrices:
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
int main()
{
Matrix2d m,c;
m << 1, 2,
0, 1;
Vector2d x(0,2), r;
// perform copy operation
c = m.selfadjointView<Upper>();
cout << c << endl;
// directly apply selfadjoint view in matrix operation
// (no entries are copied)
r = m.selfadjointView<Upper>() * x;
}
the output will be
[1, 2,
2, 1].
now, the result in r is the same as if you had used c * x instead. Just that there is no need for copying the values in the original matrix to make it selfadjoint.
In case the selfadjointView is not an option for you, the solution is to use triangularView on the destination matrix:
m.triangularView<Lower>() = m.transpose();
The simplest way I can think of is by copying the upper part of m matrix trasposed on the upper part:
m.triangularView<Upper>() = m.transpose();
For example, the following code:
MatrixXd m(3,3);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9;
m.triangularView<Upper>() = m.transpose();
std::cout << m << std::endl;
Gives the output you asked for:
1 4 7
4 5 8
7 8 9
Regards.
Simply:
m = m.selfadjointView<Upper>();
I think you are doing it the right way. If you knew some details about the memory layout of data in the matrix you could use some low-level optimizations. One of the techniques is loop tiling.
If speed is a big issue, I would not copy anything just decorate/wrap the matrix object with a coordinate inverting object that would flip the (x,y) to (y,x). if you make the () operator an an inline function it will not incur any significant cost when you use it.
This works, you can cut something but you need at least n*m/2 (less something), so only of a 2x
edit: I see that you use this matrixd object... the syntax is different, but the algorithm is this, anyway
#include <stdio.h>
int main ( )
{
int mat [ 4 ] [ 4 ];
int i, j;
mat [ 0 ] [ 0 ] = 0;
mat [ 0 ] [ 1 ] = 1;
mat [ 0 ] [ 2 ] = 2;
mat [ 0 ] [ 3 ] = 3;
mat [ 1 ] [ 0 ] = 4;
mat [ 1 ] [ 1 ] = 5;
mat [ 1 ] [ 2 ] = 6;
mat [ 1 ] [ 3 ] = 7;
mat [ 2 ] [ 0 ] = 8;
mat [ 2 ] [ 1 ] = 9;
mat [ 2 ] [ 2 ] = 10;
mat [ 2 ] [ 3 ] = 11;
mat [ 3 ] [ 0 ] = 12;
mat [ 3 ] [ 1 ] = 13;
mat [ 3 ] [ 2 ] = 14;
mat [ 3 ] [ 3 ] = 15;
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
printf ( "%02d", mat [ i ] [ j ] );
printf ( "\n" );
}
printf ( "\n" );
for ( i = 1; i < 4; i++ )
{
for ( j = 0; j < i; j++ )
mat [ j ] [ i ] = mat [ i ] [ j ];
}
for ( i = 0; i < 4; i++ )
{
for ( j = 0; j < 4; j++ )
printf ( "%02d ", mat [ i ] [ j ] );
printf ( "\n" );
}
printf ( "\n" );
scanf ( "%d", &i );
}