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.
Related
I recently finished making an algorithm for a project I'm working on.
Briefly, a part of my project needs to fill a matrix, the requirements of how to do it are these:
- Fill the matrix in form of spiral, from the center.
- The size of the matrix must be dynamic, so the spiral can be large or small.
- Every two times a cell of the matrix is filled, //DO STUFF must be executed.
In the end, the code that I made works, it was my best effort and I am not able to optimize it more, it bothers me a bit having had to use so many ifs, and I was wondering if someone could take a look at my code to see if it is possible to optimize it further or some constructive comment (it works well, but it would be great if it was faster, since this algorithm will be executed several times in my project). Also so that other people can use it!
#include <stdio.h>
typedef unsigned short u16_t;
const u16_t size = 7; //<-- CHANGE HERE!!! just odd numbers and bigger than 3
const u16_t maxTimes = 2;
u16_t array_cont[size][size] = { 0 };
u16_t counter = 3, curr = 0;
u16_t endColumn = (size - 1) / 2, endRow = endColumn;
u16_t startColumn = endColumn + 1, startRow = endColumn + 1;
u16_t posLoop = 2, buffer = startColumn, i = 0;
void fillArray() {
if (curr < maxTimes) {
if (posLoop == 0) { //Top
for (i = buffer; i <= startColumn && curr < maxTimes; i++, curr++)
array_cont[endRow][i] = counter++;
if (curr == maxTimes) {
if (i <= startColumn) {
buffer = i;
} else {
buffer = endRow;
startColumn++;
posLoop++;
}
} else {
buffer = endRow;
startColumn++;
posLoop++;
fillArray();
}
} else if (posLoop == 1) { //Right
for (i = buffer; i <= startRow && curr < maxTimes; i++, curr++)
array_cont[i][startColumn] = counter++;
if (curr == maxTimes) {
if (i <= startRow) {
buffer = i;
} else {
buffer = startColumn;
startRow++;
posLoop++;
}
} else {
buffer = startColumn;
startRow++;
posLoop++;
fillArray();
}
} else if (posLoop == 2) { //Bottom
for (i = buffer; i >= endColumn && curr < maxTimes; i--, curr++)
array_cont[startRow][i] = counter++;
if (curr == maxTimes) {
if (i >= endColumn) {
buffer = i;
} else {
buffer = startRow;
endColumn--;
posLoop++;
}
} else {
buffer = startRow;
endColumn--;
posLoop++;
fillArray();
}
} else if (posLoop == 3) { //Left
for (i = buffer; i >= endRow && curr < maxTimes; i--, curr++)
array_cont[i][endColumn] = counter++;
if (curr == maxTimes) {
if (i >= endRow) {
buffer = i;
} else {
buffer = endColumn;
endRow--;
posLoop = 0;
}
} else {
buffer = endColumn;
endRow--;
posLoop = 0;
fillArray();
}
}
}
}
int main(void) {
array_cont[endColumn][endColumn] = 1;
array_cont[endColumn][endColumn + 1] = 2;
//DO STUFF
u16_t max = ((size * size) - 1) / maxTimes;
for (u16_t j = 0; j < max; j++) {
fillArray();
curr = 0;
//DO STUFF
}
//Demostration
for (u16_t x = 0; x < size; x++) {
for (u16_t y = 0; y < size; y++)
printf("%-4d ", array_cont[x][y]);
printf("\n");
}
return 0;
}
Notice that the numbers along the diagonal (1, 9, 25, 49) are the squares of the odd numbers. That's an important clue, since it suggests that the 1 in the center of the matrix should be treated as the end of a spiral.
From the end of each spiral, the x,y coordinates should be adjusted up and to the right by 1. Then the next layer of the spiral can be constructed by moving down, left, up, and right by the same amount.
For example, starting from the position of the 1, move up and to the right (to the position of the 9), and then form a loop with the following procedure:
move down, and place the 2
move down, and place the 3
move left, and place the 4
move left, and place the 5
etc.
Thus the code looks something like this:
int size = 7;
int matrix[size][size];
int dy[] = { 1, 0, -1, 0 };
int dx[] = { 0, -1, 0, 1 };
int directionCount = 4;
int ringCount = (size - 1) / 2;
int y = ringCount;
int x = ringCount;
int repeatCount = 0;
int value = 1;
matrix[y][x] = value++;
for (int ring = 0; ring < ringCount; ring++)
{
y--;
x++;
repeatCount += 2;
for (int direction = 0; direction < directionCount; direction++)
for (int repeat = 0; repeat < repeatCount; repeat++)
{
y += dy[direction];
x += dx[direction];
matrix[y][x] = value++;
}
}
I saw already many approaches for doing a spiral. All a basically drawing it, by following a path.
BUT, you can also come up with an analytical calculation formula for a spiral.
So, no recursion or iterative solution by following a path or such. We can directly calculate the indices in the matrix, if we have the running number.
I will start with the spiral in mathematical positive direction (counter clockwise) in a cartesian coordinate system. We will concentrate on X and Y coordinates.
I made a short Excel and derived some formulas from that. Here is a short picture:
From the requirements we know that the matrix will be quadratic. That makes things easier. A little bit trickier is, to get the matrix data symmetrical. But with some simple formulas, derived from the prictures, this is not really a problem.
And then we can calculate x and y coordinates with some simple statements. See the below example program with long variable names for better understanding. The code is made using some step by step approach to illustrate the implementation. Of course it can be made more compact easily. Anyway. Let's have a look.
#include <iostream>
#include <cmath>
#include <iomanip>
int main() {
// Show some example values
for (long step{}; step < 81; ++step) {
// Calculate result
const long roundedSquareRoot = std::lround(std::sqrt(step));
const long roundedSquare = roundedSquareRoot * roundedSquareRoot;
const long distance = std::abs(roundedSquare - step) - roundedSquareRoot;
const long rsrIsOdd = (roundedSquareRoot % 2);
const long x = (distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
const long y = (-distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
// Show ouput
std::cout << "Step:" << std::setw(4) << step << std::setw(3) << x << ' ' << std::setw(3) << y << '\n';
}
}
So, you see that we really have an analytical solution. Given any number we can calculate the x and y coordinate using a formula. Cool.
Getting indices in a matrix is just adding some offset.
With that gained know how, we can now easily calculate the complete matrix. And, since there is no runtime activity needed at all, we can let the compiler do the work. We will simply use constexpr functions for everything.
Then the compiler will create this matrix at compile time. At runtime, nothing will happen.
Please see a very compact solution:
#include <iostream>
#include <iomanip>
#include <array>
constexpr size_t MatrixSize = 15u;
using MyType = long;
static_assert(MatrixSize > 0 && MatrixSize%2, "Matrix size must be odd and > 0");
constexpr MyType MatrixHalf = MatrixSize / 2;
using Matrix = std::array<std::array<MyType, MatrixSize>, MatrixSize >;
// Some constexpr simple mathematical functions ------------------------------------------------------------------------------
// No need for <cmath>
constexpr MyType myAbs(MyType v) { return v < 0 ? -v : v; }
constexpr double mySqrtRecursive(double x, double c, double p) {return c == p? c: mySqrtRecursive(x, 0.5 * (c + x / c), c); }
constexpr MyType mySqrt(MyType x) {return (MyType)(mySqrtRecursive((double)x,(double)x,0.0)+0.5); }
// Main constexpr function will fill the matrix with a spiral pattern during compile time -------------------------------------
constexpr Matrix fillMatrix() {
Matrix matrix{};
for (int i{}; i < (MatrixSize * MatrixSize); ++i) {
const MyType rsr{ mySqrt(i) }, rs{ rsr * rsr }, d{ myAbs(rs - i) - rsr }, o{ rsr % 2 };
const size_t col{ (size_t)(MatrixHalf +((d + rs - i - o) / (o ? -2 : 2)))};
const size_t row{ (size_t)(MatrixHalf -((-d + rs - i - o) / (o ? -2 : 2)))};
matrix[row][col] = i;
}
return matrix;
}
// This is a compile time constant!
constexpr Matrix matrix = fillMatrix();
// All the above has been done during compile time! -----------------------------------------
int main() {
// Nothing to do. All has beend done at compile time already!
// The matrix is already filled with a spiral pattern
// Just output
for (const auto& row : matrix) {
for (const auto& col : row) std::cout << std::setw(5) << col << ' '; std::cout << '\n';
}
}
Different coordinate systems or other spiral direction can be adapted easily.
Happy coding.
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 create a maze generator using recursive backtracking and have come across a problem that I just can't get my head around. For some reason my move function is returning the value "18446744073709551615". This is (of course) leading to a segmentation fault. Why is my move function returning such a large value when my move function can only increase or decrease the value by 2?
bool maze::generate(size_t x, size_t y) {
//mark the position as visited
labyrinth.s[y][x] = true;
//print to see progress
//this->print();
//if the position is not out of bounds
if (x < 0 || x > labyrinth.MAXWIDTH - 1 || y < 0 || y > labyrinth.MAXHIGHT - 1) {
//if the position is the endpoint return true
if (labyrinth.v[y][x - 1] == 'W' || labyrinth.v[y][x + 1] == 'W' || labyrinth.v[y - 1][x] == 'W' || labyrinth.v[y + 1][x] == 'W') {
return true;
}
}
//pick a random direction
do {
d = size_t(rand() % 4);
} while(!this->pos_test(x, y, d));
std::cout << x << ' ' << y << std::endl;
if (d == UP) {
y = move(x, y, UP);
}
else if (d == DOWN) {
y = move(x, y, DOWN);
}
else if (d == RIGHT) {
x = move(x, y, RIGHT);
}
else if (d == LEFT) {
x = move(x, y, LEFT);
}
else{
}
std::cout << x << ' ' << y << std::endl;
//recursively generate the maze
if (this->generate(x, y)) {
return true;
}
}
void maze::initialize(size_t x, size_t y) {
//set the maxhight and the maxwidth to y and x
labyrinth.MAXHIGHT = y;
labyrinth.MAXWIDTH = x;
//set all elements in the vector to #
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<char> temp;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp.push_back(labyrinth.wall);
}
labyrinth.v.push_back(temp);
}
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
if (j % 2 == 1 && i % 2 == 1 && j != labyrinth.MAXWIDTH - 1 && j != 0 && i != labyrinth.MAXHIGHT - 1 && i != 0) {
labyrinth.v[j][i] = labyrinth.path;
}
}
}
//set all posistions to unvisited
for (size_t i = 0; i < labyrinth.MAXHIGHT; i++) {
std::vector<bool> temp2;
for (size_t j = 0; j < labyrinth.MAXWIDTH; j++) {
temp2.push_back(false);
}
labyrinth.s.push_back(temp2);
}
//setup the start point
labyrinth.v[0][1] = 'S';
//setup the endpoint
labyrinth.v[labyrinth.MAXHIGHT - 2][labyrinth.MAXWIDTH - 1] = 'W';
}
//if a position has been visited or if not possible to go to return true
bool maze::pos_test(size_t x, size_t y, size_t d) const {
//if the position is out of bounds return false
if (x < 0 || y < 0 || x > labyrinth.MAXWIDTH - 1 || y > labyrinth.MAXHIGHT - 1) {
return true;
}
else if (x == 1 && d == LEFT) {
return true;
}
else if (y == 1 && d == UP) {
return true;
}
else if (x == labyrinth.MAXWIDTH - 1 && d == RIGHT) {
return true;
}
else if (y == labyrinth.MAXHIGHT - 1 && d == DOWN) {
return true;
}
else if (d == UP) {
return labyrinth.s[y - 2][x];
}
else if (d == DOWN) {
return labyrinth.s[y + 2][x];
}
else if (d == RIGHT) {
return labyrinth.s[y][x + 2];
}
else if (d == LEFT) {
return labyrinth.s[y][x - 2];
}
else {
return true;
}
}
size_t maze::move(size_t x, size_t y, size_t d) {
//if the position is out of bounds return without modifying
if (x < 0 || x > labyrinth.MAXWIDTH - 1) {
return x;
}
else if (y < 0 || y > labyrinth.MAXHIGHT - 1) {
return y;
}
else if (d == UP) {
labyrinth.v[y - 1][x] = labyrinth.path;
return y = y - 2;
}
else if (d == DOWN) {
labyrinth.v[y + 1][x] = labyrinth.path;
return y = y + 2;
}
else if (d == RIGHT) {
labyrinth.v[y][x + 1] = labyrinth.path;
return x = x + 2;
}
else if (d == LEFT) {
labyrinth.v[y][x - 1] = labyrinth.path;
return x = x - 2;
}
else {
}
}
You are underflowing your unsigned 64-bit return type size_t.
You are checking whether x and y are below zero, but that's not enough, because 0 and 1 will still be too low because you are subtracting 2!
The number you get is 0xFFFFFFFFFFFFFFFF in hexadecimal. This is the highest possible value for an unsigned 64-bit integer.
It comes from calculating 1 - 2. Yes, this is supposed to be -1, but because your move function doesn't return a signed number but an unsigned one (check the docs on size_t), it can't be negative! Instead, it wraps around to the highest possible number.
You can imagine this in the same way you would get ...99999999999 when you try to calculate 1 - 2 on paper ignoring the "you can't subtract a higher number from a smaller one on paper" rule.
As a side note: I guess the negative result is undesired anyway, because actually your huge number, once added to a pointer, will in turn overflow back into positive, so basically it will work the same is a real -1 in your case and the segmentation fault comes from accessing something right before the beginning of your buffer, not far beyond it, but it comes down to the same thing.
Apart from that, there is no need to do return y = y - 2 and such. Just return y - 2.
I need to place numbers within a grid such that it doesn't collide with each other. This number placement should be random and can be horizontal or vertical. The numbers basically indicate the locations of the ships. So the points for the ships should be together and need to be random and should not collide.
I have tried it:
int main()
{
srand(time(NULL));
int Grid[64];
int battleShips;
bool battleShipFilled;
for(int i = 0; i < 64; i++)
Grid[i]=0;
for(int i = 1; i <= 5; i++)
{
battleShips = 1;
while(battleShips != 5)
{
int horizontal = rand()%2;
if(horizontal == 0)
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != j)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row+k)*8+(column)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row+k)*8+(column)] = 1;
battleShipFilled = true;
}
battleShips++;
}
else
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row)*8+(column+k)] = 1;
battleShipFilled = true;
}
battleShips++;
}
}
}
}
But the code i have written is not able to generate the numbers randomly in the 8x8 grid.
Need some guidance on how to solve this. If there is any better way of doing it, please tell me...
How it should look:
What My code is doing:
Basically, I am placing 5 ships, each of different size on a grid. For each, I check whether I want to place it horizontally or vertically randomly. After that, I check whether the surrounding is filled up or not. If not, I place them there. Or I repeat the process.
Important Point: I need to use just while, for loops..
You are much better of using recursion for that problem. This will give your algorithm unwind possibility. What I mean is that you can deploy each ship and place next part at random end of the ship, then check the new placed ship part has adjacent tiles empty and progress to the next one. if it happens that its touches another ship it will due to recursive nature it will remove the placed tile and try on the other end. If the position of the ship is not valid it should place the ship in different place and start over.
I have used this solution in a word search game, where the board had to be populated with words to look for. Worked perfect.
This is a code from my word search game:
bool generate ( std::string word, BuzzLevel &level, CCPoint position, std::vector<CCPoint> &placed, CCSize lSize )
{
std::string cPiece;
if ( word.size() == 0 ) return true;
if ( !level.inBounds ( position ) ) return false;
cPiece += level.getPiece(position)->getLetter();
int l = cPiece.size();
if ( (cPiece != " ") && (word[0] != cPiece[0]) ) return false;
if ( pointInVec (position, placed) ) return false;
if ( position.x >= lSize.width || position.y >= lSize.height || position.x < 0 || position.y < 0 ) return false;
placed.push_back(position);
bool used[6];
for ( int t = 0; t < 6; t++ ) used[t] = false;
int adj;
while ( (adj = HexCoord::getRandomAdjacentUnique(used)) != -1 )
{
CCPoint nextPosition = HexCoord::getAdjacentGridPositionInDirection((eDirection) adj, position);
if ( generate ( word.substr(1, word.size()), level, nextPosition, placed, lSize ) ) return true;
}
placed.pop_back();
return false;
}
CCPoint getRandPoint ( CCSize size )
{
return CCPoint ( rand() % (int)size.width, rand() % (int)size.height);
}
void generateWholeLevel ( BuzzLevel &level,
blockInfo* info,
const CCSize &levelSize,
vector<CCLabelBMFont*> wordList
)
{
for ( vector<CCLabelBMFont*>::iterator iter = wordList.begin();
iter != wordList.end(); iter++ )
{
std::string cWord = (*iter)->getString();
// CCLog("Curront word %s", cWord.c_str() );
vector<CCPoint> wordPositions;
int iterations = 0;
while ( true )
{
iterations++;
//CCLog("iteration %i", iterations );
CCPoint cPoint = getRandPoint(levelSize);
if ( generate (cWord, level, cPoint, wordPositions, levelSize ) )
{
//Place pieces here
for ( int t = 0; t < cWord.size(); t++ )
{
level.getPiece(wordPositions[t])->addLetter(cWord[t]);
}
break;
}
if ( iterations > 1500 )
{
level.clear();
generateWholeLevel(level, info, levelSize, wordList);
return;
}
}
}
}
I might add that shaped used in the game was a honeycomb. Letter could wind in any direction, so the code above is way more complex then what you are looking for I guess, but will provide a starting point.
I will provide something more suitable when I get back home as I don't have enough time now.
I can see a potential infinite loop in your code
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
Here, nothing prevents row from being 0, as it was assignd rand%8 earlier, and k can be assigned a negative value (since j can be positive). Once that happens nothing will end the while loop.
Also, I would recommend re-approaching this problem in a more object oriented way (or at the very least breaking up the code in main() into multiple, shorter functions). Personally I found the code a little difficult to follow.
A very quick and probably buggy example of how you could really clean your solution up and make it more flexible by using some OOP:
enum Orientation {
Horizontal,
Vertical
};
struct Ship {
Ship(unsigned l = 1, bool o = Horizontal) : length(l), orientation(o) {}
unsigned char length;
bool orientation;
};
class Grid {
public:
Grid(const unsigned w = 8, const unsigned h = 8) : _w(w), _h(h) {
grid.resize(w * h);
foreach (Ship * sp, grid) {
sp = nullptr;
}
}
bool addShip(Ship * s, unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) { // if in valid range
if (s->orientation == Horizontal) {
if ((x + s->length) <= _w) { // if not too big
int p = 0; //check if occupied
for (int c1 = 0; c1 < s->length; ++c1) if (grid[y * _w + x + p++]) return false;
p = 0; // occupy if not
for (int c1 = 0; c1 < s->length; ++c1) grid[y * _w + x + p++] = s;
return true;
} else return false;
} else {
if ((y + s->length) <= _h) {
int p = 0; // check
for (int c1 = 0; c1 < s->length; ++c1) {
if (grid[y * _w + x + p]) return false;
p += _w;
}
p = 0; // occupy
for (int c1 = 0; c1 < s->length; ++c1) {
grid[y * _w + x + p] = s;
p += _w;
}
return true;
} else return false;
}
} else return false;
}
void drawGrid() {
for (int y = 0; y < _h; ++y) {
for (int x = 0; x < _w; ++x) {
if (grid.at(y * w + x)) cout << "|S";
else cout << "|_";
}
cout << "|" << endl;
}
cout << endl;
}
void hitXY(unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) {
if (grid[y * _w + x]) cout << "You sunk my battleship" << endl;
else cout << "Nothing..." << endl;
}
}
private:
QVector<Ship *> grid;
unsigned _w, _h;
};
The basic idea is create a grid of arbitrary size and give it the ability to "load" ships of arbitrary length at arbitrary coordinates. You need to check if the size is not too much and if the tiles aren't already occupied, that's pretty much it, the other thing is orientation - if horizontal then increment is +1, if vertical increment is + width.
This gives flexibility to use the methods to quickly populate the grid with random data:
int main() {
Grid g(20, 20);
g.drawGrid();
unsigned shipCount = 20;
while (shipCount) {
Ship * s = new Ship(qrand() % 8 + 2, qrand() %2);
if (g.addShip(s, qrand() % 20, qrand() % 20)) --shipCount;
else delete s;
}
cout << endl;
g.drawGrid();
for (int i = 0; i < 20; ++i) g.hitXY(qrand() % 20, qrand() % 20);
}
Naturally, you can extend it further, make hit ships sink and disappear from the grid, make it possible to move ships around and flip their orientation. You can even use diagonal orientation. A lot of flexibility and potential to harness by refining an OOP based solution.
Obviously, you will put some limits in production code, as currently you can create grids of 0x0 and ships of length 0. It's just a quick example anyway. I am using Qt and therefore Qt containers, but its just the same with std containers.
I tried to rewrite your program in Java, it works as required. Feel free to ask anything that is not clearly coded. I didn't rechecked it so it may have errors of its own. It can be further optimized and cleaned but as it is past midnight around here, I would rather not do that at the moment :)
public static void main(String[] args) {
Random generator = new Random();
int Grid[][] = new int[8][8];
for (int battleShips = 0; battleShips < 5; battleShips++) {
boolean isHorizontal = generator.nextInt(2) == 0 ? true : false;
boolean battleShipFilled = false;
while (!battleShipFilled) {
// Select a random row and column for trial
int row = generator.nextInt(8);
int column = generator.nextInt(8);
while (Grid[row][column] == 1) {
row = generator.nextInt(8);
column = generator.nextInt(8);
}
int lengthOfBattleship = 0;
if (battleShips == 0) // Smallest ship should be of length 2
lengthOfBattleship = (battleShips + 2);
else // Other 4 ships has the length of 2, 3, 4 & 5
lengthOfBattleship = battleShips + 1;
int numberOfCorrectLocation = 0;
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal && row + k > 0 && row + k < 8) {
if (Grid[row + k][column] == 1)
break;
} else if (!isHorizontal && column + k > 0 && column + k < 8) {
if (Grid[row][column + k] == 1)
break;
} else {
break;
}
numberOfCorrectLocation++;
}
if (numberOfCorrectLocation == lengthOfBattleship) {
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal)
Grid[row + k][column] = 1;
else
Grid[row][column + k] = 1;
}
battleShipFilled = true;
}
}
}
}
Some important points.
As #Kindread said in an another answer, the code has an infinite loop condition which must be eliminated.
This algorithm will use too much resources to find a solution, it should be optimized.
Code duplications should be avoided as it will result in more maintenance cost (which might not be a problem for this specific case), and possible bugs.
Hope this answer helps...
My computer graphics homework is to implement OpenGL algorithms using only the ability to draw points.
So obviously I need to get drawLine() to work before I can draw anything else. drawLine() has to be done using integers only. No floating point.
This is what I was taught. Basically, lines can be broken up into 4 different categories, positive steep, positive shallow, negative steep and negative shallow. This is the picture I am supposed to draw:
and this is the picture my program is drawing:
The colors are done for us. We are given vertices and we need to use Bresenham's Line algorithm to draw the lines based on the start and end points.
This is what I have so far:
int dx = end.x - start.x;
int dy = end.y - start.y;
//initialize varibales
int d;
int dL;
int dU;
if (dy > 0){
if (dy > dx){
//+steep
d = dy - 2*dx;
dL = -2*dx;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; y <= end.y; y++){
Vertex v(x,y);
drawPoint(v);
if (d >= 1){
d += dL;
}else{
x++;
d += dU;
}
}
} else {
//+shallow
d = 2*dy - dx;
dL = 2*dy;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; x <= end.x; x++) {
Vertex v(x,y);
drawPoint(v);
// if choosing L, next y will stay the same, we only need
// to update d by dL
if (d <= 0) {
d += dL;
// otherwise choose U, y moves up 1
} else {
y++;
d += dU;
}
}
}
} else {
if (-dy > dx){
cout << "-steep\n";
//-steep
d = dy - 2*dx;
//south
dL = 2*dx;
//southeast
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; y >= end.y; --y){
Vertex v(x,y);
drawPoint(v);
//if choosing L, next x will stay the same, we only need
//to update d
if (d >= 1){
d -= dL;
} else {
x++;
d -= dU;
}
}
} else {
cout << "-shallow\n";
//-shallow
d = 2*dy - dx;
dL = 2*dy;
dU = 2*dy - 2*dx;
for (int x = start.x, y = start.y; x <= end.x; x++){
Vertex v(x,y);
drawPoint(v);
if (d >= 0){
d += dL;
} else {
--y;
d -= dU;
}
}
}
}
I know my error is going to be something silly, but I honestly cannot figure out what I am doing wrong. Why are some of the lines drawn incorrectly as shown above?
/*BRESENHAAM ALGORITHM FOR LINE DRAWING*/
#include<iostream.h>
#include<graphics.h>
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
#include<dos.h>
void bhm_line(int,int,int,int,int);
void main()
{
int ghdriver=DETECT,ghmode,errorcode,x1,x2,y1,y2;
initgraph(&ghdriver,&ghmode,"..\\bgi");
errorcode = graphresult();
if(errorcode !=grOk)
{
cout<<"Graphics error:%s\n"<<grapherrormsg(errorcode);
cout<<"Press any key to halt:";
getch();
exit(1);
}
clrscr();
cout<<"Enter the coordinates (x1,y1): ";
cin>>x1>>y1;
cout<<"Enter the coordinates (x2,y2): ";
cin>>x2>>y2;
bhm_line(x1,y1,x2,y2,1);
getch();
}
void bhm_line(int x1,int y1,int x2,int y2,int c)
{
int x,y,dx,dy,dx1,dy1,px,py,xe,ye,i;
dx=x2-x1;
dy=y2-y1;
dx1=fabs(dx);
dy1=fabs(dy);
px=2*dy1-dx1;
py=2*dx1-dy1;
if(dy1<=dx1)
{
if(dx>=0)
{
x=x1;
y=y1;
xe=x2;
}
else
{
x=x2;
y=y2;
xe=x1;
}
putpixel(x,y,c);
for(i=0;x<xe;i++)
{
x=x+1;
if(px<0)
{
px=px+2*dy1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
y=y+1;
}
else
{
y=y-1;
}
px=px+2*(dy1-dx1);
}
delay(0);
putpixel(x,y,c);
}
}
else
{
if(dy>=0)
{
x=x1;
y=y1;
ye=y2;
}
else
{
x=x2;
y=y2;
ye=y1;
}
putpixel(x,y,c);
for(i=0;y<ye;i++)
{
y=y+1;
if(py<=0)
{
py=py+2*dx1;
}
else
{
if((dx<0 && dy<0) || (dx>0 && dy>0))
{
x=x+1;
}
else
{
x=x-1;
}
py=py+2*(dx1-dy1);
}
delay(0);
putpixel(x,y,c);
}
}
}
I implemented the original Bresenham's algorithm in C++ and tried to optimize as much as I could (especially regarding removing the IF from the interior loop).
It draws in a linear buffer instead of a surface, and for this matter, this implementation was almost as fast as EFLA (Extremely Fast Line Algorithm) (maybe 5% slower).
#include <vector>
#include <math.h>
using namespace std;
vector<unsigned char> buffer;
int imageSide = 2048; // the width of the surface
struct Point2Di
{
int x;
int y;
Point2Di(const int &x, const int &y): x(x), y(y){}
Point2Di(){}
};
void drawLine(const Point2Di &p0, const Point2Di &p1)
{
int dx = p1.x - p0.x;
int dy = p1.y - p0.y;
int dLong = abs(dx);
int dShort = abs(dy);
int offsetLong = dx > 0 ? 1 : -1;
int offsetShort = dy > 0 ? imageSide : -imageSide;
if(dLong < dShort)
{
swap(dShort, dLong);
swap(offsetShort, offsetLong);
}
int error = 2 * dShort - dLong;
int index = p0.y*imageSide + p0.x;
const int offset[] = {offsetLong, offsetLong + offsetShort};
const int abs_d[] = {2*dShort, 2*(dShort - dLong)};
for(int i = 0; i <= dLong; ++i)
{
buffer[index] = 255; // or a call to your painting method
const int errorIsTooBig = error >= 0;
index += offset[errorIsTooBig];
error += abs_d[errorIsTooBig];
}
}
The EFLA implementation that I am using is:
void drawLine(Point2Di p0, Point2Di p1)
{
bool yLonger=false;
int shortLen=p1.y-p0.y;
int longLen=p1.x-p0.x;
if (abs(shortLen)>abs(longLen)) {
swap(shortLen, longLen);
yLonger=true;
}
int decInc = longLen==0 ? decInc=0 : ((shortLen << 16) / longLen);
if (yLonger) {
p0.y*=imageSide;
p1.y*=imageSide;
if (longLen>0)
for (int j=0x8000+(p0.x<<16);p0.y<=p1.y;p0.y+=imageSide, j+=decInc)
buffer[p0.y + (j >> 16)] = 255; // or a call to your painting method
else
for (int j=0x8000+(p0.x<<16);p0.y>=p1.y;p0.y-=imageSide, j-=decInc)
buffer[p0.y + (j >> 16)] = 255; // or a call to your painting method
}
else
{
if (longLen>0)
for (int j=0x8000+(p0.y<<16);p0.x<=p1.x;++p0.x, j+=decInc)
buffer[(j >> 16) * imageSide + p0.x] = 255; // or a call to your painting method
else
for (int j=0x8000+(p0.y<<16);p0.x>=p1.x;--p0.x, j-=decInc)
buffer[(j >> 16) * imageSide + p0.x] = 255; // or a call to your painting method
}
}
In case anyone was wondering what the problem was, I still don't know what it was. What I ended up doing was re-factored my code so that the -shallow and -steep used the same algorithm as +shallow and +steep, respectively. After adjusting the x,y coordinates (negating the x or y coordinate), when I went to plot them I negated my original negation so that it plotted in the right spot.