I'm trying to create a simple minesweeper game, and have some issues with creating the board. I am using a 2d vector in lieu of a 2d array and am having trouble incrementing the tiles value to see how many mines are adjacent to the tile.
int Boardsize::createBoard() const {
// vector < vector<Tile> > board;
impl->board.resize(getLength(), vector<Tile>(getWidth(), Tile()));
for (int i = 0; i < getMines(); i++) {
int v1 = rand() % getLength();
int v2 = rand() % getWidth();
if (impl->board[v1][v2].getMine() == true) i--;
else {impl->board[v1][v2].setMine(true);
if (v1 - 1 > -1) impl->board[v1-1][v2]++;
if (v1 + 1 < getLength()) impl->board[v1+1][v2]++;
if (v2 - 1 > -1) impl->board[v1][v2-1]++;
if (v2 + 1 < getWidth()) impl->board[v1][v2+1]++;
if ((v1 - 1 > -1) && (v2 - 1 > -1)) impl->board[v1-1][v2-1]++;
if ((v1 - 1 > -1) && (v2 + 1 < getWidth())) impl->board[v1-1][v2+1]++;
if ((v1 + 1 < getLength()) && (v2 - 1 > -1)) impl->board[v1+1][v2-1]++;
if ((v1 + 1 < getLength()) && (v2 + 1 < getWidth())) impl->board[v1+1][v2+1]++;
}
}
}
Values length, width and mines are set ahead of time. The way I intend it to work is "Check if getMine = true, if yes then game over. If no, isRevealed is set to true and the tile shows how many mines are adjacent to the tile. However, I'm getting the error:
error: no 'operator++(int)' declared for postfix '++' [-fpermissive]|
Do I need to set a seperate function to increment the content? I am assuming that the board.resize fills the vector full of 0's.
I appreciate the help.
Here is the "Tile" file's contents:
namespace Minesweeper {
using namespace std;
class Tile::Tilement {
int status;
bool mine;
int Adjmines;
friend class Tile;
public:
Tilement ()
: status(0), mine(false), Adjmines(0)
{
}
};
Tile::Tile() {
cout << "Tile is being created" << endl;
}
Tile::~Tile() {
cout << "Tile is being deleted" << endl;
}
void Tile::setMine(int a) {
tint->mine = true;
}
void Tile::setStatus(int a) {
if ((a == 0) || (a == 1) || (a == 2)) {
tint->status = a;
}
else {
#ifdef DEBUG
cout << "Tile status invalid" << endl;
#endif // DEBUG
throw invalid_argument("Invalid tile status");
}
}
//void Tile::setContent(char r) {
// tint->content = r;
//}
int Tile::getStatus() const {
return tint->status;
}
char Tile::getAdjcount() const {
return tint->Adjmines;
}
char Tile::getMine() const {
return tint->mine;
}
int Tile::setAdjmines(int a) {
a = a++;
}
char Tile::getContent() const {
if (Tile::getMine() == true) {
return tint->mine;
}
else return tint->Adjmines;
}
EDIT: I've changed the incrementations a bit so that they're now like this:
if (v1 - 1 > -1) impl->board[v1-1][v2].incAdjmines; (etc).
And the incAdjmines function looks like this:
int Tile::incAdjmines() {
Adjmines = Adjmines + 1;
}
And...well, the code compiled, if nothing else, but due to some errors in another fragment of code, I can't tell if it works correctly. Thank you all for your help so far.
You are calling ++ on Tile object which seems with no overload for this operator.
You can solve your problem by overloading this operator for Tile class. Or by directly telling which variable you want to increase for example:
impl->board[v1-1][v2].cout_of_things++
Related
I've been trying to solve this problem (from school) for just about a week now. We're given two numbers, from -(10^100000) to +that.
Of course the simplest solution is to implement written addition, so that's what I did. I decided, that I would store the numbers as strings, using two functions:
int ti(char a) { // changes char to int
int output = a - 48;
return output;
}
char tc(int a) { // changes int to char
char output = a + 48;
return output;
}
This way I can store negative digits, like -2. With that in mind I implemented a toMinus function:
void toMinus(std::string &a) { // 123 -> -1 -2 -3
for (auto &x : a) {
x = tc(-ti(x));
}
}
I also created a changeSize function, which adds 0 to the beginning of the number until they are both their max size + 1 and removeZeros, which removes leading zeros:
void changeSize(std::string &a, std::string &b) {
size_t exp_size = std::max(a.size(), b.size()) + 2;
while (a.size() != exp_size) {
a = '0' + a;
}
while (b.size() != exp_size) {
b = '0' + b;
}
}
void removeZeros(std::string &a) {
int i = 0;
for (; i < a.size(); i++) {
if (a[i] != '0') {
break;
}
}
a.erase(0, i);
if (a.size() == 0) {
a = "0";
}
}
After all that, I created the main add() function:
std::string add(std::string &a, std::string &b) {
bool neg[2] = {false, false};
bool out_negative = false;
if (a[0] == '-') {
neg[0] = true;
a.erase(0, 1);
}
if (b[0] == '-') {
neg[1] = true;
b.erase(0, 1);
}
changeSize(a, b);
if (neg[0] && !(neg[1] && neg[0])) {
toMinus(a);
}
if(neg[1] && !(neg[1] && neg[0])) {
toMinus(b);
}
if (neg[1] && neg[0]) {
out_negative = true;
}
// Addition
for (int i = a.size() - 1; i > 0; i--) {
int _a = ti(a[i]);
int _b = ti(b[i]);
int out = _a + _b;
if (out >= 10) {
a[i - 1] += out / 10;
} else if (out < 0) {
if (abs(out) < 10) {
a[i - 1]--;
} else {
a[i - 1] += abs(out) / 10;
}
if (i != 1)
out += 10;
}
a[i] = tc(abs(out % 10));
}
if (ti(a[0]) == -1) { // Overflow
out_negative = true;
a[0] = '0';
a[1]--;
for (int i = 2; i < a.size(); i++) {
if (i == a.size() - 1) {
a[i] = tc(10 - ti(a[i]));
} else {
a[i] = tc(9 - ti(a[i]));
}
}
}
if (neg[0] && neg[1]) {
out_negative = true;
}
removeZeros(a);
if (out_negative) {
a = '-' + a;
}
return a;
}
This program works in most cases, although our school checker found that it doesn't - like instead of
-4400547114413430129608370706728634555709161366260921095898099024156859909714382493551072616612065064
it returned
-4400547114413430129608370706728634555709161366260921095698099024156859909714382493551072616612065064
I can't find what the problem is. Please help and thank you in advance.
Full code on pastebin
While I think your overall approach is totally reasonable for this problem, your implementation seems a bit too complicated. Trying to solve this myself, I came up with this:
#include <iostream>
#include <limits>
#include <random>
#include <string>
bool greater(const std::string& a, const std::string& b)
{
if (a.length() == b.length()) return a > b;
return a.length() > b.length();
}
std::string add(std::string a, std::string b)
{
std::string out;
bool aNeg = a[0] == '-';
if (aNeg) a.erase(0, 1);
bool bNeg = b[0] == '-';
if (bNeg) b.erase(0, 1);
bool resNeg = aNeg && bNeg;
if (aNeg ^ bNeg && (aNeg && greater(a, b) || bNeg && greater(b, a)))
{
resNeg = true;
std::swap(a, b);
}
int i = a.length() - 1;
int j = b.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0)
{
const int digitA = (i >= 0) ? a[i] - '0' : 0;
const int digitB = (j >= 0) ? b[j] - '0' : 0;
const int sum = (aNeg == bNeg ? digitA + digitB : (bNeg ? digitA - digitB : digitB - digitA)) + carry;
carry = 0;
if (sum >= 10) carry = 1;
else if (sum < 0) carry = -1;
out = std::to_string((sum + 20) % 10) + out;
i--;
j--;
}
if (carry) out = '1' + out;
while (out[0] == '0') out.erase(0, 1);
if (resNeg) out = '-' + out;
return out;
}
void test()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(-std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
for (int i = 0; i < 1000000; ++i)
{
const int64_t a = dis(gen);
const int64_t b = dis(gen);
const auto expected = std::to_string(a + b);
const auto actual = add(std::to_string(a), std::to_string(b));
if (actual != expected) {
std::cout << "mismatch expected: " << expected << std::endl;
std::cout << "mismatch actual : " << actual << std::endl;
std::cout << " a: " << a << std::endl;
std::cout << " b: " << b << std::endl;
}
}
}
int main()
{
test();
}
It can potentially be further optimized, but the main points are:
If the sign of both numbers is the same, we can do simple written addition. If both are negative, we simply prepend - at the end.
If the signs are different, we do written subtraction. If the minuend is greater than the subtrahend, there's no issue, we know that the result will be positive. If, however, the subtrahend is greater, we have to reformulate the problem. For example, 123 - 234 we would formulate as -(234 - 123). The inner part we can solve using regular written subtraction, after which we prepend -.
I test this with random numbers for which we can calculate the correct result using regular integer arithmetic. Since it doesn't fail for those, I'm pretty confident it also works correctly for larger inputs. An approach like this could also help you uncover cases where your implementation fails.
Other than that, I think you should use a known failing case with a debugger or simply print statements for the intermediate steps to see where it fails. The only small differences in the failing example you posted could point at some issue with handling a carry-over.
I am trying to solve an exercise in recursion that goes like this.
Say you have a matrix of nxm with integers like this(just an example):
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
I want to find a path (starting from anywhere) that, given a number n, every step n changes by n/(number_at_that_position) and the path stops when n = 1.
I am not looking for all paths, I am just looking for a path.
So if you use symbols to map the path, you would end up with a matrix
> > V - *
- - V > ^
- - V ^ -
- - > ^ -
Where '>' means a step right, '<' means a step left, '^' is a step up and 'V 'is a step down. Once n becomes 1, we insert '*' to say the path ended.
Most important: The path has to be continuous and you cannot visit a place you have visited before.
Even more important: The function that finds the path MUST be recursive.
If no path is found, the code exits with a message saying that no path was found.
Up to now I've come up with the following code for the path finding. I've used ideas from different places, but one of them is this one Recursively finding a path through a maze c++
bool path_print(vector<vector<int> > &P, size_t line, size_t col, vector<vector<char> > &A, int n) {
if (line < 0 || line > P.size() || col < 0 || col > P[0].size()) {
return false;
}
if (A[line][col] != '-') {
return false;
}
if (n == 1) {
A[line][col] = '*';
return false;
}
printf("n = %d, line = %zu, col = %zu\n", n, line, col);
n = n/P[line][col];
if (path_print(P, line, col+1, A, n) == true){
A[line][col] = '>';
return true;
} else if (path_print(P, line-1, col, A, n) == true) {
A[line][col] = '^';
return true;
} else if (path_print(P, line+1, col, A, n) == true){
A[line][col] = 'V';
return true;
} else if (path_print(P, line, col-1, A, n) == true){
A[line][col] = '<';
return true;
}
return true;
}
P is the vector containing the values
A is the char vector that stores the path
n is the actual number you are probing
I've been working on this for a while and I am stuck. This code does not work properly. Any suggestions or help would be greatly appreciated.
Thank you in advance
In your code :
if (line < 0 || line > P.size() || col < 0 || col > P[0].size())
is wrong because :
that allows to use the indexes P.size() and P[0].size(), in the original code of the link the comparisons are made with size - 1
line is a size_t so to do line < 0 has no sense, same for col
can be :
bool path_print(vector<vector<int> > &P, int line, int col, vector<vector<char> > &A, int n) {
if (line < 0 || line >= (int) P.size() || col < 0 || col >= (int) P[0].size())
or to check col and line before to do + 1 or -1 on them in a recursive call to avoid any problem including overflow.
But this is not enough to solve your problem, because your other changes from the code of the link are wrong :
you modify A cell after the recursive calls rather than before
you do not reset A cell to '-' after
when you find the exit (in your case n is 1) you return false rather than true, so you continue to search, and you check the value of n too late after an other move
at the end of the function you return true rather than false
Note that is is useless to continue to search while n is 0 after the division
To write if (f() == true) is redundant, if (f()) is enough
A solution modifying your code is :
#include <iostream>
#include <vector>
using namespace std;
bool searchPath(const vector<vector<int> > & P,
size_t line, size_t col,
vector<vector<char> > &A,
int n) {
if (A[line][col] != '-') {
return false;
}
n = n/P[line][col];
if (n == 1) {
A[line][col] = '*';
return true;
}
if (n == 0)
return false;
A[line][col] = '>';
if ((col != (P[0].size() - 1)) && searchPath(P, line, col+1, A, n)) {
return true;
}
A[line][col] = '^';
if ((line != 0) && searchPath(P, line-1, col, A, n)) {
return true;
}
A[line][col] = 'V';
if ((line != (P.size() - 1)) && searchPath(P, line+1, col, A, n)){
return true;
}
A[line][col] = '<';
if ((col != 0) && searchPath(P, line, col-1, A, n)){
return true;
}
A[line][col] = '-';
return false;
}
int main(int argc, char ** argv)
{
vector<vector<int> > P;
vector<vector<char> > A;
// fill vectors
int lines, columns;
cout << "number of lines and columns : ";
if (!((cin >> lines) && (cin >> columns) && (lines > 0) && (columns > 0))) {
cout << "invalid sizes" << endl;
return -1;
}
P.resize(lines);
A.resize(lines);
cout << "enter maze" << endl;
for (int i = 0; i != lines; ++i) {
P[i].resize(columns);
A[i].resize(columns);
for (int j = 0; j != columns; ++j) {
int v;
if (!(cin >> v) || (v < 1)) {
cout << "invalid input : " << v << endl;
return -1;
}
P[i][j] = v;
A[i][j] = '-';
}
}
int n;
cout << "enter n : ";
if (!(cin >> n) || (n <= 0)) {
cout << "invalid value of n" << endl;
return -1;
}
// search a way from all cells
for (size_t l = 0; l != (size_t) lines; ++l) {
for (size_t c = 0; c != (size_t) columns; ++c) {
if (searchPath(P, l, c, A, n)) {
// found
cout << "found from cell line " << l << " column " << c << endl;
for (l = 0; l != (size_t) lines; ++l) {
for (c = 0; c != (size_t) columns; ++c) {
cout << A[l][c] << ' ';
}
cout << endl;
}
return 0;
}
}
}
cout << "no solution" << endl;
return 0;
}
Examples :
number of lines and columns : 4 5
enter maze
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
enter n : 200
found from cell line 0 column 0
> > > > V
- * - - V
- ^ < < V
- - - ^ <
number of lines and columns : 4 5
enter maze
1 1 1 5 2
2 3 5 2 1
3 1 1 1 5
1 1 5 1 1
enter n : 999999
no solution
I created a C++ program through Matlab coder called implicit_enumeration.cpp which takes a matrix A and a vector b as input and returns a vector zstar and a probability value Vstar. I am now struggling to initialize the main function:
// Include Files
#include "stdafx.h"
#include "implicit_enumeration.h"
#include "main.h"
// Function Declarations
static void argInit_4x1_real_T(double result[4]);
static void argInit_4x9_real_T(double result[36]);
static void main_implicit_enumeration();
// Function Definitions
static void argInit_4x1_real_T(double result[4])
{
int idx0;
// Loop over the array to initialize each element.
for (idx0 = 0; idx0 < 4; idx0++) {
// Set the value of the array element.
// Change this value to the value that the application requires.
result[idx0] = 1;
}
}
static void argInit_4x9_real_T(double result[36])
{
int idx0;
int idx1;
// Loop over the array to initialize each element.
for (idx0 = 0; idx0 < 4; idx0++) {
for (idx1 = 0; idx1 < 9; idx1++) {
// Set the value of the array element.
// Change this value to the value that the application requires.
if (idx0 == 0) {
if (idx1 == 0) { result[idx0 + (idx1 << 2)] = 1; }
else if (idx1 == 1) { result[idx0 + (idx1 << 2)] = 1; }
else { result[idx0 + (idx1 << 2)] = 0; }
}
else if (idx0 == 1) {
if (idx1 == 2) { result[idx0 + (idx1 << 2)] = 1; }
else if (idx1 == 3) { result[idx0 + (idx1 << 2)] = 1; }
else if (idx1 == 4) { result[idx0 + (idx1 << 2)] = 1; }
else { result[idx0 + (idx1 << 2)] = 0; }
}
else if (idx0 == 2) {
if (idx1 == 5) { result[idx0 + (idx1 << 2)] = 1; }
else { result[idx0 + (idx1 << 2)] = 0; }
}
else {
if (idx1 == 6) { result[idx0 + (idx1 << 2)] = 1; }
else if (idx1 == 7) { result[idx0 + (idx1 << 2)] = 1; }
else if (idx1 == 8) { result[idx0 + (idx1 << 2)] = 1; }
else { result[idx0 + (idx1 << 2)] = 0; }
}
}
}
}
static void main_implicit_enumeration()
{
double dv0[36];
double dv1[4];
double zstar[9];
double Vstar;
// Initialize function 'implicit_enumeration' input arguments.
// Initialize function input argument 'A'.
// Initialize function input argument 'b'.
// Call the entry-point 'implicit_enumeration'.
argInit_4x9_real_T(dv0);
argInit_4x1_real_T(dv1);
implicit_enumeration(dv0, dv1, zstar, &Vstar);
}
int main(int argc, const char * const argv[])
{
// Initialize the application.
// You do not need to do this more than one time.
// Invoke the entry-point functions.
// You can call entry-point functions multiple times.
main_implicit_enumeration();
return 0;
}
Specifically, I am wondering how to initialize argv[] as a matrix A and a vector b. Is it necessary to set the command arguments even though I already initialized the matrix A and the vector b through the functions argInit_4x9_real_T() and argInit_4x1_real_T()? If yes, how to include a matrix and a vector as command arguments? The examples I checked always show single integer or real values, but not matrix or vectors.
Thank you in advance!
Actually, you are mostly done.
In main(int argc, const char * const argv[]):
argc is the number of of command line arguments, argv contains these command line arguments.
Example:
If you call test.ext something, argc is 2, argv[0] is "test.exe", argv[1] is "something".
Your initialization is done in main_implicit_enumeration()
dv0 is you matrix A (4*9 Matrix -> 36 elements), and it is
initialized in argInit_4x9_real_T()
dv1 is your vector b (4 Vector -> 4 elements), and it is initialized in argInit_4x1_real_T
zstar is the return vector
Vstar the skalar return
Question is: How do you want to pass values to your program? Load values from a file? Use a format like test.ext A=1,2,3;4,5,6 b=8,9 ?
The goal of this program is for the knight to move around the chest board and only touching each spot once.
Each spot is initialized and set to zero by default.
As the knight moves, each spot the knight touches should correspond with the number of moves taken to reach that point.
However, I am having quite a few problems
1) My Knight is moving around the board and going either out of bound of the multidimensional chess board array or manipulates the movement arrays (horizontal[] and vertical[])
2) The conditions of my boolean functions MoveOnBoard && MoveHasNotBeenMade are that if the next possible move is between the exisiting rows and columns also if the spot being moved to has a value of 0(meaning it has yet to be moved to). However, both of these conditions
seem to be ignored.
How would I go about fixing this?
Thank you in advance!
Here's the code below
using namespace std;
#include <iostream>
#include <array>
void DefinedMoveSet();
void RenderBoard();
void MoveKnight(int& moveChoice, int& numberOfMovesMade);
void PossibleMoves();
bool MoveOnBoard(int& moveChoice);
bool MoveHasNotBeenMade(int& moveChoice);
// Two single dimenisional arrays to store move positions for the Knight
// Arrays have yet to be assigned values
int vertical[8], horizontal[8];
int currentRow = 4, currentColumn = 3;
// Initializing an array with the dimension 8 * 8
int chestBoard[8][8] = { 0 };
int main()
{
DefinedMoveSet();
PossibleMoves();
RenderBoard();
cin.ignore();
return 0;
}
void RenderBoard()
{
// The outer loop goes through each row until it reaches 8
for (int boardRow = 0; boardRow < 8; boardRow++)
{
// The inner loop takes in the specific row
for (int boardColumn = 0; boardColumn < 8; boardColumn++)
{
// Then iterates through the columns of that row until it reaches 8
// Each index is seperated by a tab escape key shortcut
cout << chestBoard[boardRow][boardColumn] << "\t";
}
// Back to the inner array a new line is printed for the next row
cout << "\n";
}
}
void DefinedMoveSet()
{
// Values for the horizontal array at each index
horizontal[0] = 2;
horizontal[1] = 1;
horizontal[2] = -1;
horizontal[3] = -2;
horizontal[4] = -2;
horizontal[5] = -1;
horizontal[6] = 1;
horizontal[7] = 2;
// Values for the vertical array at each index
vertical[0] = -1;
vertical[1] = -2;
vertical[2] = -2;
vertical[3] = -1;
vertical[4] = 1;
vertical[5] = 2;
vertical[6] = 2;
vertical[7] = 1;
}
bool MoveOnBoard(int& moveChoice)
{
int futureRow = currentRow + vertical[moveChoice];
int futureColumn = currentColumn + horizontal[moveChoice];
if ((0 < futureRow) && (0 < futureColumn) && (futureRow < 8) && (futureColumn < 8))
return true;
}
bool MoveHasNotBeenMade(int& moveChoice)
{
int futureRow = currentRow + vertical[moveChoice];
int futureColumn = currentColumn + horizontal[moveChoice];
if (chestBoard[futureRow][futureColumn] == 0)
return true;
}
void PossibleMoves()
{
bool movesStillExist = true;
int numberOfMovesMade = 1;
while (numberOfMovesMade < 65 && movesStillExist)
{
for (int i = 0; i < 8; i++)
{
if (i == 8)
movesStillExist = false;
if (MoveOnBoard(i) && MoveHasNotBeenMade(i))
{
numberOfMovesMade++;
MoveKnight(i, numberOfMovesMade);
}
}
}
}
void MoveKnight(int &moveChoice, int &numberOfMovesMade)
{
// Takes in the int moveNumber as a parameter
// MoveNumber(or case) must be between 0 and 7
// if there is not a case for the value then the knight will not move
//chestBoard[currentRow][currentColumn] = numberOfMovesMade;
currentRow += vertical[moveChoice];
currentColumn += horizontal[moveChoice];
chestBoard[currentRow][currentColumn] = numberOfMovesMade;
}
in MoveOnBoardand and in MoveHasNotBeenMade instead of
if(...)
return true;
should be
if(...)
return true;
return false;
if condtion == false, function returning not void reach end without return statement.
With the advice from the comments I received, I was able to fix the index issues as well as the return value of the boolean functions.
My main problem was that I was not breaking out of the previous loop after moving.
Easily solved by this if statement
if (MoveOnBoard(i) && MoveHasNotBeenMade(i))
{
MoveKnight(i);
break;
}
I was trying to achieve this by telling the compiler
if (i == 8)
movesStillExist = false;
As pointed out by #Aziuth this condition will never be met because a move at that index does not exist.
So instead for my purposes I changed that condition to be
if (i == 7)
movesStillExist = false;
Also for the index issues my logic was a little off
if (((0 <= futureRow) && (0 <= futureColumn)) && ((futureRow < 8) && (futureColumn < 8)))
return true; // if the future row and column are in bounds then return true
return false; // else the default is false
Also, my code is not idealistic for c++.
Having so many global variables and not enough commenting.
Please understand that the use of single and multidimensional arrays are required due to this being a challenge for my c++ course.
bool MoveOnBoard(int& moveChoice)
{
int futureRow = currentRow + vertical[moveChoice];
int futureColumn = currentColumn + horizontal[moveChoice];
if (((0 <= futureRow) && (0 <= futureColumn)) && ((futureRow < 8) && (futureColumn < 8)))
return true;
return false;
}
bool MoveHasNotBeenMade(int& moveChoice)
{
int futureRow = currentRow + vertical[moveChoice];
int futureColumn = currentColumn + horizontal[moveChoice];
if (chestBoard[futureRow][futureColumn] == 0)
return true;
return false;
}
void PossibleMoves()
{
bool movesStillExist = true;
while (numberOfMovesMade < 65 && movesStillExist)
{
for (int i = 0; i < 8; i++)
{
if (MoveOnBoard(i) && MoveHasNotBeenMade(i))
{
MoveKnight(i);
break;
}
if (i == 7)
movesStillExist = false;
}
}
}
void MoveKnight(int &moveChoice)
{
// Takes in the int moveNumber as a parameter
// MoveNumber(or case) must be between 0 and 7
// if there is not a case for the value then the knight will not move
chestBoard[currentRow][currentColumn] = numberOfMovesMade;
numberOfMovesMade++;
currentRow += vertical[moveChoice];
currentColumn += horizontal[moveChoice];
chestBoard[currentRow][currentColumn] = numberOfMovesMade;
}
I have a program that works in VS C++ and does not work with g++. Here is the code:
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <set>
#define EP 1e-10
using namespace std;
typedef pair<long long, long long> ii;
typedef pair<bool, int> bi;
typedef vector<ii> vii;
// Returns the orientation of three points in 2D space
int orient2D(ii pt0, ii pt1, ii pt2)
{
long long result = (pt1.first - pt0.first)*(pt2.second - pt0.second)
- (pt1.second - pt0.second)*(pt2.first - pt0.first);
return result == 0 ? 0 : result < 0 ? -1 : 1;
}
// Returns the angle derived from law of cosines center-pt1-pt2.
// Defined to be negative if pt2 is to the right of segment pt1 to center
double angle(ii center, ii pt1, ii pt2)
{
double aS = pow(center.first - pt1.first, 2) + pow(center.second - pt1.second, 2);
double bS = pow(pt2.first - pt1.first, 2) + pow(pt2.second - pt1.second, 2);
double cS = pow(center.first - pt2.first, 2) + pow(center.second - pt2.second, 2);
/* long long aS = (center.first - pt1.first)*(center.first - pt1.first) + (center.second - pt1.second)*(center.second - pt1.second);
long long bS = (pt2.first - pt1.first)*(pt2.first - pt1.first) + (pt2.second - pt1.second)*(pt2.second - pt1.second);
long long cS = (center.first - pt2.first)*(center.first - pt2.first) + (center.second - pt2.second)*(center.second - pt2.second);*/
int sign = orient2D(pt1, center, pt2);
return sign == 0 ? 0 : sign * acos((aS + bS - cS) / ((sqrt(aS) * sqrt(bS) * 2)));
}
// Computes the average point of the set of points
ii centroid(vii &pts)
{
ii center(0, 0);
for (int i = 0; i < pts.size(); ++i)
{
center.first += pts[i].first;
center.second += pts[i].second;
}
center.first /= pts.size();
center.second /= pts.size();
return center;
}
// Uses monotone chain to convert a set of points into a convex hull, ordered counter-clockwise
vii convexHull(vii &pts)
{
sort(pts.begin(), pts.end());
vii up, dn;
for (int i = 0; i < pts.size(); ++i)
{
while (up.size() > 1 && orient2D(up[up.size()-2], up[up.size()-1], pts[i]) >= 0)
up.pop_back();
while (dn.size() > 1 && orient2D(dn[dn.size()-2], dn[dn.size()-1], pts[i]) <= 0)
dn.pop_back();
up.push_back(pts[i]);
dn.push_back(pts[i]);
}
for (int i = up.size()-2; i > 0; --i)
{
dn.push_back(up[i]);
}
return dn;
}
// Tests if a point is critical on the polygon, i.e. if angle center-qpt-polygon[i]
// is larger (smaller) than center-qpt-polygon[i-1] and center-qpt-polygon[i+1].
// This is true iff qpt-polygon[i]-polygon[i+1] and qpt-polygon[i]-polygon[i-1]
// are both left turns (min) or right turns (max)
bool isCritical(vii &polygon, bool mx, int i, ii qpt, ii center)
{
int ip1 = (i + 1) % polygon.size();
int im1 = (i + polygon.size() - 1) % polygon.size();
int p1sign = orient2D(qpt, polygon[i], polygon[ip1]);
int m1sign = orient2D(qpt, polygon[i], polygon[im1]);
if (p1sign == 0 && m1sign == 0)
{
return false;
}
if (mx)
{
return p1sign <= 0 && m1sign <= 0;
}
else
{
return p1sign >= 0 && m1sign >= 0;
}
}
// Conducts modified binary search on the polygon to find tangent lines in O(log n) time.
// This is equivalent to finding a max or min in a "parabola" that is rotated and discrete.
// Vanilla binary search does not work and neither does vanilla ternary search. However, using
// the fact that there is only a single max and min, we can use the slopes of the points at start
// and mid, as well as their values when compared to each other, to determine if the max or min is
// in the left or right section
bi find_tangent(vii &polygon, bool mx, ii qpt, int start, int end, ii center)
{
// When query is small enough, iterate the points. This avoids more complicated code dealing with the cases not possible as
// long as left and right are at least one point apart. This does not affect the asymptotic runtime.
if (end - start <= 4)
{
for (int i = start; i < end; ++i)
{
if (isCritical(polygon, mx, i, qpt, center))
{
return bi(true, i);
}
}
return bi(false, -1);
}
int mid = (start + end) / 2;
// use modulo to wrap around the polygon
int startm1 = (start + polygon.size() - 1) % polygon.size();
int midm1 = (mid + polygon.size() - 1) % polygon.size();
// left and right angles
double startA = angle(center, qpt, polygon[start]);
double midA = angle(center, qpt, polygon[mid]);
// minus 1 angles, to determine slope
double startm1A = angle(center, qpt, polygon[startm1]);
double midm1A = angle(center, qpt, polygon[midm1]);
int startSign = abs(startm1A - startA) < EP ? 0 : (startm1A < startA ? 1 : -1);
int midSign = abs(midm1A - midA) < EP ? 0 : (midm1A < midA ? 1 : -1);
bool left = true;
// naively 27 cases: left and left angles can be <, ==, or >,
// slopes can be -, 0, or +, and each left and left has slopes,
// 3 * 3 * 3 = 27. Some cases are impossible, so here are the remaining 18.
if (abs(startA - midA) < EP)
{
if (startSign == -1)
{
left = !mx;
}
else
{
left = mx;
}
}
else if (startA < midA)
{
if (startSign == 1)
{
if (midSign == 1)
{
left = false;
}
else if (midSign == -1)
{
left = mx;
}
else
{
left = false;
}
}
else if (startSign == -1)
{
if (midSign == -1)
{
left = true;
}
else if (midSign == 1)
{
left = !mx;
}
else
{
left = true;
}
}
else
{
if (midSign == -1)
{
left = false;
}
else
{
left = true;
}
}
}
else
{
if (startSign == 1)
{
if (midSign == 1)
{
left = true;
}
else if (midSign == -1)
{
left = mx;
}
else
{
left = true;
}
}
else if (startSign == -1)
{
if (midSign == -1)
{
left = false;
}
else if (midSign == 1)
{
left = !mx;
}
else
{
left = false;
}
}
else
{
if (midSign == 1)
{
left = true;
}
else
{
left = false;
}
}
}
if (left)
{
return find_tangent(polygon, mx, qpt, start, mid+1, center);
}
else
{
return find_tangent(polygon, mx, qpt, mid, end, center);
}
}
int main(){
int n, m;
cin >> n >> m;
vii rawPoints(n);
for (int i = 0; i < n; ++i)
{
cin >> rawPoints[i].first >> rawPoints[i].second;
}
vii polygon = convexHull(rawPoints);
set<ii> points(polygon.begin(), polygon.end());
ii center = centroid(polygon);
for (int i = 0; i < m; ++i)
{
ii pt;
cin >> pt.first >> pt.second;
bi top = find_tangent(polygon, true, pt, 0, polygon.size(), center);
bi bot = find_tangent(polygon, false, pt, 0, polygon.size(), center);
// a query point is inside if it is collinear with its max (top) and min (bot) angled points, it is a polygon point, or if none of the points are critical
if (!top.first || orient2D(polygon[top.second], pt, polygon[bot.second]) == 0 || points.count(pt))
{
cout << "INSIDE" << endl;
}
else
{
cout << polygon[top.second].first << " " << polygon[top.second].second << " " << polygon[bot.second].first << " " << polygon[bot.second].second << endl;
}
}
}
My suspicion is there's something wrong with the angle function. I have narrowed it down to either that or find_tangent. I also see different results in g++ when I switch from double to long long in the angle function. The double results are closer to correct, but I can't see why it should be any different. The values I'm feeding in are small and no overflow/ rounding should be causing issues. I have also seen differences in doing pow(x, 2) or x*x when I assign to a double. I don't understand why this would make a difference.
Any help would be appreciated!
EDIT: Here is the input file: https://github.com/brycesandlund/Coursework/blob/master/Java/PrintPoints/points.txt
Here is the correct result:
https://github.com/brycesandlund/Coursework/blob/master/CompGeo/CompGeo/correct.txt
Here is the incorrect result:
https://github.com/brycesandlund/Coursework/blob/master/CompGeo/CompGeo/fast.txt
The problem was with this piece of code:
// Computes the average point of the set of points
ii centroid(vii &pts)
{
ii center(0LL, 0LL);
for (int i = 0; i < pts.size(); ++i)
{
center.first += pts[i].first;
center.second += pts[i].second;
}
center.first /= pts.size(); //right here!!
center.second /= pts.size();
return center;
}
I don't know why but g++ was taking the negative center.first and turning it into a positive, overflowed long long when dividing by the unsigned integer pts.size. By converting the statements into:
center.first /= (long long)pts.size();
center.second /= (long long)pts.size();
The output from g++ and VS c++ matches.