I am developing an 8x8 grid game. Similar to checkers I guess. Players can move in any direction and jump/take a piece in any direction.
I am individually writing out EVERY single move.. including invalid moves. Is there a way for me to clean this up? I believe there is but I just dont see it at the moment, I cant seem to think up a simpler solution.
Everything works fine, I just am curious if its possible to shorten it.
Heres some of the moves:
//If player attempts to move 2 squares within the same column
if(checkRow == 2 && checkCol == 0){
//Checks if row is OOB. If not, Checks to see if there is a player 2 one position to the right.
//If yes checks to see if row - 2 equals the initial player. This avoids methods getting called
// When surrounded by multiple pieces.
if(fromRow+1 < 8 && boardGame[fromRow+1][fromCol].getPlayer()== 2 && boardGame[toRow-2][toCol].getPlayer() == 1){
board[fromRow+1][fromCol] = 0;
valid = true;
updateTurnCount();
}
//Checks if row is OOB. If not, Checks to see if there is a player 2 one position to the left.
else if(fromRow-1 >= 0 && boardGame[fromRow-1][fromCol].getPlayer()== 2 && boardGame[toRow+2][toCol].getPlayer() == 1){
board[fromRow-1][fromCol] = 0;
valid = true;
updateTurnCount();
}
else if(fromRow+1 < 8 && boardGame[fromRow+1][fromCol].getPlayer()== 1 && boardGame[toRow-2][toCol].getPlayer() == 2){
board[fromRow+1][fromCol] = 0;
valid = true;
updateTurnCount();
}
else if(fromRow-1 >= 0 && boardGame[fromRow-1][fromCol].getPlayer()== 1 && boardGame[toRow+2][toCol].getPlayer() == 2){
board[fromRow-1][fromCol] = 0;
valid = true;
updateTurnCount();
}
}
Don't quite get what your asking here but you can certainly pull most of this logic out into simple statements that will cover all cases.
if ( newRow <0 || newRow >8 ) {
disallowMove();
return;
}
if ( board[newRow][newCol].player() != board[oldRow][oldCol].player() ){
disallowMove();
return;
}
board[newRow][newCol] == somethingElse;
updateTurnCount();
lambdas can shorten considerably the code: for instance, declaring just immediately before the main loop
auto from = [boardGame,fromRow,fromCol](int deltaRow, int deltaCol) {
return boardGame[fromRow+deltaRow][fromCol+deltaCol];
};
auto to = [boardGame,toRow,toCol](int deltaRow, int deltaCol) {
return boardGame[toRow+deltaRow][toCol+deltaCol];
};
the conditions can be written like
if(fromRow+1 < 8 && from(+1,0) == 2 && to(-2,0) == 1){...}
Further cleanup can follow from factorization of repeated code: the action taken is always the same, and uses the same variables pattern: then the lambda (assuming boardGame etc are member variables) could be
auto action = [this](int df_Row, int df_Col, int dt_Row, int dt_Col) {
int f_row = fromRow+deltaRow, f_col = fromCol+deltaCol;
int t_row = toRow+dt_Row, t_col = toCol+dt_Col;
if (f_row < 8 && boardGame[f_row][f_col].getPlayer()== 2 &&
boardGame[t_row][t_col].getPlayer() == 1){
boardGame[f_row][f_col] = 0;
valid = true;
return true;
}
return false;
};
and the logic become simpler:
if (action(+1,0,-2,0)) updateTurnCount();
...
Related
I have read and understood how Mergesort works (as a text) and now I'm trying to code it. I have finished the part where you divide the data (I use vectors) until it has each size of 1. Now I have written code for another required part in Mergesort, I don't know how to call it but I just call it "compare and ordering part".
You have 2 vectors and this part is supposed to compare the very first elements, take the smaller element, then remove the chosen element and put it inside a new vector. Doing that untill both vectors have size 0.
I'm sorry for the long code but I really don't see why the very last element is ignored by the code? : /
I have added some comments so maybe it is easier to follow what I tried to do.
I tried as input:
vector<int> v1 = {1,4,5,9};
vector<int> v2 = {2,3,6,7,8};
Output:
1 2 3 4 5 6 7 8 0
vector<int> sortit(vector<int> &left, vector<int> &right) {
vector<int> sorted(left.size() + right.size());
int i = 0;
while (left.size() > 0 && right.size() > 0) {
if (left.at(0) <= right.at(0)) {
sorted.at(i) = left.at(0); // putting the smaller element into the new vector
left.erase(left.begin()); // removing this smaller element from the (old) vector
}
else if (right.at(0) <= left.at(0)) {
sorted.at(i) = right.at(0); // see comment above
right.erase(right.begin()); // see comment above
}
else if (left.size() <= 0 && right.size() > 0) { // if left vector has no elements, then take all elements of the right vector and put them into the new vector
while (right.size() > 0) {
sorted.at(i) = right.at(0);
right.erase(right.begin());
}
}
else if (right.size() <= 0 && left.size() > 0) { // the same just for the right vector
while (left.size() > 0) {
sorted.at(i) = left.at(0);
left.erase(left.begin());
}
}
i++;
}
return sorted;
}
The check of whether one of the arrays has exhausted and other array has remaining elements should be outside the main while loop.
So, try to put the below two checks outside.
else if (left.size() <= 0 && right.size() > 0)
else if (right.size() <= 0 && left.size() > 0)
Think of what will happen when one array has (1) and other (2,3), On adding 1 to the sorted vector, the while(left.size() > 0 && right.size() > 0) condition is false and the loop breaks. So the other elements are ignored.
don't know how to call [the] "compare and ordering part"
Conventionally: merge
sorry for the long code
use a
first = *left <= *right ? left : right
and manipulate that, avoiding code replication.
don't see why the very last element is ignored by the code?
left.at(0) <= right.at(0)
and
right.at(0) <= left.at(0)
cover all possible comparison results (equality twice): no further else will get evaluated.
Moving "the move parts" to follow "the proper merge" as suggested by Msk, note that the preliminary checks are dispensable - just use "the move loops".
There is a lot to say about your code (starting with commentation) - see code reviews of C++ merge implementations for ideas.
If you want code you are in control of reviewed at CR#SE, be sure to be on topic and write a Good Question.
The code could be simplified:
vector<int> sortit(vector<int> &left, vector<int> &right) {
vector<int> sorted(left.size() + right.size());
int i = 0;
while (1) {
if (left.at(0) <= right.at(0)) {
sorted.at(i++) = left.at(0);
left.erase(left.begin());
if(left.size == 0){
do{
sorted.at(i++) = right.at(0);
right.erase(right.begin());
}while(right.size != 0);
return;
}
} else {
sorted.at(i++) = right.at(0);
right.erase(right.begin());
if(right.size == 0){
do{
sorted.at(i++) = left.at(0);
left.erase(left.begin());
}while(left.size != 0);
return;
}
}
}
return sorted;
}
rather than erasing elements of vectors, indexing could be used instead:
vector<int> sortit(vector<int> &left, vector<int> &right) {
vector<int> sorted(left.size() + right.size());
int i = 0;
int ll = 0;
int rr = 0;
while (1) {
if (left[ll] <= right[rr]) {
sorted[i++] = left[ll++];
if(ll == left.size){
do{
sorted[i++] = right[rr++];
}while(rr != right.size);
break;
}
} else {
sorted[i++] = right[rr++];
if(rr == right.size){
do{
sorted[i++] = left[ll++];
}while(ll != left.size);
break;
}
}
}
return sorted;
}
I've got a double[9] and want to check if it contains the values (1,0,0,0,1,0,0,0,1). Is there a cleaner way than this?
if (ornt1[0] == 1 && ornt1[1] == 0 && ornt1[2] == 0
&& ornt1[3] == 0 && ornt1[4] == 1 && ornt1[5] == 0
&& ornt1[6] == 0 && ornt1[7] == 0 && ornt1[8] == 1 )
I'm using C++.
It is not a good idea to compare double values strictly. I would recommend you create a constant array to compare against and then use a cycle and also use a tolerance(e.g. 1e-9):
bool doublesEqual(double a, double b) {
return fabs(a - b) < 1e-9;
}
const double expected[9] = {1,0,0,0,1, 0, 0, 0, 1};
bool equal = true;
for (int i = 0; i< 9; ++i) {
if (!doublesEqual(expected[i], ornt1[i])) {
equal = false;
break;
}
}
if (equal) { // do smth
EDIT: as suggested by John Zwinck I have edited the code to be able to handle the case when the array we compare contains only NAN. I have edited his suggestion a bit to make the code more readable. Please refer to his comment below for clarification why this is needed.
I'm working on a Sudoku solver, and my program is having trouble recursing backwards when it has exhausted its outputs.
I have four functions that do the check:
scolumn, srow, sbox. Each one will return false if the number already exists in the column row or box respectively.
bool sudoku::solve(int row, int column)
{
if(column == 9)
{
column = 0;
row +=1;
}
if(puzzle[row][column] != 0)
{
solve(row, column + 1);
return false;
}
else
{
for(int n = 0; n < 10; n ++)
{
if(srow(column, n) && scolumn(row,n) && sbox(row, column, n)
{
puzzle[row][column] = n;
if(!solve(row, column + 1);
table[row][column] = 0;
}
}
puzzle[row][column] = 0;// if not commented out then infinite loop
}
return false
}
the problem with it is that if its at 9 and there is no next choice, it will not backtrack correctly.
There are a number of problems with your code, as people have observed in the comments.
This answer summarises some of them:
1) As #n.m. said, you should not be trying '0' as a valid choice in a cell. That will be the cause of some infinite looping, no doubt.
2) As you have observed, you don't know how the recursion finishes. The answer is that when you get to the last cell, and you find a value that works in it, you are supposed to return true. This is what is supposed to break the for(n) loop: that loop is saying "try each number until the call of solve to the right of this cell succeeds'. Success is measured by your routine returning true.
Since you try every number (n) in the current cell, no matter whether or not the call to the solve on its right works ... it's not going to work.
You'll know that you're more on the right track when:
You can see the place in your code where you return true when you discover that you can put a number in the last cell (9,9)
You can see how it is that you stop trying numbers (n=0..9) when the call to the right succeeds.
Given int puzzle[9][9], and your srow, scol, and sbox functions:
bool sudoku::solve(int row, int column) //to solve entire puzzle, call with parameters 0 and 0
{
int cell;
//ignore all nonzero cells (zero = empty)
while (row < 9 && puzzle[row][column] != 0)
{
column++;
if (column == 9)
{
row++;
column = 0;
}
}
if (row == 9) return true; //puzzle is already solved
//try values 1-9 inclusive. If successful, then return true
for (cell = 1; cell <= 9; cell++)
{
puzzle[row][column] = cell;
if (srow(row) &&
scol(column) &&
sbox(row-row%3, column-column%3) &&
solve(row, column)) //recursion!!
{
return true;
}
}
//if no value works, reset the cell and return false.
puzzle[row][column] = 0;
return false;
}
I am attempting to make a maze-solver using a Breadth-first search, and mark the shortest path using a character '*'
The maze is actually just a bunch of text. The maze consists of an n x n grid, consisting of "#" symbols that are walls, and periods "." representing the walkable area/paths. An 'S' denotes start, 'F' is finish. Right now, this function does not seem to be finding the solution (it thinks it has the solution even when one is impossible). I am checking the four neighbors, and if they are 'unfound' (-1) they are added to the queue to be processed.
The maze works on several mazes, but not on this one:
...###.#....
##.#...####.
...#.#.#....
#.####.####.
#F..#..#.##.
###.#....#S.
#.#.####.##.
....#.#...#.
.####.#.#.#.
........#...
What could be missing in my logic?
int mazeSolver(char *maze, int rows, int cols)
{
int start = 0;
int finish = 0;
for (int i=0;i<rows*cols;i++) {
if (maze[i] == 'S') { start=i; }
if (maze[i] == 'F') { finish=i; }
}
if (finish==0 || start==0) { return -1; }
char* bfsq;
bfsq = new char[rows*cols]; //initialize queue array
int head = 0;
int tail = 0;
bool solved = false;
char* prd;
prd = new char[rows*cols]; //initialize predecessor array
for (int i=0;i<rows*cols;i++) {
prd[i] = -1;
}
prd[start] = -2; //set the start location
bfsq[tail] = start;
tail++;
int delta[] = {-cols,-1,cols,+1}; // North, West, South, East neighbors
while(tail>head) {
int front = bfsq[head];
head++;
for (int i=0; i<4; i++) {
int neighbor = front+delta[i];
if (neighbor/cols < 0 || neighbor/cols >= rows || neighbor%cols < 0 || neighbor%cols >= cols) {
continue;
}
if (prd[neighbor] == -1 && maze[neighbor]!='#') {
prd[neighbor] = front;
bfsq[tail] = neighbor;
tail++;
if (maze[neighbor] == 'F') { solved = true; }
}
}
}
if (solved == true) {
int previous = finish;
while (previous != start) {
maze[previous] = '*';
previous = prd[previous];
}
maze[finish] = 'F';
return 1;
}
else { return 0; }
delete [] prd;
delete [] bfsq;
}
Iterating through neighbours can be significantly simplified(I know this is somewhat similar to what kobra suggests but it can be improved further). I use a moves array defining the x and y delta of the given move like so:
int moves[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
Please note that not only tis lists all the possible moves from a given cell but it also lists them in clockwise direction which is useful for some problems.
Now to traverse the array I use a std::queue<pair<int,int> > This way the current position is defined by the pair of coordinates corresponding to it. Here is how I cycle through the neighbours of a gien cell c:
pair<int,int> c;
for (int l = 0;l < 4/*size of moves*/;++l){
int ti = c.first + moves[l][0];
int tj = c.second + moves[l][1];
if (ti < 0 || ti >= n || tj < 0 || tj >= m) {
// This move goes out of the field
continue;
}
// Do something.
}
I know this code is not really related to your code, but as I am teaching this kind of problems trust me a lot of students were really thankful when I showed them this approach.
Now back to your question - you need to start from the end position and use prd array to find its parent, then find its parent's parent and so on until you reach a cell with negative parent. What you do instead considers all the visited cells and some of them are not on the shortest path from S to F.
You can break once you set solved = true this will optimize the algorithm a bit.
I personally think you always find a solution because you have no checks for falling off the field. (the if (ti < 0 || ti >= n || tj < 0 || tj >= m) bit in my code).
Hope this helps you and gives you some tips how to improve your coding.
A few comments:
You can use queue container in c++, its much more easier in use
In this task you can write something like that:
int delta[] = {-1, cols, 1 -cols};
And then you simple can iterate through all four sides, you shouldn't copy-paste the same code.
You will have problems with boundaries of your array. Because you are not checking it.
When you have founded finish you should break from cycle
And in last cycle you have an error. It will print * in all cells in which you have been (not only in the optimal way). It should look:
while (finish != start)
{
maze[finish] = '*';
finish = prd[finish];
}
maze[start] = '*';
And of course this cycle should in the last if, because you don't know at that moment have you reach end or not
PS And its better to clear memory which you have allocate in function
I'm having trouble with this C++ code. The integer num is a number that I want to check if it is prime. However this program is always returning false. It's probably something simple but I can't find anything.
for(int i=2;i<num;i++){ //primes are allowed to be divided by 1 so we start at 2
if(num % i == 0){ //can be divided by a number other than itself or 1 so we trip out
return false;
} else if(i == num){ //if we've already done checks as high as possible and not tripped out yet then report success
return true;
}
}
i == num will never occur, since your loop condition is i<num. Try:
for(int i=2;i<num;i++){ //primes are allowed to be divided by 1 so we start at 2
if(num % i == 0){ //can be divided by a number other than itself or 1 so we trip out
return false;
} else if(i == num-1){ //if we've already done checks as high as possible and not tripped out yet then report success
return true;
}
}
As pointed out below, the else condition here is redundant, and you only need to check from 2 to sqrt(num) - since the remaining factors have already been checked.
There are more improvements that can be made depending on how complex you want to make the problem. Most methods in reality use probabilistic algorithms.
You don't have to check every number, as a lot of them can easily be ruled out. For example, after checking that num is not divisible by 2, you can skip all other even numbers. That saves you half the tests.
We also definitely know that any other factor must be less than num/2 (or really sqrt(num), but that is harder to compute). That knowledge can save us another half of the tests.
So now we have:
if (num % 2 == 0)
return false;
for(int i = 3; i < num / 2; i += 2){
if(num % i == 0){ //can be divided by a number other than itself or 1 so we trip out
return false;
}
}
// arriving here we have found no factors, so it must be a prime
return true;
A small optimization for Will Ness's code, just calculate the sqrt of the number outside the for. The condition check executes many times and has no sense to calculate sqrt each time.
if( num == 2 ) return true;
if( num < 2 || num % 2 == 0 ) return false;
int sqrt = sqrt(num);
for( int i=3; i<=sqrt; i+=2 ){
if(num % i == 0){
return false;
}
}
return true;
So far I think that this is the most efficient way!
bool CheckPrime(int num) {
bool yayornay = true;
for(int i = 2; i < num; i++) {
if(num % i == 0) {
yayornay = false;
break;
}
}
return yayornay;
}
bool isprime(int n)
{
if(n<2) return false;
if(n==2)return true;
for(int i=2;i<=sqrt(n);i++)
if(n%i==0) return false;
return true;
}
Here's the proper way to write what you meant:
int i=2; // move declaration out
for(/*int i=2*/;i<num;i++){
if(num % i == 0){
return false;
} // else // and the final test too
}
if(i == num){
return true;
}
But that's not efficient. You only have to check for i's not exceeding of sqrt(num). Plus, if you check num%2, there's no more need to check any other even numbers, so you can use an increment of 2. Or you can even count by 6:
if( num == 2 || num == 3 ) return true;
if( num < 2 || num % 2 == 0 || num % 3 == 0 ) return false;
for( int i=5, j=7, lim=sqrt(num); i<=lim; i+=6, j+=6 ){
if( num % i == 0 || num % j == 0 ){
return false;
}
}
return true;
(notice: this is more efficient than another answer here, which says it's an "optimization" of an initial version of this answer).