I have a ball(a simple circle) in my view port and I want to know if the ball is colliding to the sides of view port or not?
how can I do that?
I've tried to limit it with some values, but it makes it special and the circle should start from a certain place. I want to have it even if it starts from random coordinates.
This is what I have now:
if(vertices[i].first < 1.80f && vertices[i].second <0.9f && left == true
&& !up && !right && !down && !exception){
c = 'u';
}
else if (vertices[i].first < 1.80f && up==true && !right && !down &&
!left && !exception) {
c = 'r';
}
else if (vertices[i].first > -1.80f && vertices[i].second > -0.9f &&
right == true && !up && !down && !left && !exception){
c = 'd';
}
else if (vertices[i].first > -1.80f && down == true && !up && !right
&& !left && !exception) {
c = 'l';
}
Related
These change the array that I print to the screen. direc is an input before this. However, when array[1][2] == '#', it still moves '#' to array[1][0].
if (array[1][1] == '#' && direc == 'A' || direc == 'a' ) {
array[1][1] = '_';
array[1][0] = '#';
}
else {
if (array[1][1] == '#' && direc == 'D' || direc == 'd' ) {
array[1][1] = '_';
array[1][2] = '#';
}
else {
if (array[1][2] == '#' && direc == 'A' || direc == 'a' ) {
array[1][1] = '#';
array[1][2] = '_';
}
}
}
You can either add parentheses, as already noted in the comments, like this
if (array[1][1] == '#' && (direc == 'A' || direc == 'a' )) {
Alternatively you could use std::tolower in which case you no longer nee
if (array[1][1] == '#' && std::tolower(direc) == 'a') {
You could still add extra parentheses if you are not comfortable that operator && is lower precedence than operator ==
(the full table of operator precedences can be seen here)
NOTE: Please comment if you think this post looks to you not having adequate details e.g. codes, results and other stuff; I will edit the post accordingly.
NOTE 2: I wrote this program by hand myself.
I have a negamax implementation the result of which looked very wrong to me i have tried many ways of debugging it but I still can't seem to get the crux of it.
First of all this is a negamax implementation for Tic Tac Toe, which has board of 3X3.
following codes are the full set in order to replicate the error I had wit this algorithm. please comment below if I missed anything.
An Example could be doing this main:
int main {
Board board;
board.startGameNage(0,0);
}
I would expect the game ended in a draw because this is computer (perfect player) vs computer (perfect player), however,Using the following set of functions I got a game ending like below:
current max move is: 0,0, current score is: -inf
current max move is: 0,2, current score is: 3
current max move is: 0,1, current score is: -3
current max move is: 1,1, current score is: 3
current max move is: 2,0, current score is: -3
current max move is: 1,2, current score is: 3
current max move is: 2,1, current score is: -3
current max move is: 1,0, current score is: 3
current max move is: 1,0, current score is: -3
X X O
X O O
X X ---
the " - " there means no move is made in that cell, which looked obviously wrong.
I implemented my minimax first and this negamax was in a way evolving based on my minimax implementation, which might be the reason that I can't see my error.
I got that minimax makes moves from 2 player's perspective and evaluate scores the same as well, whereas negamax make moves from 2 player's perspective but evaluate score only from current player's perspective.
I guess this is the bit that confused me. I can't seem to see how my implementation went wrong here.
I start my game by the following function in main:
// in main I will just give the following function a coordinate, e.g. (0,0)
void Board::startGameNega(const int & row, const int & col){
Move move(row, col);
int player = 1;
for (int depth = 0; depth < 9; depth++){
applyMoveNega(move, player);
Move current_move = move;
move = negaMax(depth, player, move);
player = -player;
cout << "current Max move is: " << current_move.getRow()
<< " , "
<< current_move.getCol()
<< ", Current score is: "
<< current_move.getScore() << endl;
}
print(); // print the end of game board
}
here is the board.hpp:
#define LENGTH 3
#define WIDTH 3
#define CROSS 1
#define NOUGHT -1
#include <iostream>
#include <vector>
#include <array>
#include <map>
#include "Move.hpp"
using namespace std;
#pragma once
typedef vector<Move> Moves;
struct Board {
// constructors;
Board(int width, int length) :m_width(width), m_length(width){};
Board(){};
// destructor;
~Board(){};
// negamax;
Move negaMax(const int & depth, const int & player, const Move & initialMove);
void startGameNega(const int & row, const int & col);
void applyMoveNega(const Move & move, const int & player);
bool isWon(const int & player);
bool isGameComplete();
int evaluateGameStateNega(const int & depth, const int & player);
// share;
int getOpponent(const int & player);
void deleteMove(const Move & move);
void deleteMoves(const Move & initialMove);
// utilities;
static int defaultBoard[WIDTH][LENGTH];
int getWidth() const { return m_width; }
int getLength() const { return m_length; }
void setWidth(int width){ m_width = width; }
void setLength(int length){ m_length = length; }
void print();
int getCurrentPlayer();
private:
int m_width;
int m_length;
enum isWin{ yes, no, draw };
int result;
int m_player;
};
some key elements listed here:
print:
void Board::print(){
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < LENGTH; j++) {
switch (defaultBoard[i][j]) {
case CROSS:
cout << "X";
break;
case NOUGHT:
cout << "O";
break;
default:
cout << "-";
break;
}
cout << " ";
}
cout << endl;
}
}
generateMoves:
Moves Board::generateMoves(const int &rowIndex, const int &colIndex){
Moves Moves;
if (defaultBoard){
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < LENGTH; j++)
{
if (i == rowIndex && j == colIndex)
{
continue;
}
else if (defaultBoard[i][j] == 1 || defaultBoard[i][j] == 4)
{
continue;
}
else if (defaultBoard[i][j] == 0)
{
Move move(i, j);
Moves.push_back(move);
}
}
}
}
return Moves;
}
applyMovesNega:
void Board::applyMoveNega(const Move & move, const int & player){
if (player == 1){
defaultBoard[move.getRow()][move.getCol()] = CROSS;
}
else if (player == -1)
{
defaultBoard[move.getRow()][move.getCol()] = NOUGHT;
}
}
isGameComplete:
bool Board::isGameComplete(){
if (defaultBoard[0][0] == defaultBoard[0][1] && defaultBoard[0][1] == defaultBoard[0][2] && defaultBoard[0][0] != 0 ||
defaultBoard[1][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[1][2] && defaultBoard[1][0] != 0 ||
defaultBoard[2][0] == defaultBoard[2][1] && defaultBoard[2][1] == defaultBoard[2][2] && defaultBoard[2][0] != 0 ||
defaultBoard[0][0] == defaultBoard[1][0] && defaultBoard[1][0] == defaultBoard[2][0] && defaultBoard[0][0] != 0 ||
defaultBoard[0][1] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][1] && defaultBoard[0][1] != 0 ||
defaultBoard[0][2] == defaultBoard[1][2] && defaultBoard[1][2] == defaultBoard[2][2] && defaultBoard[0][2] != 0 ||
defaultBoard[0][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][2] && defaultBoard[0][0] != 0 ||
defaultBoard[2][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[0][2] && defaultBoard[2][0] != 0){
return true;
}
return false;
}
evaluate the score:
int Board::evaluateGameStateNega(const int & depth, const int & player){
int new_score;
isWon(player);
if (result == isWin::yes)
new_score = 10 - depth;
else if (result == isWin::no)
new_score = depth - 10;
else
new_score = 0;
return new_score;
}
deleteMove:
void Board::deleteMove(const Move & move){
defaultBoard[move.getRow()][move.getCol()] = 0;}
here's the move.hpp:
struct Move{
Move(){};
Move(const int & index) :m_rowIndex(index / 3),m_colIndex(index % 3){};
Move(const int & row, const int & col) :m_rowIndex(row), m_colIndex(col){};
Move(const int & row, const int & col, const int & score):m_rowIndex(row), m_colIndex(col), m_score(score){};
~Move(){};
//member functions;
int getRow() const { return m_rowIndex; };
int getCol() const { return m_colIndex; };
void setRow(const int & row){ m_rowIndex = row; };
void setCol(const int & col){ m_colIndex = col; };
void setScore(const int & score){ m_score = score; };
int getScore() const { return m_score; }
private:
int m_rowIndex;
int m_colIndex;
int m_score;
};
This is the actual NegaMax Function:
Move Board::negaMax(const int & depth, const int & curPlayer, const Move & initialMove){
int row = initialMove.getRow();
int col = initialMove.getCol();
int _depth = depth;
int _curplayer = curPlayer;
Moves moves = generateMoves(row, col);
Move bestMove;
Move proposedNextMove;
//change to isGameComplete as of 15/10;
if (_depth == 8 || isGameComplete())
{
int score = evaluateGameStateNega(_depth, _curplayer);
bestMove.setScore(score);
bestMove.setRow(initialMove.getRow());
bestMove.setCol(initialMove.getCol());
}
else{
_depth += 1;
int bestScore = -1000;
for (auto move : moves){
applyMoveNega(move, -_curplayer);
proposedNextMove = negaMax(_depth, -_curplayer, move);
int tScore = -proposedNextMove.getScore();
proposedNextMove.setScore(tScore);
if (proposedNextMove.getScore() > bestScore){
bestScore = proposedNextMove.getScore();
bestMove.setScore(bestScore);
bestMove.setRow(move.getRow());
bestMove.setCol(move.getCol());
}
deleteMove(move);
}
}
return bestMove;
}
I evaluate the game state using following Function:
bool Board::isWon(const int & player){
if (defaultBoard[0][0] == defaultBoard[0][1] && defaultBoard[0][1] == defaultBoard[0][2] && defaultBoard[0][0] == player ||
defaultBoard[1][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[1][2] && defaultBoard[1][0] == player ||
defaultBoard[2][0] == defaultBoard[2][1] && defaultBoard[2][1] == defaultBoard[2][2] && defaultBoard[2][0] == player ||
defaultBoard[0][0] == defaultBoard[1][0] && defaultBoard[1][0] == defaultBoard[2][0] && defaultBoard[0][0] == player ||
defaultBoard[0][1] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][1] && defaultBoard[0][1] == player ||
defaultBoard[0][2] == defaultBoard[1][2] && defaultBoard[1][2] == defaultBoard[2][2] && defaultBoard[0][2] == player ||
defaultBoard[0][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][2] && defaultBoard[0][0] == player ||
defaultBoard[2][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[0][2] && defaultBoard[2][0] == player){
result = isWin::yes;
return true;
}
else if (defaultBoard[0][0] == defaultBoard[0][1] && defaultBoard[0][1] == defaultBoard[0][2] && defaultBoard[0][0] == -player ||
defaultBoard[1][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[1][2] && defaultBoard[1][0] == -player ||
defaultBoard[2][0] == defaultBoard[2][1] && defaultBoard[2][1] == defaultBoard[2][2] && defaultBoard[2][0] == -player ||
defaultBoard[0][0] == defaultBoard[1][0] && defaultBoard[1][0] == defaultBoard[2][0] && defaultBoard[0][0] == -player ||
defaultBoard[0][1] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][1] && defaultBoard[0][1] == -player ||
defaultBoard[0][2] == defaultBoard[1][2] && defaultBoard[1][2] == defaultBoard[2][2] && defaultBoard[0][2] == -player ||
defaultBoard[0][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][2] && defaultBoard[0][0] == -player ||
defaultBoard[2][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[0][2] && defaultBoard[2][0] == -player)
{
result = isWin::no;
return true;
}
result = isWin::draw;
return false;
}
thanks #PaulMckenzie for pointing out some of my code issues.
But they were nothing to do with errors I made on core logic of Negamax.
One by one, i will list them all out here and hope it could also help others who want to learn Negamax as well. if I miss anything just comment, I will edit afterwards.
*
DO remember to initialise all your new fields to a value, don't leave
them for the logic to decide what is the initial value. this helps in
debugging and it is just a good code practice. Thanks to #PaulMcKenzie
*
Issue 1: deleteMoveNega() && applyMoveNega()
all they do is deleting a proposed move/applying a proposed move; they don't give back/pass on the turn to current player. Because the move is proposed as the best move for the opponent of current player, once we finish calculating the score for this proposed move (A) and we want to test the next proposed move(B), we will need to delete A and give the turn back to current player. (or, to some people it's better understood as previous player.) the same applies when we apply a proposed move.
it should therefore be:
void Board::deleteMoveNega(const Move & move){
defaultBoard[move.getRow()][move.getCol()] = EMPTY;
m_player = getOpponent(m_player); // give turn back to current player;
}
void Board::applyMoveNega(const Move & move){
defaultBoard[move.getRow()][move.getCol()] = m_player;
m_player = getOpponent(m_player); // pass on the turn to current player;
}
this is the most important error I made because with the old codes I would just propose move and calculate scores as whoever started the game all the way through; because I manually set the player to the opponent in startGameNage(), I then played the game as opponent proposing moves and calculating scores only as the opponent all the way through (whereas I should really be switching context and be in two players' positions). And this happened in each iteration of the negamax function. this didn't enforce the concept of thinking as current player because when I am supposed to play as current player, I however played as opponent.
This is fundamentally wrong in negamax.
Once we fix this, we then don't need to manually set the turn in startGameNage() therefore:
player = -player;
should be deleted and:
int player = 1;
will be changed to:
m_player = 1;
Issue 2: negaMax()
with deleteMove() and applyMove() sorted out, we can now have a look at our negamax engine.
applyMoveNega(move, -_curplayer);
proposedNextMove = negaMax(_depth, -_curplayer, move);
First, I don't need the current player parameter. I have private m_player
which I can make use of.
Second, and more importantly, with old deleteMove() and applyMove() and setting turn manually in startGameNega(), this negation for player here (-_curplayer) is just so wrong.
for example, we apply/make a move for -_curplayer; the proposed move happens next should be for the opponent, which in our case, should be _curplayer. i am still passing -_curplayer, this will then generate moves for the wrong player right from the very beginning.
a new core negamax would be like:
Move Board::negaMax(const int & depth, const Move & initialMove){
int row = initialMove.getRow();
int col = initialMove.getCol();
int _depth = depth;
Move bestMove;
Move proposedNextMove;
//change to isGameComplete as of 15/10;
if (_depth == 8 || isGameComplete())
{
int score = evaluateGameStateNega(_depth);
bestMove.setScore(score);
bestMove.setRow(initialMove.getRow());
bestMove.setCol(initialMove.getCol());
}
else{
Moves moves = generateMoves(row, col);
_depth += 1;
int bestScore = -1000;
for (auto move : moves){
applyMoveNega(move);
proposedNextMove = negaMax(_depth, move);
int tScore = -proposedNextMove.getScore();
proposedNextMove.setScore(tScore);
if (proposedNextMove.getScore() > bestScore){
bestScore = proposedNextMove.getScore();
bestMove.setScore(bestScore);
bestMove.setRow(move.getRow());
bestMove.setCol(move.getCol());
}
deleteMoveNega(move);
}
}
return bestMove;
}
Issue 3: clean up a bit
Yes I just have to admit this piece of algorithm was horribly written only to rush out the logic in my head and only to be prone to errors later. As we progress, we should all be diligent enough to prevent this. However sometimes we still need to get the logic going first :)
I will post clean-ups just to make it work, but not all the clean-ups which are to make it perfect. happy to accept comment.
isWon()
bool Board::isWon(const int & currentPlayer){
if (defaultBoard[0][0] == defaultBoard[0][1] && defaultBoard[0][1] == defaultBoard[0][2] && defaultBoard[0][0] == currentPlayer ||
defaultBoard[1][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[1][2] && defaultBoard[1][0] == currentPlayer ||
defaultBoard[2][0] == defaultBoard[2][1] && defaultBoard[2][1] == defaultBoard[2][2] && defaultBoard[2][0] == currentPlayer ||
defaultBoard[0][0] == defaultBoard[1][0] && defaultBoard[1][0] == defaultBoard[2][0] && defaultBoard[0][0] == currentPlayer ||
defaultBoard[0][1] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][1] && defaultBoard[0][1] == currentPlayer ||
defaultBoard[0][2] == defaultBoard[1][2] && defaultBoard[1][2] == defaultBoard[2][2] && defaultBoard[0][2] == currentPlayer ||
defaultBoard[0][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[2][2] && defaultBoard[0][0] == currentPlayer ||
defaultBoard[2][0] == defaultBoard[1][1] && defaultBoard[1][1] == defaultBoard[0][2] && defaultBoard[2][0] == currentPlayer){
return true;
}
return false;
}
now I realised I didn't have to check for both players; that was wrong, I shall only be checking for current player; and the code is cleaner to read with only one if statement. the result was completely unnecessary. delete them. I was just confusing myself by complicating matters.
evaluateGameStateNega()
following the change in isWon() we would accordingly change the implementation of evaluateGameStateNega() as well:
int Board::evaluateGameStateNega(const int & depth){
if (isWon(m_player))
return 10 - depth;
if (isWon(getOpponent(m_player)))
return depth - 10;
else
return 0;
}
generateMoves()
Above changes suffice to make it work with all other parts being untouched. this one therefore, is to add value.
Moves Board::generateMoves(const int &rowIndex, const int &colIndex){
Moves Moves;
if (defaultBoard){
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < LENGTH; j++)
{
if (defaultBoard[i][j] == 0)
{
Move move(i, j);
Moves.push_back(move);
}
}
}
}
return Moves;
}
obviously I wrote redundant codes. we don't need to check if the cell was occupied or not; we just need to generate moves for all empty cells!
We are trying to check a scenario before displaying a pop-up message. The code below works great from Visual Studio but not from Azure after being published. Both are pointing to the same Azure SQL database.
PTO objPTOExist = db.PTOes.Where(p =>
(p.UserId == model.UserId && p.StartDate <= model.StartDate && model.StartDate <= p.EndDate && p.PTOId != model.PTOId)
|| (p.UserId == model.UserId && p.StartDate <= model.EndDate && model.EndDate <= p.EndDate && p.PTOId != model.PTOId)
|| (p.UserId == model.UserId && model.StartDate <= p.StartDate && p.StartDate <= model.EndDate && p.PTOId != model.PTOId)
|| (p.UserId == model.UserId && model.StartDate <= p.EndDate && p.EndDate <= model.EndDate && p.PTOId != model.PTOId)
|| (p.Name == "Holiday" && p.StartDate <= model.StartDate && model.StartDate <= p.EndDate && p.PTOId != model.PTOId)
|| (p.Name == "Holiday" && p.StartDate <= model.EndDate && model.EndDate <= p.EndDate && p.PTOId != model.PTOId)
|| (p.Name == "Holiday" && model.StartDate <= p.StartDate && p.StartDate <= model.EndDate && p.PTOId != model.PTOId)
|| (p.Name == "Holiday" && model.StartDate <= p.EndDate && p.EndDate <= model.EndDate && p.PTOId != model.PTOId)
).FirstOrDefault();
I know I can make the code simpler but that also had bad results on Azure even though it works locally.
Thank you for any insight as to why Azure behaves differently.
I want to check whether a given char is a digit at compile time. In particular I need the implementation of the following function prototype:
template<char c>
constexpr bool IsDigit();
For clarification: I dont must use a custom implementation. If there is already a built-in way in the std, I would prefer that method.
This should work for ASCII:
constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } // ASCII only
If you need to keep your prototype:
template<char C>
constexpr bool IsDigit() { return C >= '0' && C <= '9'; } // ASCII only
For wchar_t support you could try something like:
constexpr bool IsDigit(wchar_t c)
{
return (c >= L'0' && c <= L'9') ||
(c >= L'\u0660' && c <= L'\u0669') || // Arabic-Indic
(c >= L'\u06F0' && c <= L'\u06F9') || // Extended Arabic-Indic
(c >= L'\u07C0' && c <= L'\u07C9') || // NKO
(c >= L'\u0966' && c <= L'\u096F') || // Devanagari
(c >= L'\u09E6' && c <= L'\u09EF') || // Bengali
(c >= L'\u0A66' && c <= L'\u0A6F') || // Gurmukhi
(c >= L'\u0AE6' && c <= L'\u0AEF') || // Gujarati
(c >= L'\u0B66' && c <= L'\u0B6F') || // Oriya
(c >= L'\u0BE6' && c <= L'\u0BEF') || // Tamil
(c >= L'\u0C66' && c <= L'\u0C6F') || // Telugu
(c >= L'\u0CE6' && c <= L'\u0CEF') || // Kannada
(c >= L'\u0D66' && c <= L'\u0D6F') || // Malayalam
(c >= L'\u0E50' && c <= L'\u0E59') || // Thai
(c >= L'\u0ED0' && c <= L'\u0ED9') || // Lao
(c >= L'\u0F20' && c <= L'\u0F29'); // Tibetan
// Missing check for Myanmar, Khmer, Mongolian, Limbu, New Tai Lue,
// Tai Tham Hora, Tai Tham Tham, Balinese, Sundanese, Lepcha, Ol Chiki,
// Vai, Surashtra, Kayah, Javanese, Cham, Meetei Mayek, Osmanya, Brahmi,
// Sora, Chakma, Sharada, Takri, Mathematical.
// For codes see http://www.unicode.org/ucd/
}
if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
I am checking to see if the first indice is between 'A' and 'H' and the second indice is between 1 - 8.
so the argument would = 1 if the user entered { A, 1 }
-1 if the user entered { J, 1 }
And (&&) has higher precedence than or (||), so to express what you want you need:
if ((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
Otherwise what's happening is that it does the equivalent of this:
if (location[0] <= 'H' || (location[0] >= 'A' && location[1] <= 8) || location[1] >= 1)
Which is clearly not what you intended.
You can put as many expressions in the condition as you want, but you must remember the precedence rules; I suggest always using extra parentheses for clarity.
As Jeremiah has pointed out in the comments, the condition still wouldn't be doing what you wanted -- you are asking if something is in a given range by checking if it's either less than the upper bound or greater than the lower bound (this covers all input), when you intended to check whether the input was both larger than the lower bound and smaller than the upper:
if (location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
In this case, since the operators are all &&, no extra parentheses are needed, though you can add them for extra clarity.
You need &&s not ||s. For example: 'Z' >= 'A' || 'Z' <= 'H' is true.
if(location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
While not necessary in this case, you should group your logic together with parenthesis (and if they were ||s you would have to for it to work as expected):
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= 8 && location[1] >= 1))
Add parenthesis to group the conditions:
if( (location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If location[0] was equal to 'J' (definitely NOT between 'A' and 'H'), your if-clause would be TRUE because even though location[0] <= 'H' is FALSE, location[0] >= 'A' is TRUE and you are using || (OR). The problem is that you are using || (OR) instead of && (AND). You need to use all && (AND) in the if-clause.
&& has higher precedence than ||. So, you may want to write it as
if((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If you already tried this, please tell what error you got
Sorry guys, new here. I should have posted my entire method. Thank you for explaining the precedence of the operators, but my issue was that I was comparing a char with an int. All I needed to do was put ' ' around my numbers.
void GameBoard::enterShips()
{
char location[2];
int ships = 0;
int count = 1;
while( ships < NUM_SHIPS )
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location[0];
cin >> location[1];
cout << endl;
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= '8' && location[1] >= '1'))
{
location[0] = location[0] - 64;
location[1]--;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
else
{
cout << "Wrong coordinates entered. Try again." << endl << endl;
}
}
}
As you can see in this operator precedence table, && is #13. It's higher up than ||, which is #14.
Therefore:
if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
Is equivalent to:
if(location[0] <= 'H' || (location[0] >= 'A'
&& location[1] <= 8) || location[1] >= 1)
You want:
if((location[0] <= 'H' || location[0] >= 'A') &&
(location[1] <= 8 || location[1] >= 1))
Or even better:
if(((location[0] <= 'H') || (location[0] >= 'A')) &&
((location[1] <= 8) || (location[1] >= 1)))
I always put brackets around everything except when */ and +- are concerned. Even if you memorize the table, you shouldn't assume others do.
It helps code readability and helps prevent bugs... even compiler bugs! Triple bonus. :)
EDIT: Ah, you want ALL of them to be true. Just use all &&s, then! This works:
if(((location[0] <= 'H') && (location[0] >= 'A')) &&
((location[1] <= 8) && (location[1] >= 1)))