I'm working on translation of some old MATLAB code to C++. I have noticed, that my custom function to calculate histogram that supposed to be equivalent to MATLAB [counts,centers]= hist(___) gives different results. I could not find a bug in my implementation, so I used MATLAB Coder to generate C++ function from MATLAB code and compare it to my C++ code. Here is a simple MATLAB function I used to generate C++ code:
function [counts, centers] = my_hist(values, bins)
[counts, centers] = hist(values, bins);
disp(centers);
disp(counts);
end
And a script to call it, so MATLAB can define inputs:
values = rand(1,1000);
bins = linspace(0.05, 0.95, 10);
[counts, centers] = my_hist(values, bins);
Based on the above, the Coder generates the function:
//
// File: my_hist.cpp
//
// MATLAB Coder version : 5.3
// C/C++ source code generated on : 17-Nov-2022 15:46:17
//
// Include Files
#include "my_hist.h"
#include "rt_nonfinite.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <math.h>
// Function Definitions
//
// MY_HIST Summary of this function goes here
// Detailed explanation goes here
//
// Arguments : const double values[1000]
// const double bins[10]
// double counts[10]
// double centers[10]
// Return Type : void
//
void my_hist(const double values[1000], const double bins[10],
double counts[10], double centers[10])
{
double edges[11];
double nn[11];
double absx;
int k;
int low_i;
std::copy(&bins[0], &bins[10], ¢ers[0]);
for (k = 0; k < 9; k++) {
absx = bins[k];
edges[k + 1] = absx + (bins[k + 1] - absx) / 2.0;
}
edges[0] = rtMinusInf;
edges[10] = rtInf;
for (k = 0; k < 9; k++) {
double absx_tmp;
absx_tmp = edges[k + 1];
absx = std::abs(absx_tmp);
if ((!std::isinf(absx)) && (!std::isnan(absx))) {
if (absx <= 2.2250738585072014E-308) {
absx = 4.94065645841247E-324;
} else {
frexp(absx, &low_i);
absx = std::ldexp(1.0, low_i - 53);
}
} else {
absx = rtNaN;
}
edges[k + 1] = absx_tmp + absx;
}
std::memset(&nn[0], 0, 11U * sizeof(double));
low_i = 1;
int exitg1;
do {
exitg1 = 0;
if (low_i + 1 < 12) {
if (!(edges[low_i] >= edges[low_i - 1])) {
for (low_i = 0; low_i < 11; low_i++) {
nn[low_i] = rtNaN;
}
exitg1 = 1;
} else {
low_i++;
}
} else {
for (k = 0; k < 1000; k++) {
low_i = 0;
absx = values[k];
if (!std::isnan(absx)) {
if ((absx >= edges[0]) && (absx < edges[10])) {
int high_i;
int low_ip1;
low_i = 1;
low_ip1 = 2;
high_i = 11;
while (high_i > low_ip1) {
int mid_i;
mid_i = (low_i + high_i) >> 1;
if (values[k] >= edges[mid_i - 1]) {
low_i = mid_i;
low_ip1 = mid_i + 1;
} else {
high_i = mid_i;
}
}
}
if (values[k] == edges[10]) {
low_i = 11;
}
}
if (low_i > 0) {
nn[low_i - 1]++;
}
}
exitg1 = 1;
}
} while (exitg1 == 0);
std::copy(&nn[0], &nn[10], &counts[0]);
counts[9] += nn[10];
}
//
// File trailer for my_hist.cpp
//
// [EOF]
//
I don't understande what happens in this chunk of code and why it is done:
for (k = 0; k < 9; k++) {
double absx_tmp;
absx_tmp = edges[k + 1];
absx = std::abs(absx_tmp);
if ((!std::isinf(absx)) && (!std::isnan(absx))) {
if (absx <= 2.2250738585072014E-308) {
absx = 4.94065645841247E-324;
} else {
frexp(absx, &low_i);
absx = std::ldexp(1.0, low_i - 53);
}
} else {
absx = rtNaN;
}
edges[k + 1] = absx_tmp + absx;
}
The function shift the edges of bins, but how and why? I will be grateful for help and explanation!
That bit of code adds eps to each bin edge except the first and last.
It is hard to know why hist does this, they must be working around some edge case they discovered (presumably related to floating-point rounding errors), and figured this was the best or the easiest solution.
Related
I'm trying implement a doodle jump video game. So far my program works well except the fact that platform are being generated rapidly rather than slowly being incremented as the player proceeds upwards. I'm using the cinder framework to implement it and using the poScene cinderblock to help me with the game flow and animation. The doodle character and each platform is a single jpg.
From my understanding, I think the platform is being generated every time update() is being called, which occurs at every frame. I tried using "std::chrono_duration_cast" to get time in ticks to cause a delay in the update function being called, but it doesn't seem to work.
I also tried calling the manipulatePlatform in Setup() but if I do that, the image of platform is not being generated.
using namespace cinder;
using cinder::app::KeyEvent;
namespace myapp {
using namespace po::scene;
using cinder::app::KeyEvent;
using po::scene::ImageView;
using po::scene::View;
MyApp::MyApp() {
state_ = GameState::kPlaying;
speed_ = 20;
}
void MyApp::setup() {
SoundSetUp(background_sound_,"BackgroundMusic.wav");
mViewController = ViewController::create();
my_scene = Scene::create(mViewController);
//setUpIntro();
}
void MyApp::DrawBackground() {
cinder::gl::Texture2dRef texture2D = cinder::gl::Texture::create(
cinder::loadImage(MyApp::loadAsset("background.jpg")));
cinder::gl::draw(texture2D, getWindowBounds());
}
void MyApp::SetUpCharacter() {
my_scene->getRootViewController()->getView()->addSubview(character);
}
void MyApp::SetUpPlatform() {
my_scene->getRootViewController()->getView()->addSubview(platform);
}
void MyApp::ManipulatePlatform() {
cinder::gl::Texture2dRef texture_platform = cinder::gl::Texture::create(
cinder::loadImage(MyApp::loadAsset("platform.jpg")));
platform = po::scene::ImageView::create(texture_platform);
my_scene->getRootViewController()->getView()->addSubview(platform);
point array[20];
for (int i = 0; i < 10; i++) {
array[i].x = cinder::Rand::randInt() % 400;
array[i].y = cinder::Rand::randInt() % 533;
}
if (y < h) {
for (int i = 0; i < 10; i++) {
y = h;
array[i].y = array[i].y - change_in_height;
if (array[i].y > 533) {
array[i].y = 0;
array[i].x = cinder::Rand::randInt() % 400;
}
}
}
auto end = std::chrono::steady_clock::now();
for (int i = 0; i < 10; i++) {
platform->setPosition(array[i].x, array[i].y);
}
}
void MyApp::SimulateGame() {
cinder::gl::Texture2dRef texture_character = cinder::gl::Texture::create(
cinder::loadImage(MyApp::loadAsset("doodle.jpg")));
character = po::scene::ImageView::create(texture_character);
my_scene->getRootViewController()->getView()->addSubview(character);
point array[20];
change_in_height = change_in_height + 0.2;
y = y + change_in_height;
if (y > 500) {
change_in_height = change_in_height - 10;
}
for (int i = 0; i < 10; i++) {
if ((x + 50 > array[i].x) && (x + 20 < array[i].x + 68)
&& (y + 70 > array[i].y) && (y + 70 < array[i].y + 14) && (change_in_height > 0)) {
change_in_height = -10;
}
}
character->setPosition(x, y);
}
void MyApp::update() {
auto start = std::chrono::steady_clock::now();
ManipulatePlatform();
SimulateGame();
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
while (duration < 100) {
std::cout << duration++;
}
my_scene->update();
}
void MyApp::draw() {
my_scene->getRootViewController()->getView()->removeAllSubviews();
DrawBackground();
SetUpPlatform();
SetUpCharacter();
my_scene->draw();
}
void MyApp::keyDown(KeyEvent event) {
switch (event.getCode()) {
case KeyEvent::KEY_RIGHT:
x = x + 50;
break;
case KeyEvent::KEY_LEFT:
x = x - 50;
}
}
void MyApp::ResetGame() {
my_scene->getRootViewController()->getView()->removeAllSubviews();
}
void MyApp::SoundSetUp(cinder::audio::VoiceRef &audio_object, std::string file_path) {
cinder::audio::SourceFileRef sourceFile = cinder::audio::load(MyApp::loadAsset(file_path));
audio_object = cinder::audio::Voice::create(sourceFile);
audio_object->start();
}
void MyApp::setUpIntro() {
intro_background_doodle_jump = cinder::gl::Texture::create(
cinder::loadImage(MyApp::loadAsset("intro.jpg")));
intro_background_doodle_jump->setCleanBounds(cinder::Area(0, 0 , getWindowWidth(), getWindowHeight()));
}
}// namespace myapp
I'm trying to solve this problem in C++:
"Given a sequence S of integers, find a number of increasing sequences I such that every two consecutive elements in I appear in S, but on the opposite sides of the first element of I."
This is the code I've developed:
#include<iostream>
#include<set>
#include<vector>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int solution(vector<int> &H) {
// set up
int N = (int)H.size();
if (N == 0 || N == 1) return N;
long long sol = 0;
// build trees
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt), leftTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri, li;
for (int i = 0; i < N; i++) {
Element* e = new Element;
e->acc = 0;
e->con = 0;
e->height = H[i];
rightTree.insert(e);
}
//tree elements set up
ri = --rightTree.end();
Element* elem = *ri;
elem->con = 1;
elem->acc = 1;
while (elem->height > H[0]) {
Element* succ = elem;
ri--;
elem = *ri;
elem->con = 1;
elem->acc = succ->acc + 1;
}
rightTree.erase(ri);
elem->con = elem->acc;
leftTree.insert(elem);
sol += elem->acc;
// main loop
Element* pE = new Element;
for (int j = 1; j < (N - 1); j++) {
// bad case
if (H[j] < H[j - 1]) {
///////
Element* nE = new Element;
nE->height = H[j];
pE->height = H[j - 1];
rightTree.erase(nE);
leftTree.insert(nE);
///////
li = leftTree.lower_bound(pE);
long ltAcc = (*li)->acc;
li--;
///////
ri = rightTree.lower_bound(pE);
long rtAcc = 0;
if (ri != rightTree.end()) rtAcc = (*ri)->acc;
ri--;
///////
while (ri != (--rightTree.begin()) && (*ri)->height > H[j]) {
if (fncomp(*ri, *li)) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
else {
(*ri)->con = ltAcc + 1;
(*ri)->acc = ltAcc + 1 + rtAcc;
rtAcc = (*ri)->acc;
--ri;
}
}
while ((*li)->height > H[j]) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
sol += (*li)->acc;
}
// good case
else {
Element* nE = new Element;
nE->height = H[j];
ri = rightTree.upper_bound(nE);
li = leftTree.upper_bound(nE);
rightTree.erase(nE);
if (li == leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1;
}
else if (li != leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1 + (*li)->acc;
}
else if (li == leftTree.end() && ri != rightTree.end()) {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con;
}
else {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con + (*li)->acc;
}
leftTree.insert(nE);
sol += nE->acc;
}
}
// final step
li = leftTree.upper_bound(*rightTree.begin());
while (li != leftTree.end()) {
sol++;
li++;
}
sol++;
return (int)(sol % 1000000007);
}
int main(int argc, char* argv[]) {
vector<int> H = { 13, 2, 5 };
cout << "sol: " << solution(H) << endl;
system("pause");
}
The main function calls solution(vector<int> H). The point is, when the argument has the particular value of H = {13, 2, 5} the VC++ compiled program give an output value of 7 (which is the correct one), but the GNU g++ compiled program give an output value of 5 (also clang compiled program behave like this).
I'm using this website, among others, for testing different compilers
http://rextester.com/l/cpp_online_compiler_gcc
I've tried to figure out the reason for this wierd behaviour but didn't found any relevant info. Only one post treat a similar problem:
Different results VS C++ and GNU g++
and that's why I'm using long long types in the code, but the problem persists.
The problem was decrementing the start-of-sequence --rightTree.begin()
As I found VC++ and GNU g++ does not behave the same way on above operation. Here is the code that shows the difference, adapted from http://www.cplusplus.com/forum/general/84609/:
#include<iostream>
#include<set>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int main(){
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri;
ri = rightTree.begin();
--ri;
++ri;
if(ri == rightTree.begin()) cout << "it works!" << endl;
}
so I'm working on a school assignement, as I'm learning C++. I'm not so much looking for code to be given to me as help understanding/coming up with the right algorithm for this problem.
I need to create a (5x5x5) 3d maze of 1's and 0's. Populate it randomly (except 0,0,0 being a 1 for start and 4,4,4 being a 1 at the finish.
Here's what I've done.
I made a cube object:
#include "cube.h"
Cube :: Cube(int cube_value)
{
cube_value = 0;
chk_up = false;
chk_down = false;
chk_left = false;
chk_right = false;
chk_front = false;
chk_back = false;
}
Cube :: ~Cube(void){}
in my maze managing class I initialize like this
PathFinder::PathFinder()
{
// initializing / sizing 5x5x5 Maze
Maze.resize(5);
for(int y = 0; y < 5 ; ++y)
{
Maze[y].resize(5);
for(int z = 0; z<5 ; ++z)
{
Maze[y][z].resize(5);
}
}
int at_x = 0;
int at_y = 0;
int at_z = 0;
}
The header for that class:
#include "PathfinderInterface.h"
#include "cube.h"
class PathFinder : public PathfinderInterface {
private:
int at_x;
int at_y;
int at_z;
public:
vector<vector<vector<Cube> > > Maze;
PathFinder();
virtual ~PathFinder();
string getMaze();
void createRandomMaze();
bool importMaze(string file_name);
vector<string> solveMaze();
};
So I'm trying to populate it and this is what I have, it might not make a ton of sense:
void PathFinder :: fillmaze()
{
Maze[0][0][0].cube_value = 1;
Maze[4][4][4].cube_value = 1;
int atx = 0 , aty = 0 , atz = 0;
while(atx<5 && aty < 5 && atz < 5)
{
if(atz == 5)
{
aty = aty + 1;
}
if(aty == 5)
{
atx = atx + 1;
atx = 0;
}
for(atz=0 ; atz<5 ; ++atz)
{
if((atx!= 0 && aty!=0 && atz!=0) || (atx!=4 && aty!=4 && atz!= 4) )
{
Maze[atx][aty][atz].cube_value = (rand() % 2);
}
}
}
}
I'm attempting to fill all the z axis and trace to the right on x, then move up one y and do the same, is this a good approach, or is there a better way of doing this? I'm just getting pretty confused.
void PathFinder :: fillmaze()
{
int atx = 0 , aty = 0 , atz = 0;
while(atz<=4)
{
if(atx == 5)
{
aty = aty + 1;
}
if(aty == 5)
{
aty = 0;
atz = atz + 1;
}
if(atz < 5)
{
for(atx=0 ; atx<5 ; ++atx)
{
Maze[atx][aty][atz].cube_value = (rand() % 2);
}
}
}
Maze[0][0][0].cube_value = 1;
Maze[4][4][4].cube_value = 1;
}
This worked! Now on to maze traversal! :/
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...
This is a problem I have been struggling for a week, coming back just to give up after wasted hours...
I am supposed to find coefficents for the following Laguerre polynomial:
P0(x) = 1
P1(x) = 1 - x
Pn(x) = ((2n - 1 - x) / n) * P(n-1) - ((n - 1) / n) * P(n-2)
I believe there is an error in my implementation, because for some reason the coefficents I get seem way too big. This is the output this program generates:
a1 = -190.234
a2 = -295.833
a3 = 378.283
a4 = -939.537
a5 = 774.861
a6 = -400.612
Description of code (given below):
If you scroll the code down a little to the part where I declare array, you'll find given x's and y's.
The function polynomial just fills an array with values of said polynomial for certain x. It's a recursive function. I believe it works well, because I have checked the output values.
The gauss function finds coefficents by performing Gaussian elimination on output array. I think this is where the problems begin. I am wondering, if there's a mistake in this code or perhaps my method of veryfying results is bad? I am trying to verify them like that:
-190.234 * 1.5 ^ 5 - 295.833 * 1.5 ^ 4 ... - 400.612 = -3017,817625 =/= 2
Code:
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;
double polynomial(int i, int j, double **tab)
{
double n = i;
double **array = tab;
double x = array[j][0];
if (i == 0) {
return 1;
} else if (i == 1) {
return 1 - x;
} else {
double minusone = polynomial(i - 1, j, array);
double minustwo = polynomial(i - 2, j, array);
double result = (((2.0 * n) - 1 - x) / n) * minusone - ((n - 1.0) / n) * minustwo;
return result;
}
}
int gauss(int n, double tab[6][7], double results[7])
{
double multiplier, divider;
for (int m = 0; m <= n; m++)
{
for (int i = m + 1; i <= n; i++)
{
multiplier = tab[i][m];
divider = tab[m][m];
if (divider == 0) {
return 1;
}
for (int j = m; j <= n; j++)
{
if (i == n) {
break;
}
tab[i][j] = (tab[m][j] * multiplier / divider) - tab[i][j];
}
for (int j = m; j <= n; j++) {
tab[i - 1][j] = tab[i - 1][j] / divider;
}
}
}
double s = 0;
results[n - 1] = tab[n - 1][n];
int y = 0;
for (int i = n-2; i >= 0; i--)
{
s = 0;
y++;
for (int x = 0; x < n; x++)
{
s = s + (tab[i][n - 1 - x] * results[n-(x + 1)]);
if (y == x + 1) {
break;
}
}
results[i] = tab[i][n] - s;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int num;
double **array;
array = new double*[5];
for (int i = 0; i <= 5; i++)
{
array[i] = new double[2];
}
//i 0 1 2 3 4 5
array[0][0] = 1.5; //xi 1.5 2 2.5 3.5 3.8 4.1
array[0][1] = 2; //yi 2 5 -1 0.5 3 7
array[1][0] = 2;
array[1][1] = 5;
array[2][0] = 2.5;
array[2][1] = -1;
array[3][0] = 3.5;
array[3][1] = 0.5;
array[4][0] = 3.8;
array[4][1] = 3;
array[5][0] = 4.1;
array[5][1] = 7;
double W[6][7]; //n + 1
for (int i = 0; i <= 5; i++)
{
for (int j = 0; j <= 5; j++)
{
W[i][j] = polynomial(j, i, array);
}
W[i][6] = array[i][1];
}
for (int i = 0; i <= 5; i++)
{
for (int j = 0; j <= 6; j++)
{
cout << W[i][j] << "\t";
}
cout << endl;
}
double results[6];
gauss(6, W, results);
for (int i = 0; i < 6; i++) {
cout << "a" << i + 1 << " = " << results[i] << endl;
}
_getch();
return 0;
}
I believe your interpretation of the recursive polynomial generation either needs revising or is a bit too clever for me.
given P[0][5] = {1,0,0,0,0,...}; P[1][5]={1,-1,0,0,0,...};
then P[2] is a*P[0] + convolution(P[1], { c, d });
where a = -((n - 1) / n)
c = (2n - 1)/n and d= - 1/n
This can be generalized: P[n] == a*P[n-2] + conv(P[n-1], { c,d });
In every step there is involved a polynomial multiplication with (c + d*x), which increases the degree by one (just by one...) and adding to P[n-1] multiplied with a scalar a.
Then most likely the interpolation factor x is in range [0..1].
(convolution means, that you should implement polynomial multiplication, which luckily is easy...)
[a,b,c,d]
* [e,f]
------------------
af,bf,cf,df +
ae,be,ce,de, 0 +
--------------------------
(= coefficients of the final polynomial)
The definition of P1(x) = x - 1 is not implemented as stated. You have 1 - x in the computation.
I did not look any further.