LogDoctor/logdoctor/games/snake/food.cpp

237 lines
5.9 KiB
C++

#include "food.h"
#include "snake.h"
#include <QGraphicsPixmapItem>
Food::Food( const bool can_move )
: image{ new QGraphicsPixmapItem( (can_move) ? this->img_rat : this->img_egg ) }
, movable{ can_move }
, x{ 0 }
, y{ 0 }
{
}
Food::Food( Food&& other ) noexcept
: image{ other.image }
, movable{ other.movable }
, x{ other.x }
, y{ other.y }
{
other.image = nullptr;
}
Food& Food::operator=( Food&& other ) noexcept
{
if ( this == &other ) return *this;
this->x = other.x;
this->y = other.y;
this->movable = other.movable;
this->image = other.image;
other.image = nullptr;
return *this;
}
unsigned Food::X() const noexcept
{
return this->x;
}
unsigned Food::Y() const noexcept
{
return this->y;
}
QGraphicsPixmapItem* Food::getImageItem() const noexcept
{
return this->image;
}
bool Food::inTile( const unsigned x, const unsigned y ) const noexcept
{
return this->x == x && this->y == y;
}
void Food::update( const unsigned new_x, const unsigned new_y ) noexcept
{
this->x = new_x;
this->y = new_y;
this->image->setOffset( 16+(new_x*32), 16+(new_y*32) );
}
void Food::spawn( const Snake& snake, const Snake& snake_ ) noexcept
{
// pick a new random position
unsigned new_x, new_y;
while (true) {
new_x = static_cast<unsigned>( rand()%16 );
new_y = static_cast<unsigned>( rand()%16 );
// check it's actually inside the field
if ( new_x < 16u && new_y < 16u ) {
// check the tile is empty
if ( new_x != this->x && new_y != this->y ) {
if ( !(snake.inTile( new_x, new_y, false ) || snake_.inTile( new_x, new_y, false )) ) {
break;
}
}
}
}
// update to new position
this->update( new_x, new_y );
// randomly rotate the image
int rand_{ rand()%4 };
switch (rand_) {
case 1:
this->image->setPixmap(
this->image->pixmap().transformed(
QTransform().rotate( 90.0 ) ) );
break;
case 2:
this->image->setPixmap(
this->image->pixmap().transformed(
QTransform().rotate( 180.0 ) ) );
break;
case 3:
this->image->setPixmap(
this->image->pixmap().transformed(
QTransform().rotate( -90.0 ) ) );
break;
default:
// do not rotate
break;
}
}
void Food::move( const Snake& snake )
{
int move_up { 0 },
move_down { 0 },
move_left { 0 },
move_right { 0 };
const unsigned
snake_x{ snake.front().x },
snake_y{ snake.front().y };
// check the field's limits
if ( this->y == 0u ) {
move_up -= 100;
} else if ( this->y == 15u ) {
move_down -= 100;
}
if ( this->x == 0u ) {
move_left -= 100;
} else if ( this->x == 15u ) {
move_right -= 100;
}
// check the snake
if ( ! snake.inTile( this->x, this->y-1u, false ) ) {
move_up += 100;
} else {
move_up -= 100;
}
if ( ! snake.inTile( this->x, this->y+1u, false ) ) {
move_down += 100;
} else {
move_down -= 100;
}
if ( ! snake.inTile( this->x-1u, this->y, false ) ) {
move_left += 100;
} else {
move_left -= 100;
}
if ( ! snake.inTile( this->x+1u, this->y, false ) ) {
move_right += 100;
} else {
move_right -= 100;
}
// check the snake position
if ( this->x == snake_x ) {
move_left += 30;
move_right += 30;
if ( this->y < snake_y ) {
move_up += 30;
} else if ( this->y > snake_y ) {
move_down += 30;
}
} else if ( this->x < snake_x ) {
move_left += 30;
if ( this->y < snake_y ) {
move_up += 30;
} else if ( this->y > snake_y ) {
move_down += 30;
} else /*if ( this->y == snake_y )*/ {
move_up += 30;
move_down += 30;
}
} else /*if ( this->x > snake_x )*/ {
move_right += 30;
if ( this->y < snake_y ) {
move_up += 30;
} else if ( this->y > snake_y ) {
move_down += 30;
} else /*if ( this->y == snake_y )*/ {
move_up += 30;
move_down += 30;
}
}
// decide
int max{ -1000 };
Direction choice;
if ( move_up > max || (move_up == max && rand()%2) ) {
max = move_up;
choice = Direction::UP;
}
if ( move_down > max || (move_down == max && rand()%2) ) {
max = move_down;
choice = Direction::DOWN;
}
if ( move_left > max || (move_left == max && rand()%2) ) {
max = move_left;
choice = Direction::LEFT;
}
if ( move_right > max || (move_right == max && rand()%2) ) {
choice = Direction::RIGHT;
}
// apply the move
switch ( choice ) {
case Direction::UP:
this->update( this->x, this->y-1u );
this->image->setPixmap(
this->img_rat );
break;
case Direction::DOWN:
this->update( this->x, this->y+1u );
this->image->setPixmap(
this->img_rat.transformed(
QTransform().rotate( 180.0 ) ) );
break;
case Direction::LEFT:
this->update( this->x-1u, this->y );
this->image->setPixmap(
this->img_rat.transformed(
QTransform().rotate( -90.0 ) ) );
break;
case Direction::RIGHT:
this->update( this->x+1u, this->y );
this->image->setPixmap(
this->img_rat.transformed(
QTransform().rotate( 90.0 ) ) );
break;
default:
// should be unreachable
throw("Unexpected choice direction: "+std::to_string(choice));
}
}