Initial commit, some logic added
This commit is contained in:
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
Executable
+32
@@ -0,0 +1,32 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.25.1)
|
||||||
|
project(game)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(SFML
|
||||||
|
GIT_REPOSITORY https://github.com/SFML/SFML.git
|
||||||
|
GIT_TAG 3.0.x)
|
||||||
|
FetchContent_MakeAvailable(SFML)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_FLAGS "-g -Wall -Wextra -Werror -pedantic -fsanitize=address")
|
||||||
|
# set(CMAKE_CXX_FLAGS "-g -Wall -pedantic")
|
||||||
|
|
||||||
|
file(GLOB SRC source/*.cpp)
|
||||||
|
# file(GLOB THIRD thirdpart/*.hpp)
|
||||||
|
|
||||||
|
add_executable(game
|
||||||
|
${SRC}
|
||||||
|
# ${THIRD}
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
./include/
|
||||||
|
# ./thirdpart/
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(game PRIVATE
|
||||||
|
sfml-graphics
|
||||||
|
)
|
||||||
Executable
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tilePosition.h"
|
||||||
|
#include "line.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
class Field {
|
||||||
|
private:
|
||||||
|
std::mt19937 mt;
|
||||||
|
|
||||||
|
Score score = 0;
|
||||||
|
|
||||||
|
size_t FieldSize = 4;
|
||||||
|
std::vector<Line> field;
|
||||||
|
|
||||||
|
std::vector<Tile> processLine(const std::vector<Tile> &sourceLine, Score &score);
|
||||||
|
|
||||||
|
Line getRow(size_t rowIndex) const;
|
||||||
|
std::vector<Tile> getColumn(size_t columnIndex) const;
|
||||||
|
void setRow(size_t rowIndex, const std::vector<Tile> &line);
|
||||||
|
void setColumn(size_t columnIndex, const std::vector<Tile> &line);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void setSize(size_t size);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Field(size_t fieldSize);
|
||||||
|
|
||||||
|
bool canMove() const;
|
||||||
|
bool moveUp();
|
||||||
|
bool moveDown();
|
||||||
|
bool moveLeft();
|
||||||
|
bool moveRight();
|
||||||
|
|
||||||
|
std::vector<Position> getEmptyTiles() const;
|
||||||
|
bool spawnTile(const std::vector<Position> &empty);
|
||||||
|
|
||||||
|
void debug() const;
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct Line {
|
||||||
|
std::vector<Tile> line;
|
||||||
|
Score score;
|
||||||
|
|
||||||
|
explicit Line();
|
||||||
|
Line(size_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
};
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Position {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
Position() : x(0), y(0) {}
|
||||||
|
Position(int x, int y) : x(x), y(y) {}
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
using Tile = unsigned long long int;
|
||||||
|
using Score = unsigned long long int;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "field.h"
|
||||||
|
|
||||||
|
using Tile = unsigned long long int;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Field field(4);
|
||||||
|
char action;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
field.debug();
|
||||||
|
std::cin >> action;
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case 'w':
|
||||||
|
field.moveUp();
|
||||||
|
field.spawnTile();
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
field.moveDown();
|
||||||
|
field.spawnTile();
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
field.moveLeft();
|
||||||
|
field.spawnTile();
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
field.moveRight();
|
||||||
|
field.spawnTile();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Executable
+180
@@ -0,0 +1,180 @@
|
|||||||
|
#include "field.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fields:
|
||||||
|
std::vector<std::vector<int>> field;
|
||||||
|
|
||||||
|
Private methods:
|
||||||
|
std::vector<Tile> processLine(const std::vector<Tile> &sourceLine);
|
||||||
|
|
||||||
|
std::vector<Tile> getRow(size_t idx);
|
||||||
|
std::vector<Tile> getColumn(size_t idx);
|
||||||
|
void setRow(size_t idx);
|
||||||
|
void setColumn(size_t idx);
|
||||||
|
|
||||||
|
Public methods:
|
||||||
|
void moveUp();
|
||||||
|
void moveDown();
|
||||||
|
void moveLeft();
|
||||||
|
void moveRight();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PRIVATE
|
||||||
|
std::vector<Tile> Field::processLine(const std::vector<Tile>& sourceLine, Score &score) {
|
||||||
|
std::vector<Tile> result;
|
||||||
|
Tile pending = 0;
|
||||||
|
bool hasPending = false;
|
||||||
|
|
||||||
|
for (Tile element : sourceLine) {
|
||||||
|
if (element == 0) continue;
|
||||||
|
|
||||||
|
if (!hasPending) {
|
||||||
|
pending = element;
|
||||||
|
hasPending = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element == pending) {
|
||||||
|
result.push_back(pending * 2);
|
||||||
|
score += pending * 2;
|
||||||
|
hasPending = false;
|
||||||
|
pending = 0;
|
||||||
|
} else {
|
||||||
|
result.push_back(pending);
|
||||||
|
pending = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPending) {
|
||||||
|
result.push_back(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (result.size() < sourceLine.size()) {
|
||||||
|
result.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Line Field::getRow(size_t rowIndex) const {
|
||||||
|
return this->field[rowIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Tile> Field::getColumn(size_t columnIndex) const {
|
||||||
|
// from top to bottom
|
||||||
|
std::vector<Tile> column;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
column.push_back(this->field[i][columnIndex]);
|
||||||
|
}
|
||||||
|
return column;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Field::setRow(size_t rowIndex, const std::vector<Tile> &line) {
|
||||||
|
this->field[rowIndex] = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Field::setColumn(size_t columnIndex, const std::vector<Tile> &line) {
|
||||||
|
// from top to bottom (same)
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
this->field[i][columnIndex] = line[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Field::reset() {
|
||||||
|
this->field.resize(this->FieldSize, std::vector<Tile>(this->FieldSize, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUBLIC
|
||||||
|
Field::Field(size_t fieldSize) : mt(std::random_device{}()), FieldSize(fieldSize) {
|
||||||
|
this->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printVector(const std::vector<Tile> &arr) {
|
||||||
|
for (size_t i = 0; i < arr.size(); ++i) {
|
||||||
|
printf("%llu ", arr[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Field::moveUp() {
|
||||||
|
auto oldField = this->field;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
std::vector<Tile> column;
|
||||||
|
column = getColumn(i);
|
||||||
|
column = processLine(column, this->score);
|
||||||
|
setColumn(i, column);
|
||||||
|
}
|
||||||
|
return this->field != oldField;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Field::moveDown() {
|
||||||
|
auto oldField = this->field;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
std::vector<Tile> column;
|
||||||
|
column = getColumn(i);
|
||||||
|
std::reverse(column.begin(), column.end());
|
||||||
|
column = processLine(column, this->score);
|
||||||
|
std::reverse(column.begin(), column.end());
|
||||||
|
setColumn(i, column);
|
||||||
|
}
|
||||||
|
return this->field != oldField;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Field::moveLeft() {
|
||||||
|
auto oldField = this->field;
|
||||||
|
std::vector<Tile> row;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
row = getRow(i);
|
||||||
|
row = processLine(row, this->score);
|
||||||
|
setRow(i, row);
|
||||||
|
}
|
||||||
|
return this->field != oldField;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Field::moveRight() {
|
||||||
|
auto oldField = this->field;
|
||||||
|
std::vector<Tile> row;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
row = getRow(i);
|
||||||
|
std::reverse(row.begin(), row.end());
|
||||||
|
row = processLine(row, this->score);
|
||||||
|
std::reverse(row.begin(), row.end());
|
||||||
|
setRow(i, row);
|
||||||
|
}
|
||||||
|
return this->field != oldField;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Position> Field::getEmptyTiles() const {
|
||||||
|
std::vector<Position> empty;
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
for (size_t j = 0; j < this->FieldSize; ++j) {
|
||||||
|
if (this->field[i][j] == 0) {
|
||||||
|
empty.push_back(Position(i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Field::spawnTile(const std::vector<Position> &empty) {
|
||||||
|
if (!empty.empty()) {
|
||||||
|
std::uniform_int_distribution<> dist(0, static_cast<int>(empty.size() - 1));
|
||||||
|
std::uniform_int_distribution<> chance(1, 10);
|
||||||
|
int choice = dist(this->mt);
|
||||||
|
Position spawnPoint = empty[choice];
|
||||||
|
this->field[spawnPoint.x][spawnPoint.y] = ((chance(this->mt) == 10) ? 4 : 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Field::debug() const {
|
||||||
|
for (size_t i = 0; i < this->FieldSize; ++i) {
|
||||||
|
for (size_t j = 0; j < this->FieldSize; ++j) {
|
||||||
|
printf("%5llu ", this->field[i][j]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include "line.h"
|
||||||
|
|
||||||
|
Line::Line() {
|
||||||
|
this->line.clear();
|
||||||
|
this->line.reserve(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Line::Line(size_t length) {
|
||||||
|
this->line.clear();
|
||||||
|
this->line.reserve(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Line::processLine() {
|
||||||
|
std::vector<Tile> result;
|
||||||
|
Tile pending = 0;
|
||||||
|
bool hasPending = false;
|
||||||
|
|
||||||
|
for (Tile element : this->line) {
|
||||||
|
if (element == 0) continue;
|
||||||
|
|
||||||
|
if (!hasPending) {
|
||||||
|
pending = element;
|
||||||
|
hasPending = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element == pending) {
|
||||||
|
result.push_back(pending * 2);
|
||||||
|
this->score += pending * 2;
|
||||||
|
hasPending = false;
|
||||||
|
pending = 0;
|
||||||
|
} else {
|
||||||
|
result.push_back(pending);
|
||||||
|
pending = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPending) {
|
||||||
|
result.push_back(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (result.size() < sourceLine.size()) {
|
||||||
|
result.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user