Skip to content

Commit

Permalink
Added solution to the Kattis "Mate in One" problem. Added "Developmen…
Browse files Browse the repository at this point in the history
…t" folder in which the projects and files used to develop

each solution will be placed along with any tests.
  • Loading branch information
William Weston authored and William Weston committed Oct 5, 2023
1 parent 19f0880 commit 0220759
Show file tree
Hide file tree
Showing 12 changed files with 1,928 additions and 0 deletions.
52 changes: 52 additions & 0 deletions Development/Mate In One Move/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#cmake

CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

#C++

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app
# name of executable if no extention

build/

3 changes: 3 additions & 0 deletions Development/Mate In One Move/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}
94 changes: 94 additions & 0 deletions Development/Mate In One Move/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
cmake_minimum_required( VERSION 3.26 )

project( Mate_In_One_Move )

set( MAIN_PROGRAM MIOM )

# Set compiler flags
set( CMAKE_CXX_STANDARD 20 )
set( CMAKE_CXX_EXTENSIONS OFF )

# use mold linker
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=mold")
set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=mold")
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=mold")

set(SOURCE
src/Solver.cpp
main.cpp
)


add_executable( ${MAIN_PROGRAM} ${SOURCE} )

target_compile_options( ${MAIN_PROGRAM}
PRIVATE
-Wall
-Werror
-Wextra
-pedantic
-pedantic-errors
)

target_include_directories( ${MAIN_PROGRAM} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
target_include_directories( ${MAIN_PROGRAM} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" )


set( TEST_SUITE MIOM_Tests_Suite )

include(CTest)
enable_testing()

find_package( GTest REQUIRED )

set( TEST_SOURCE
src/Solver.cpp
tests/mate_in_one_move.t.cpp
)

add_executable( ${TEST_SUITE} ${TEST_SOURCE} )

target_compile_options( ${TEST_SUITE}
PRIVATE
-Wall
-Wextra
-pedantic
-pedantic-errors
-pg
-ftest-coverage
-fsanitize=address
-fsanitize=undefined
-fsanitize=shift
-fsanitize=shift-exponent
-fsanitize=shift-base
-fsanitize=integer-divide-by-zero
-fsanitize=vla-bound
-fsanitize=null
-fsanitize=return
-fsanitize=signed-integer-overflow
-fsanitize=bounds
-fsanitize=bounds-strict
-fsanitize=alignment
-fsanitize=object-size
-fsanitize=float-divide-by-zero
-fsanitize=float-cast-overflow
-fsanitize=enum
-fsanitize=pointer-overflow
-fsanitize-address-use-after-scope
-fstack-protector-all
)

target_link_options(${TEST_SUITE}
PRIVATE
-fsanitize=undefined
-fsanitize=address
)

target_link_libraries( ${TEST_SUITE} GTest::gtest_main )
target_link_libraries( ${TEST_SUITE} GTest::gmock_main)

target_include_directories( ${TEST_SUITE} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
target_include_directories( ${TEST_SUITE} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" )

include( GoogleTest )
gtest_discover_tests( ${TEST_SUITE} )
Binary file not shown.
Binary file not shown.
91 changes: 91 additions & 0 deletions Development/Mate In One Move/include/Solver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* @file Solver.h
* @author William Weston
* @brief Class to solve "Mate in One" Problem
* @version 0.1
* @date 2023-06-09
*
* @copyright Copyright (c) 2023
*
*/
#ifndef WJTW_SOLVER_H_2023_06_09_INCLUDE
#define WJTW_SOLVER_H_2023_06_09_INCLUDE

#include <iosfwd>
#include <string>
#include <utility>
#include <vector>

using Board = std::vector<std::string>; // [row][col]
using Cell = std::pair<int, int>; // row by col
using Direction = std::pair<int, int>;
using Directions = std::vector<Direction>;

struct Move
{
using Cell = std::pair<int, int>; // row by col

Cell from = { -1, -1 }; // returing a default constructed move indicates no "mate in one move" could be found
Cell to = { -1, -1 };
};

auto operator<<( std::ostream&, Move const& ) -> std::ostream&;
constexpr auto operator==( Move const& lhs, Move const& rhs ) noexcept -> bool;
auto output_format( Move const& move ) -> std::string;

class Solver final
{
public:
auto load_board( std::istream& in ) -> bool;
auto solve() -> Move;
auto print_board() const -> void;

private:
using Board = std::vector<std::string>; // [row][col]

Board board_ = {};

auto find_solution( std::vector<Move> const& white_moves ) -> Move;
auto is_checkmate( Move const& white ) -> bool;
};


constexpr auto Empty = '.';
constexpr auto Unlimited = 16; // max distance a piece can travel

auto const Cross = Directions{ { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
auto const Diagonal = Directions{ { 1, 1 }, { -1, 1 }, { 1, -1 }, { -1, -1 } };
auto const Knight = Directions{ { 1, 2 }, { 1, -2 }, { 2, 1 }, { 2, -1 }, { -1, 2 }, { -1, -2 }, { -2, 1 }, { -2, -1 } };
auto const All_Moves = Directions{ { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 }, { -1, -1 } };


enum class Side
{
white,
black,
};

auto generate_moves( Side side, Board const& board ) -> std::vector<Move>;
auto generate_moves( Cell const& cell, Board const& board ) -> std::vector<Move>;
auto pawn_moves( Cell const& cell, Board const& board ) -> std::vector<Move>;
auto move_generator( Cell const&, Board const&, Directions const&, int ) -> std::vector<Move>;
auto do_move( Move const& move, Board const& board ) -> Board;
auto do_castling_move( Move const& move, Board const& board ) -> Board;

auto can_escape( Move const& black, Board const& board ) -> bool;
constexpr auto is_white( unsigned char ch ) noexcept -> bool;
constexpr auto is_castled( Cell cell, char piece ) noexcept -> bool;
constexpr auto is_pawn( char piece ) noexcept -> bool;
constexpr auto is_knight_move( Move const& move ) noexcept -> bool;
constexpr auto is_king_taken( Move const&, Board const&, Side ) -> bool;
constexpr auto is_valid( Move const& move, Board const& board ) noexcept -> bool;

auto is_in_check( Side side, Board const& board ) -> bool;
auto print_board( Board const& board ) -> void;

// -------------------------------------------------------------------------------------------------------------------


#include "Solver.inl"

#endif
112 changes: 112 additions & 0 deletions Development/Mate In One Move/include/Solver.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* @file Solver.inl
* @author William Weston
* @brief Inline functions from Solver.h
* @version 0.1
* @date 2023-06-12
*
* @copyright Copyright (c) 2023
*
*/

#ifndef WJTW_SOLVER_INL_2023_06_12_INCLUDE
#define WJTW_SOLVER_INL_2023_06_12_INCLUDE

#include <cctype> // isupper
#include <stdexcept>

constexpr auto
operator==( Move const& lhs, Move const& rhs ) noexcept -> bool
{
return lhs.from.first == rhs.from.first && lhs.from.second == rhs.from.second &&
lhs.to.first == rhs.to.first && lhs.to.second == rhs.to.second;
}


constexpr auto
is_white( unsigned char ch ) noexcept -> bool
{
return std::isupper( ch );
}

constexpr auto
is_pawn( char piece ) noexcept -> bool
{
return ( piece == 'p' || piece =='P' );
}

constexpr auto
is_castled( Cell cell, char piece ) noexcept -> bool
{
if ( !is_pawn( piece ) ) // only pawns can be castled
return false;

[[maybe_unused]] auto const& [row, dummy] = cell;
auto const isWhite = is_white( piece );

return ( ( isWhite && row == 0 ) || ( !isWhite && row == 7 ) );
}


constexpr auto
is_knight_move( Move const& move ) noexcept -> bool
{
auto const& [from_row, from_col] = move.from;
auto const& [to_row, to_col] = move.to;

for ( auto const& direction : Knight )
{
auto const& [row_dir, col_dir] = direction;
auto const dest_row = from_row + row_dir;
auto const dest_col = from_col + col_dir;

return ( ( dest_row == to_row ) && ( dest_col == to_col ) );
}

return false;
}

/**
* @brief
*
* @param move
* @param board
* @param side the side ( black/white ) whose piece the Move represents
* @return true
* @return false
*/
constexpr auto
is_king_taken( Move const& move, Board const& board, Side side ) -> bool
{
auto const& [to_row, to_col] = move.to;
auto const& dest_piece = board[to_row][to_col];

switch ( side )
{
case Side::white:
return ( dest_piece == 'k' );
case Side::black:
return ( dest_piece == 'K' );
default:
throw std::runtime_error( "Error: Unknown Side" );
}
}

constexpr auto
is_valid( Move const& move, Board const& board ) noexcept -> bool
{
auto const& [from_row, from_col] = move.from;
auto const& [to_row, to_col] = move.to;

// out of bounds
if ( to_row < 0 || to_row > 7 || to_col < 0 || to_col > 7 )
return false;

auto const& piece = board[from_row][from_col];
auto const& destination_piece = board[to_row][to_col];

return ( ( destination_piece == Empty ) || // empty square
( is_white( piece ) != is_white( destination_piece ) ) ); // the two pieces are not of the same side
}

#endif // WJTW_SOLVER_INL_2023_06_12_INCLUDE
Loading

0 comments on commit 0220759

Please sign in to comment.