This app only creates a chess board set to the start-of-game state. It does nothing else. I'd appreciate feedback on the files that are relevant to this board setup (all shown below: board.cpp, pieces.cpp, board_view.cpp). Although the project uses SFML, I'm hoping for C++ feedback, not SFML best practices per se.
Below the files I will give a link just in case you want the two .cpp files I didn't include (main.cpp and game_loop.cpp), which don't control how the board is actually built at all. (The link also has all the header files, the pieces fonts, and the CMakeLists file... for whatever it's worth, everything will "just work" only if you have SFML installed).
board.h
#pragma once
#include <SFML/Graphics.hpp>
class board {
public:
explicit board(sf::Vector2u windowSize);
explicit board(sf::Event &event);
void render_board();
void draw_board(sf::RenderWindow &render_window) const;
private:
std::unordered_map<std::string, std::string> board_state{};
std::unordered_map<int, std::string> row_index_to_alg_notation_num{};
std::unordered_map<int, std::string> column_index_to_alg_notation_letter{};
sf::Vector2u windowSize;
sf::RenderTexture render_texture;
sf::Color white_square_color = sf::Color(238, 238, 211);
sf::Color black_square_color = sf::Color(118, 150, 86);
sf::Color window_background_color = sf::Color(169, 169, 169);
sf::Font open_sans_font;
std::unordered_map<int, std::string> alg_notation_letter_map;
std::unordered_map<int, int> alg_notation_number_map;
float x_offset = 0.0;
float y_offset = 0.0;
float square_size{};
void render_square(int i, int j);
void render_piece(int i, int j);
void render_algebraic_notation(int i, int j);
void set_open_sans_font();
void set_alg_notation_letter_map();
void set_alg_notation_number_map();
void set_initial_board_state();
void set_indices_to_alg_notation();
std::string get_algebraic_notation(int i, int j);
std::string get_piece_for_square(const std::string &);
void init_();
};
board.cpp
#include <SFML/Graphics.hpp>
#include <cmath>
#include "board.h"
#include "pieces.h"
board::board(sf::Vector2u windowSize) : windowSize(windowSize) {
init_();
}
board::board(sf::Event &event) {
windowSize = {event.size.width, event.size.height};
init_();
}
void board::render_board() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
render_square(i, j);
render_algebraic_notation(i, j);
render_piece(i, j);
}
}
}
void board::render_square(int i, int j) {
sf::RectangleShape currSquare({square_size, square_size});
currSquare.setFillColor((i + j) % 2 == 0 ? white_square_color : black_square_color);
currSquare.setPosition(x_offset + static_cast<float>(j) * square_size,
y_offset + static_cast<float>(i) * square_size);
render_texture.draw(currSquare);
render_texture.display();
}
void board::render_piece(int i, int j) {
std::string square_alg_notation = get_algebraic_notation(i, j);
std::string piece_for_square = get_piece_for_square(square_alg_notation);
if (!piece_for_square.empty()) {
pieces p;
sf::Text
sfml_text_for_piece =
p.get_positioned_sfml_text_graphic_for_piece(piece_for_square, square_size, x_offset, y_offset, i, j);
render_texture.draw(sfml_text_for_piece);
render_texture.display();
}
}
void board::render_algebraic_notation(int i, int j) {
if (i == 7) {
sf::Text text(alg_notation_letter_map.at(j), open_sans_font, std::floor(square_size / 5.8f));
auto letter_color = j % 2 == 0 ? white_square_color : black_square_color;
text.setFillColor(letter_color);
text.setPosition(square_size / 1.2f + x_offset + static_cast<float>(j) * square_size,
square_size / 1.3f + y_offset + static_cast<float>(i) * square_size);
render_texture.draw(text);
render_texture.display();
}
if (j == 0) {
sf::Text text(std::to_string(alg_notation_number_map.at(i)), open_sans_font, std::floor(square_size / 5.8f));
auto letter_color = i % 2 == 1 ? sf::Color(254, 232, 209) : sf::Color(83, 120, 99);
text.setFillColor(letter_color);
text.setPosition(square_size / 18.f + x_offset + static_cast<float>(j) * square_size,
square_size / 25.f + y_offset + static_cast<float>(i) * square_size);
render_texture.draw(text);
render_texture.display();
}
}
void board::draw_board(sf::RenderWindow &render_window) const {
render_window.draw(sf::Sprite(render_texture.getTexture()));
}
std::string board::get_algebraic_notation(int i, int j) {
return column_index_to_alg_notation_letter.at(j) + row_index_to_alg_notation_num.at(i);
}
/**
* get_piece_for_square Takes the algebraic notation for a square and returns the piece belonging on that square.
* @param sqr_alg_notation Algebraic notation for the square of interest.
* @return Piece belonging on the square provided as input.
*/
std::string board::get_piece_for_square(const std::string &sqr_alg_notation) {
return board_state.at(sqr_alg_notation);
};
void board::init_() {
x_offset = 0;
square_size = static_cast<float>(windowSize.y) / 8.f;
render_texture.create(windowSize.x, windowSize.y);
set_open_sans_font();
set_alg_notation_letter_map();
set_alg_notation_number_map();
set_initial_board_state();
set_indices_to_alg_notation();
}
/**
* Methods called by `init_()` appear below
*/
void board::set_open_sans_font() {
if (!open_sans_font.loadFromFile("font/OpenSans-ExtraBold.ttf")) {
// error...
}
}
void board::set_alg_notation_letter_map() {
alg_notation_letter_map = {{0, "a"}, {1, "b"}, {2, "c"}, {3, "d"}, {4, "e"}, {5, "f"}, {6, "g"}, {7, "h"}};
}
void board::set_alg_notation_number_map() {
alg_notation_number_map = {{0, 8}, {1, 7}, {2, 6}, {3, 5}, {4, 4}, {5, 3}, {6, 2}, {7, 1}};
}
void board::set_initial_board_state() {
board_state = {
{"a1", "white_rook"},
{"b1", "white_knight"},
{"c1", "white_bishop"},
{"d1", "white_queen"},
{"e1", "white_king"},
{"f1", "white_bishop"},
{"g1", "white_knight"},
{"h1", "white_rook"},
{"a2", "white_pawn"},
{"b2", "white_pawn"},
{"c2", "white_pawn"},
{"d2", "white_pawn"},
{"e2", "white_pawn"},
{"f2", "white_pawn"},
{"g2", "white_pawn"},
{"h2", "white_pawn"},
{"a3", ""},
{"b3", ""},
{"c3", ""},
{"d3", ""},
{"e3", ""},
{"f3", ""},
{"g3", ""},
{"h3", ""},
{"a4", ""},
{"b4", ""},
{"c4", ""},
{"d4", ""},
{"e4", ""},
{"f4", ""},
{"g4", ""},
{"h4", ""},
{"a5", ""},
{"b5", ""},
{"c5", ""},
{"d5", ""},
{"e5", ""},
{"f5", ""},
{"g5", ""},
{"h5", ""},
{"a6", ""},
{"b6", ""},
{"c6", ""},
{"d6", ""},
{"e6", ""},
{"f6", ""},
{"g6", ""},
{"h6", ""},
{"a7", "black_pawn"},
{"b7", "black_pawn"},
{"c7", "black_pawn"},
{"d7", "black_pawn"},
{"e7", "black_pawn"},
{"f7", "black_pawn"},
{"g7", "black_pawn"},
{"h7", "black_pawn"},
{"a8", "black_rook"},
{"b8", "black_knight"},
{"c8", "black_bishop"},
{"d8", "black_queen"},
{"e8", "black_king"},
{"f8", "black_bishop"},
{"g8", "black_knight"},
{"h8", "black_rook"}
};
}
void board::set_indices_to_alg_notation() {
row_index_to_alg_notation_num = {
{0, "8"},
{1, "7"},
{2, "6"},
{3, "5"},
{4, "4"},
{5, "3"},
{6, "2"},
{7, "1"}
};
column_index_to_alg_notation_letter = {
{0, "a"},
{1, "b"},
{2, "c"},
{3, "d"},
{4, "e"},
{5, "f"},
{6, "g"},
{7, "h"}
};
}
pieces.h
#pragma once
#include "../include/game_loop.h"
#include <iostream>
#include <codecvt>
class pieces {
public:
pieces();
sf::Color white_piece_color = sf::Color(248, 248, 248);
sf::Color black_piece_color = sf::Color(86, 83, 82);
char32_t king{};
char32_t queen{};
char32_t rook{};
char32_t bishop{};
char32_t knight{};
char32_t pawn{};
sf::Text get_positioned_sfml_text_graphic_for_piece(const std::string &piece_for_square,
float square_size,
float x_offset,
float y_offset,
int i,
int j);
private:
sf::Font free_sarif_font;
char32_t get_char32_piece_code(const std::string &piece_name) const;
void set_free_sarif_font();
void init_();
sf::Color get_piece_color(const std::string &piece_for_square) const;
static std::string get_piece_name(const std::string &piece_for_square);
};
pieces.cpp
#include <SFML/Graphics.hpp>
#include <cmath>
#include "pieces.h"
pieces::pieces() {
init_();
}
sf::Text pieces::get_positioned_sfml_text_graphic_for_piece(const std::string &piece_for_square,
float square_size,
float x_offset,
float y_offset,
int i,
int j) {
sf::Text text(get_char32_piece_code(get_piece_name(piece_for_square)), free_sarif_font, std::floor(square_size));
text.setFillColor(get_piece_color(piece_for_square));
text.setOutlineColor(sf::Color(0, 0, 0));
text.setOutlineThickness(1);
text.setPosition(square_size / 8.f + x_offset + static_cast<float>(j) * square_size,
-square_size / 8.f + y_offset + static_cast<float>(i) * square_size);
return text;
}
std::string pieces::get_piece_name(const std::string &piece_for_square) {
size_t index_of_first_piece_letter = piece_for_square.find('_') + 1;
std::string piece_name = piece_for_square.substr(index_of_first_piece_letter, piece_for_square.size());
return piece_name;
}
sf::Color pieces::get_piece_color(const std::string &piece_for_square) const {
sf::Color piece_color;
if (piece_for_square.find("white") != std::string::npos) {
piece_color = white_piece_color;
} else {
piece_color = black_piece_color;
};
return piece_color;
}
char32_t pieces::get_char32_piece_code(const std::string &piece_name) const {
if (piece_name == "king")
return king;
if (piece_name == "queen")
return queen;
if (piece_name == "rook")
return rook;
if (piece_name == "bishop")
return bishop;
if (piece_name == "knight")
return knight;
if (piece_name == "pawn")
return pawn;
}
void pieces::init_() {
set_free_sarif_font();
king = std::stoul("265A", nullptr, 16);
queen = std::stoul("265B", nullptr, 16);
rook = std::stoul("265C", nullptr, 16);
bishop = std::stoul("265D", nullptr, 16);
knight = std::stoul("265E", nullptr, 16);
pawn = std::stoul("265F", nullptr, 16);
}
/**
* Methods called by `init_()` appear below
*/
void pieces::set_free_sarif_font() {
if (!free_sarif_font.loadFromFile("font/FreeSerif-4aeK.ttf")) {
// error...
};
}
board_view.h
#pragma once
#include <SFML/Graphics.hpp>
class board_view {
public:
board_view(const sf::Event &event, sf::RenderWindow &render_window);
void configure_and_set_view();
private:
const sf::Event &event;
sf::RenderWindow &render_window;
sf::View view;
};
board_view.cpp
#include "board_view.h"
board_view::board_view(const sf::Event &event, sf::RenderWindow &render_window)
: event(event), render_window(render_window) {}
void board_view::configure_and_set_view() {
auto w = static_cast<float>(event.size.width);
auto h = static_cast<float>(event.size.height);
view.setSize({w, h});
view.setCenter({
w / 2.f, h / 2.f});
render_window.setView(view);
}
#include <unordered_map>
to get it to compile for me. pieces.cpp is missing the include for string as well. \$\endgroup\$#include <SFML/Graphics.hpp>
(which apparently gave me the includes you mentioned) before I got around to adding my own includes... and then I forgot to come back to adding includes. Is this common? \$\endgroup\$