I'm making a neural network in c++ to traverse a maze knowing where the player is, which 2d direction it can move in (up,down,left,right) and where the goal is, i can at any time get the distance of the player to the goal as well
thus far this is my code
std::string NeuralNetwork::evolve(player p)
{
openMoves = p.getMoves();
playerPos = p.getListPos();
goalPos = p.getGoalPos();
values.clear();
for (auto item : openMoves)
values.push_back(item);
values.push_back(playerPos.x);
values.push_back(playerPos.y);
if (outputs.size() == 0)
outputs.resize(4);
if (inputs.size() == 0)
inputs.resize(values.size());
for (int i = 0; i < inputs.size(); i++)
{
inputs[i].srcValue = values[i];
if (inputs[i].weightList.size() == 0)
{
for (int j = 0; j < outputs.size(); j++)
{
inputs[i].weightList.push_back(dist(100) / 100.0f);
}
}
}
for (int i = 0; i < outputs.size(); i++)
{
outputs[i].out = 0;
if (outputs[i].theta == NULL)
outputs[i].theta = dist(-100, 100) / 100.0f;//rand funct to produce int between -100-100 then divide by 100 to get theta between -1 and 1
for (auto a : inputs)
{
outputs[i].out += (a.srcValue * a.weightList[i]);
}
outputs[i].finalOut = outputs[i].out / (1.0f + fabs(outputs[i].out));
//outputs[i].finalOut = 1 / (1 + std::pow(exp(1), -(outputs[i].out - outputs[i].theta)));
}
for (int i = 0; i < outputs.size(); i++)//backwards prop
{
float e = 1 - outputs[i].finalOut;
float delta = outputs[i].finalOut * (1 - outputs[i].finalOut)*e;
for (int j = 0; j < inputs.size(); j++)
{
inputs[j].weightList[i] += alpha * inputs[j].srcValue * delta;
}
outputs[i].theta += alpha * (-1)*delta;
}
the neural network is a function that's called every frame, the player starts in the top left and the goal is in the bottom right, the function returns a direction for the player to move in.
however, using backwards propagation each output final is never 1 which is what I use to determine its direction using
for (int i = 0; i < outputs.size(); i++)
{
if (outputs[0].finalOut == 1)//left
{
return "01";
}
else if (outputs[1].finalOut == 1)//up
{
return "10";
}
else if (outputs[2].finalOut == 1)//down
{
return "11";
}
else if (outputs[3].finalOut == 1)//right
{
return "00";
}
}
return "";}
however the function always returns no movement at all and i'm not sure why, even after a few minutes of waiting, there are no hidden layers to the network i'm starting simple with the inputs directly linking to the output
i'm unsure if my error calculation is correct to then adjust the weights. i'm unsure what i should be using to allow the ai to determine how to move
To represent all the cells I'm using a variable std::vector<bool> cells to represent the cells where true represents a live cell. To update the canvas, I have a variable std::vector<int> neighborCounts, where neighborCounts[i] represents how many live neighbors cell[i] has. In the update loop, I loop through all the cells, and if its a live cell, I add 1 to the neighborCounts of all the adjacent cells. Then after determining all of the neighbors, I once again loop through all the cells and perform the updates based on the number of neighbors it has.
std::vector<int> neighborCounts(NUM_ROWS * ROW_SIZE, 0);
for (int x = 0; x < ROW_SIZE; x++)
{
for (int y = 0; y < NUM_ROWS; y++)
{
if (cells[convertCoord(x, y)])
{
for (int m = x - 1; m <= x + 1; m++)
{
for (int n = y - 1; n <= y + 1; n++)
{
if (!(m == x && n == y) && m >= 0 && m < ROW_SIZE && n >= 0 && n < NUM_ROWS)
{
neighborCounts[convertCoord(m, n)] += 1;
}
}
}
}
}
}
for (int x = 0; x < ROW_SIZE; x++)
{
for (int y = 0; y < NUM_ROWS; y++)
{
int coord = convertCoord(x, y);
int numNeighbors = neighborCounts[coord];
if (cells[coord])
{
if (numNeighbors < 2)
{
cells[coord] = false;
}
else if (numNeighbors > 3)
{
cells[coord] = false;
}
}
else
{
if (numNeighbors == 3)
{
cells[coord] = true;
}
}
}
}
Then in the render function, I loop through all the cells and if its alive I draw it to the screen.
This seems to be the most straightforward way to do this, but there's definitely room for further optimization. How do powder toys and other apps manage a huge array of particles and yet still manage to run amazingly smooth? What is the most efficient way to manage all the cells in Conway's Game of Life?
Beginner at c++ here.
for (int z = 0; z < arraysize; z++) {
if (generated[z][0] == generated[z][1] && generated[z][1] == generated[z][2]) {
wins++;
}
if (generated[0][z] == generated[1][z] && generated[1][z] == generated[2][z]) {
wins++;
}
As you can see it checks for the horizontal lines. I would like to check wether or not there are 3 in a row diagonally. If there is, the wins variable should add one. Any ideas?
You can do this by using z as the index for both extents instead of just one.
for (int z = 0; z < arraysize; z++)
{
if (generated[z][z] == generated[0][0])
{
//... handle it
}
if (generated[arraysize - z - 1][z] == generated[arraysize - 1][0])
{
//... handle it
}
}
Unfortunately this will only get you so far. The current logic in your code is not going to work as you expect. The problem is that it keeps a cumulative count of matches across all lines both horizontally and vertically. If you have several partial matches you could end up with a an incorrect win value. You can avoid this problem by adding a couple of additional loops to check the contents of each the vertical and horizontal lines as you perform your scan. This will require a couple of additional flags to be added as well to keep track of whether there is a win in either direction. The following example should provide you with a much more flexible set of checks that are flexible and can be used for any size array.
bool hwin = false;
bool vwin = false;
int d1wins = 0;
int d2wins = 0;
for (int z = 0; z < arraysize; z++)
{
int hwins = 0;
int vwins = 0;
// Check horizontal line
for (int i = 0; i < arraysize; ++i)
{
if (generated[i][z] == generated[0][z])
{
hwins++;
}
}
hwin = hwin || hwins == arraysize;
// Check vertical line
for (int i = 0; i < arraysize; ++i)
{
if (generated[z][i] == generated[z][0])
{
vwins++;
}
}
vwin = vwin || vwins == arraysize;
// Check diagonal
if (generated[z][z] == generated[0][0])
{
d1wins++;
}
// Check diagonal
if (generated[arraysize - z - 1][z] == generated[arraysize - 1][0])
{
d2wins++;
}
}
bool dwin = d1wins == arraysize || d2wins == arraysize;
From two if condition, you used, I think you are trying something like 3*3 Tic-tac-toe.
So, if your arraysize is 3, you can't use following checking in your loop:
if (generated[z][z] == generated[z+1][z+1] && generated[z+1][z+1] == generated[z+2][z+2])
{
wins++;
}
z+2 and z+1 will cross the array limit.
So you can check it outside of your loop:
generated[0][0] == generated[1][1] && generated[1][1] == generated[2][2]
generated[0][2] == generated[1][1] && generated[1][1] == generated[2][0]
Integer Range = 1;
for(Integer k = -Range; k <= Range; ++k)
{
for(Integer j = -Range; j <= Range; ++j)
{
for(Integer i = -Range; i <= Range; ++i)
{
Integer MCID = GetCellID(&CONSTANT_BOUNDINGBOX,CIDX +i, CIDY + j,CIDZ
+ k);
if(MCID < 0 || MCID >= c_CellNum)
{
continue;
}
unsigned int TriangleNum = c_daCell[MCID].m_TriangleNum;
for(unsigned int l = 0; l < TriangleNum; ++l)
{
TriangleID=c_daCell[MCID].m_TriangleID[l];
if( TriangleID >= 0 && TriangleID < c_TriangleNum && TriangleID
!= NearestID)// No need to calculate again for the same triangle
{
CDistance Distance ;
Distance.Magnitude = CalcDistance(&c_daTriangles[TriangleID], &TargetPosition,
&Distance.Direction);
if(Distance.Magnitude < NearestDistance.Magnitude)
{
NearestDistance = Distance;
NearestID = TriangleID;
}
}
}
}
}
}
}
c_daSTLDistance[ID] = NearestDistance;
c_daSTLID[ID] = NearestID;
GetCellID is the function to return the cellid in the variable CID with CIDX,CIDY,CIDZ with its position in the 3 axes
here the above code is a function to calculate the distance ,actually STL distance between a point and the triangles of the stl. This code runs fine however the problem is it is too slow as it has large number of loops within the code. Now my concern is to optimize the loop. Is there any technique of optimizing the loops within the code?
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...