PaulRB, thank you for this advice. Actually I know that, but use only when I am not sure what value may come with a shortened condition so that to check that something came at all (I mean when several different values may come with it and I don't know which one it was) . It's rather a professional way of dealing with that. I am not a professional yet. What is more, it may end up with a mistake as well, so I prefer to be precise most of the time.
P.S. I have updated the code. Now it works properly and it's possible to choose a random field with a joystick, just in case if it still matters. You can find it below:
#include <Adafruit_NeoPixel.h>
#include <Vector.h>
#include <limits.h>
#define PIN 4
#define RGB 4
#define SIZE 16
#define SHIP 10
#define MOVE 512
#define SLEEP 0
#define SPEED 0
#define XJ1 A0
#define YJ1 A1
#define SW1 A2
Adafruit_NeoPixel pixels(SIZE * SIZE, PIN);
struct Color {
int r;
int g;
int b;
};
struct Coord {
int x;
int y;
Color c;
};
struct Deck {
int qty;
int slot;
};
bool error = false;
bool selected = false;
Coord c;
Coord storage_v[2 * SHIP] = {};
Vector<Coord> v(storage_v, 2 * SHIP);
String direction[SHIP] = {"HOR", "VER", "HOR", "VER", "HOR", "VER", "HOR", "VER", "HOR", "VER"};
Deck decks[SHIP] = {{4, 0}, {3, 0}, {3, 0}, {2, 0}, {2, 0}, {2, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}};
Color colors[RGB] = {{UCHAR_MAX, UCHAR_MAX / 2, 0}, {0, UCHAR_MAX, 0}, {UCHAR_MAX , 0, 0}, {UCHAR_MAX / 2, 0, UCHAR_MAX}};
void setup() {
Serial.begin(9600);
pixels.begin();
//Link joystick
pinMode(XJ1, INPUT);
pinMode(YJ1, INPUT);
pinMode(SW1, INPUT);
//Link joystick
pixels.setBrightness(5);
//Clear vectors initialized with zeroes
v.clear();
//Clear vectors initialized with zeroes
//Shuffle decks and colors (primarily for the random set)
ShuffleColors(decks, SHIP);
ShuffleColors(colors, RGB);
//Shuffle decks and colors (primarily for the random set)
}
//Shuffle decks and their colors (template function)
template<class T>
void ShuffleColors(T arr[], int limit) {
for (int i = 0; i < limit; i++) {
int n = random(0, limit);
auto temp = arr[n];
arr[n] = arr[i];
arr[i] = temp;
}
}
//Shuffle decks and their colors (template function)
//Clear game field (for random set only)
void ClearGameField() {
for (int i = 0; i < v.size(); i++) {
pixels.setPixelColor(XY(v[i].y, v[i].x), pixels.Color(0, 0, 0));
pixels.show();
}
}
//Clear game field (for random set only)
//Check if the ship is not beyond the grid (for random set only)
bool CheckFieldShipBoundary(int x, int y, int decks, String dir, String name) {
if ((x >= 1 && x <= SIZE) && (y >= 1 && y <= SIZE)) {
if (dir == "HOR") {
if (decks - 1 <= SIZE - y) {
return true;
}
return false;
} else if (dir == "VER") {
if (decks - 1 <= SIZE - x) {
return true;
}
return false;
}
}
return false;
}
//Check if the ship is not beyond the grid (for random set only)
//Check if the ship has got enough space around (for random set only)
bool CheckShipObstacleAround(int x, int y, int decks, String dir, String name) {
if (dir == "HOR") {
if ((y - 2 >= 0 && x - 2 >= 0 && pixels.getPixelColor(XY(y - 2, x - 2)) != 0) ||
(y - 2 >= 0 && x - 1 >= 0 && pixels.getPixelColor(XY(y - 2, x - 1)) != 0) ||
(y - 2 >= 0 && x >= 0 && x < SIZE && pixels.getPixelColor(XY(y - 2, x)) != 0)) {
return false;
}
for (int i = 0; i < decks; i++) {
int cx = x - 1;
int cy = y - 1 + i;
if ((cy >= 0 && cy < SIZE && cx - 1 >= 0 && pixels.getPixelColor(XY(cy, cx - 1)) != 0) ||
(cy >= 0 && cy < SIZE && cx + 1 < SIZE && pixels.getPixelColor(XY(cy, cx + 1)) != 0)) {
return false;
}
}
if ((y + decks - 1 >= 0 && y + decks - 1 < SIZE && x - 2 >= 0 && pixels.getPixelColor(XY(y + decks - 1, x - 2)) != 0) ||
(y + decks - 1 >= 0 && y + decks - 1 < SIZE && x - 1 >= 0 && pixels.getPixelColor(XY(y + decks - 1, x - 1)) != 0) ||
(y + decks - 1 >= 0 && y + decks - 1 < SIZE && x >= 0 && x < SIZE && pixels.getPixelColor(XY(y + decks - 1, x)) != 0)) {
return false;
}
return true;
} else if (dir == "VER") {
if ((y - 2 >= 0 && x - 2 >= 0 && pixels.getPixelColor(XY(y - 2, x - 2)) != 0) ||
(y - 1 >= 0 && x - 2 >= 0 && pixels.getPixelColor(XY(y - 1, x - 2)) != 0) ||
(y >= 0 && y < SIZE && x - 2 >= 0 && pixels.getPixelColor(XY(y, x - 2)) != 0)) {
return false;
}
for (int i = 0; i < decks; i++) {
int cx = x - 1 + i;
int cy = y - 1;
if ((cy - 1 >= 0 && cx >= 0 && cx < SIZE && pixels.getPixelColor(XY(cy - 1, cx)) != 0) ||
(cy + 1 < SIZE && cx >= 0 && cx < SIZE && pixels.getPixelColor(XY(cy + 1, cx)) != 0)) {
return false;
}
}
if ((y - 2 >= 0 && x + decks - 1 >= 0 && x + decks - 1 < SIZE && pixels.getPixelColor(XY(y - 2, x + decks - 1)) != 0) ||
(y - 1 >= 0 && x + decks - 1 >= 0 && x + decks - 1 < SIZE && pixels.getPixelColor(XY(y - 1, x + decks - 1)) != 0) ||
(y >= 0 && y < SIZE && x + decks - 1 >= 0 && x + decks - 1 < SIZE && pixels.getPixelColor(XY(y, x + decks - 1)) != 0)) {
return false;
}
return true;
}
}
//Check if the ship has got enough space around (for random set only)
//Check if one ship does not overlap another (for random set only)
void ResetShipAfterOverlap(int i, int cx, int cy, String name) {
for (int j = 0; j < v.size(); j++) {
if ((v[j].x == cx) && (v[j].y == cy)) {
Serial.println("OVERLAPPED " + name + "!");
delay(SLEEP);
int index = i;
for (int i = 0; i < index; i++) {
pixels.setPixelColor(XY(v.back().y, v.back().x), pixels.Color(0, 0, 0));
pixels.show();
v.pop_back();
}
error = true;
break;
}
}
}
//Check if one ship does not overlap another (for random set only)
//Check random ship RGB color (the same number of decks) (for random set only)
void SetShipRGBColor(int x, int y, int decks, String dir, String name) {
c.x = x;
c.y = y;
for (int i = 0; i < RGB; i++) {
if (decks == RGB - i) {
c.c.r = colors[decks-1].r;
c.c.g = colors[decks-1].g;
c.c.b = colors[decks-1].b;
}
}
v.push_back(c);
pixels.setPixelColor(XY(c.y, c.x), pixels.Color(c.c.r, c.c.g, c.c.b));
pixels.show();
}
//Check random ship RGB color (the same number of decks) (for random set only)
//Set a random ship position (for random set only)
void SetHomeShipPosition(int x, int y, int decks, String dir, String name) {
error = false;
if ((CheckFieldShipBoundary(x, y, decks, dir, name) == true) && (CheckShipObstacleAround(x, y, decks, dir, name) == true)) {
if (dir == "HOR") {
for (int i = 0; i < decks; i++) {
int cx = x - 1;
int cy = y - 1 + i;
ResetShipAfterOverlap(i, cx, cy, name);
if (error == true) {
break;
}
SetShipRGBColor(cx, cy, decks, dir, name);
}
if (error == false) {
Serial.println("OK " + name + "!");
delay(SLEEP);
}
} else if (dir == "VER") {
for (int i = 0; i < decks; i++) {
int cx = x - 1 + i;
int cy = y - 1;
ResetShipAfterOverlap(i, cx, cy, name);
if (error == true) {
break;
}
SetShipRGBColor(cx, cy, decks, dir, name);
}
if (error == false) {
Serial.println("OK " + name + "!");
delay(SLEEP);
}
}
} else {
if (CheckFieldShipBoundary(x, y, decks, dir, name) == false) {
error = true;
Serial.println("NOT ENOUGH SPACE " + name + "!");
delay(SLEEP);
} else if (CheckShipObstacleAround(x, y, decks, dir, name) == false) {
error = true;
Serial.println("TOO NEARBY " + name + "!");
delay(SLEEP);
}
}
}
//Set a random ship position (for random set only)
//Player joystick control
void PlayerJoystickControl() {
int x = analogRead(A1);
int y = analogRead(A0);
if (x == 2 * MOVE - 1 && y == MOVE) { //LEFT
GenerateRandomShipSet();
//delay(SPEED);
Serial.println("LEFT");
selected = false;
} else if (x == 0 && y == MOVE) { //RIGHT
GenerateRandomShipSet();
//delay(SPEED);
Serial.println("RIGHT");
selected = false;
} else if (y == 2 * MOVE - 1 && x == MOVE) { //DOWN
GenerateRandomShipSet();
//delay(SPEED);
Serial.println("DOWN");
selected = false;
} else if (y == 0 && x == MOVE) { //UP
GenerateRandomShipSet();
//delay(SPEED);
Serial.println("UP");
selected = false;
}
}
//Player joystick control
//Generate a random multi-colored field with ships (according to the Naval Clash game rules)
void GenerateRandomShipSet() {
if (selected == false) {
ClearGameField();
v.clear();
for (int i = 0; i < SHIP; i++) {
randomSeed(micros() + analogRead(A0) + analogRead(A1));
SetHomeShipPosition(random(1, SIZE + 1), random(1, SIZE + 1), decks[i].qty, direction[random(0, SIZE)], String(i + 1));
if (error == true) {
//if (i >= 0) {
i--;
Serial.print("INDEX => ");
Serial.println(i);
//}
}
}
ShuffleColors(decks, SHIP);
ShuffleColors(colors, RGB);
selected = true;
}
}
//Generate a random multi-colored field with ships (according to the Naval Clash game rules)
void loop() {
PlayerJoystickControl();
}
int XY(int x, int y) {
if (y % 2 == 0) {
return y * SIZE + x;
} else {
return ((y + 1) * SIZE - 1) - x;
}
}