The simply network play type Shogi implementation. This project is not for practical because it was implemented for learning.
- Boost Asio
- libshogi
- GCC 7.1.0 or later
- Ubuntu 16.04
// Copyright (C) 2017 roki | |
#ifndef INCLUDED_BOARD_MANAGER_HPP | |
#define INCLUDED_BOARD_MANAGER_HPP | |
#include<boost/utility.hpp> | |
#include<random> | |
#include<optional> | |
#include<sstream> | |
#include<Shogi.h> | |
#include<Array.h> | |
namespace board{ | |
std::string input()noexcept | |
{ | |
std::string buffer; | |
while(!std::cin.fail()){ | |
std::cout << "Your turn (value or \"r\") >> "; | |
std::cin >> buffer; | |
try{ | |
std::stoi(buffer); | |
}catch(const std::invalid_argument&){ | |
if(buffer != "r")continue; | |
} | |
break; | |
} | |
return buffer; | |
} | |
template<class RandomEngine> | |
struct shogi_board : private boost::noncopyable { | |
template<class RandomDevice,std::enable_if_t<std::is_invocable_v<std::decay_t<RandomDevice>>,std::nullptr_t> = nullptr> | |
explicit shogi_board(game::Position& sw,RandomDevice&& seed_gen) | |
:sw_(sw),engine_(seed_gen()){} | |
std::string get_board()const | |
{ | |
std::ostringstream ss; | |
ss << sw_; | |
return ss.str(); | |
} | |
std::optional<std::string> get_board(std::string choice) | |
{ | |
using namespace std::string_literals; | |
foundation::Array<game::Move::Move,game::Move::Max> move; | |
sw_.genMove(move); | |
if(move.vsize() == 0)return std::nullopt; | |
std::uniform_int_distribution<std::size_t> dist_(0,move.vsize()); | |
std::size_t c = 0; | |
if(choice == "r"){ | |
c = dist_(engine_); | |
}else if(choice == "end"){ | |
return std::nullopt; | |
}else{ | |
try{ | |
c = std::stoi(std::move(choice)); | |
}catch(const std::exception&){ | |
return std::nullopt; | |
} | |
} | |
sw_.move(move[c]); | |
return std::make_optional(get_board()); | |
} | |
private: | |
game::Position& sw_; | |
RandomEngine engine_; | |
}; | |
} // namespace board | |
#endif |
// Copyright (C) 2017 roki | |
#include"tcp_client.hpp" | |
#include"board_manager.hpp" | |
void main_loop(tcp_client& client)noexcept | |
{ | |
using namespace std::string_literals; | |
for(boost::asio::streambuf receive_buffer;; receive_buffer.consume(receive_buffer.size())){ | |
std::string buffer = board::input(); | |
client << buffer; | |
try{ | |
client >> receive_buffer; | |
}catch(const std::exception& exp){ | |
std::cout << exp.what() << std::endl; | |
break; | |
} | |
std::cout << boost::asio::buffer_cast<const char*>(receive_buffer.data()) << std::endl; | |
std::cout << "Waiting player..." << std::endl; | |
receive_buffer.consume(receive_buffer.size()); | |
try{ | |
client >> receive_buffer; | |
}catch(const std::exception& exp){ | |
std::cout << exp.what() << std::endl; | |
break; | |
} | |
std::cout << boost::asio::buffer_cast<const char*>(receive_buffer.data()) << std::endl; | |
} | |
} | |
int main(const int argc,const char* argv[]) | |
{ | |
if(argc!=3){ | |
std::cerr << "Usage: client <ip-address> <port>" << std::endl; | |
return EXIT_FAILURE; | |
} | |
using namespace std::string_literals; | |
boost::asio::io_service io_service; | |
tcp_client client(io_service); | |
client.connect(argv[1],static_cast<short unsigned int>(std::stoi(argv[2]))); | |
boost::asio::streambuf receive_buffer; | |
try{ | |
client >> receive_buffer; | |
}catch(const std::exception& exp){ | |
std::cout << exp.what() << std::endl; | |
return EXIT_FAILURE; | |
} | |
std::cout << boost::asio::buffer_cast<const char*>(receive_buffer.data()) << std::endl; | |
main_loop(client); | |
} |
GNU LESSER GENERAL PUBLIC LICENSE | |
Version 3, 29 June 2007 | |
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | |
Everyone is permitted to copy and distribute verbatim copies | |
of this license document, but changing it is not allowed. | |
This version of the GNU Lesser General Public License incorporates | |
the terms and conditions of version 3 of the GNU General Public | |
License, supplemented by the additional permissions listed below. | |
0. Additional Definitions. | |
As used herein, "this License" refers to version 3 of the GNU Lesser | |
General Public License, and the "GNU GPL" refers to version 3 of the GNU | |
General Public License. | |
"The Library" refers to a covered work governed by this License, | |
other than an Application or a Combined Work as defined below. | |
An "Application" is any work that makes use of an interface provided | |
by the Library, but which is not otherwise based on the Library. | |
Defining a subclass of a class defined by the Library is deemed a mode | |
of using an interface provided by the Library. | |
A "Combined Work" is a work produced by combining or linking an | |
Application with the Library. The particular version of the Library | |
with which the Combined Work was made is also called the "Linked | |
Version". | |
The "Minimal Corresponding Source" for a Combined Work means the | |
Corresponding Source for the Combined Work, excluding any source code | |
for portions of the Combined Work that, considered in isolation, are | |
based on the Application, and not on the Linked Version. | |
The "Corresponding Application Code" for a Combined Work means the | |
object code and/or source code for the Application, including any data | |
and utility programs needed for reproducing the Combined Work from the | |
Application, but excluding the System Libraries of the Combined Work. | |
1. Exception to Section 3 of the GNU GPL. | |
You may convey a covered work under sections 3 and 4 of this License | |
without being bound by section 3 of the GNU GPL. | |
2. Conveying Modified Versions. | |
If you modify a copy of the Library, and, in your modifications, a | |
facility refers to a function or data to be supplied by an Application | |
that uses the facility (other than as an argument passed when the | |
facility is invoked), then you may convey a copy of the modified | |
version: | |
a) under this License, provided that you make a good faith effort to | |
ensure that, in the event an Application does not supply the | |
function or data, the facility still operates, and performs | |
whatever part of its purpose remains meaningful, or | |
b) under the GNU GPL, with none of the additional permissions of | |
this License applicable to that copy. | |
3. Object Code Incorporating Material from Library Header Files. | |
The object code form of an Application may incorporate material from | |
a header file that is part of the Library. You may convey such object | |
code under terms of your choice, provided that, if the incorporated | |
material is not limited to numerical parameters, data structure | |
layouts and accessors, or small macros, inline functions and templates | |
(ten or fewer lines in length), you do both of the following: | |
a) Give prominent notice with each copy of the object code that the | |
Library is used in it and that the Library and its use are | |
covered by this License. | |
b) Accompany the object code with a copy of the GNU GPL and this license | |
document. | |
4. Combined Works. | |
You may convey a Combined Work under terms of your choice that, | |
taken together, effectively do not restrict modification of the | |
portions of the Library contained in the Combined Work and reverse | |
engineering for debugging such modifications, if you also do each of | |
the following: | |
a) Give prominent notice with each copy of the Combined Work that | |
the Library is used in it and that the Library and its use are | |
covered by this License. | |
b) Accompany the Combined Work with a copy of the GNU GPL and this license | |
document. | |
c) For a Combined Work that displays copyright notices during | |
execution, include the copyright notice for the Library among | |
these notices, as well as a reference directing the user to the | |
copies of the GNU GPL and this license document. | |
d) Do one of the following: | |
0) Convey the Minimal Corresponding Source under the terms of this | |
License, and the Corresponding Application Code in a form | |
suitable for, and under terms that permit, the user to | |
recombine or relink the Application with a modified version of | |
the Linked Version to produce a modified Combined Work, in the | |
manner specified by section 6 of the GNU GPL for conveying | |
Corresponding Source. | |
1) Use a suitable shared library mechanism for linking with the | |
Library. A suitable mechanism is one that (a) uses at run time | |
a copy of the Library already present on the user's computer | |
system, and (b) will operate properly with a modified version | |
of the Library that is interface-compatible with the Linked | |
Version. | |
e) Provide Installation Information, but only if you would otherwise | |
be required to provide such information under section 6 of the | |
GNU GPL, and only to the extent that such information is | |
necessary to install and execute a modified version of the | |
Combined Work produced by recombining or relinking the | |
Application with a modified version of the Linked Version. (If | |
you use option 4d0, the Installation Information must accompany | |
the Minimal Corresponding Source and Corresponding Application | |
Code. If you use option 4d1, you must provide the Installation | |
Information in the manner specified by section 6 of the GNU GPL | |
for conveying Corresponding Source.) | |
5. Combined Libraries. | |
You may place library facilities that are a work based on the | |
Library side by side in a single library together with other library | |
facilities that are not Applications and are not covered by this | |
License, and convey such a combined library under terms of your | |
choice, if you do both of the following: | |
a) Accompany the combined library with a copy of the same work based | |
on the Library, uncombined with any other library facilities, | |
conveyed under the terms of this License. | |
b) Give prominent notice with the combined library that part of it | |
is a work based on the Library, and explaining where to find the | |
accompanying uncombined form of the same work. | |
6. Revised Versions of the GNU Lesser General Public License. | |
The Free Software Foundation may publish revised and/or new versions | |
of the GNU Lesser General Public License from time to time. Such new | |
versions will be similar in spirit to the present version, but may | |
differ in detail to address new problems or concerns. | |
Each version is given a distinguishing version number. If the | |
Library as you received it specifies that a certain numbered version | |
of the GNU Lesser General Public License "or any later version" | |
applies to it, you have the option of following the terms and | |
conditions either of that published version or of any later version | |
published by the Free Software Foundation. If the Library as you | |
received it does not specify a version number of the GNU Lesser | |
General Public License, you may choose any version of the GNU Lesser | |
General Public License ever published by the Free Software Foundation. | |
If the Library as you received it specifies that a proxy can decide | |
whether future versions of the GNU Lesser General Public License shall | |
apply, that proxy's public statement of acceptance of any version is | |
permanent authorization for you to choose that version for the | |
Library. |
INCDIR = /usr/local/include/shogi | |
SERVER = server | |
CLIENT = client | |
DEBUG = n | |
MCHCK = n | |
BMI2 = n | |
TLS = n | |
CC = g++-7 | |
ifeq ($(BMI2),y) | |
CFLAGS += -DUSE_NATIVE_PEXTINSTRUCTION | |
endif | |
ifeq ($(TLS),y) | |
CFLAGS += -DUSE_THREADLOCALSTORAGE | |
endif | |
ifeq ($(DEBUG),y) | |
ifeq ($(MCHCK),y) | |
CFLAGS += -std=c++1z -Wall -Wextra -Wformat=2 -Wstrict-aliasing=2 \ | |
-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \ | |
-Wfloat-equal -Wpointer-arith -Wswitch-enum \ | |
-O0 -g -mtune=native -ftrapv -fthreadsafe-statics \ | |
-fsanitize=address \ | |
-I$(INCDIR) | |
LFLAGS = -pthread -lrt -lshogi -lboost_system | |
else | |
CFLAGS += -std=c++1z -Wall -Wextra -Wformat=2 -Wstrict-aliasing=2 \ | |
-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \ | |
-Wfloat-equal -Wpointer-arith -Wswitch-enum \ | |
-O0 -g -mtune=native -fthreadsafe-statics \ | |
-I$(INCDIR) | |
LFLAGS = -pthread -lrt -lshogi -lboost_system | |
endif | |
else | |
ifeq ($(MCHCK),y) | |
CFLAGS += -std=c++1z -Wall -Wextra -Wformat=2 -Wstrict-aliasing=2 \ | |
-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \ | |
-Wfloat-equal -Wpointer-arith -Wswitch-enum \ | |
-O3 -g -mtune=native -funroll-loops \ | |
-fthreadsafe-statics -ftrapv -fsanitize=address\ | |
-I$(INCDIR) | |
LFLAGS = -pthread -lrt -lshogi -lboost_system | |
else | |
CFLAGS += -std=c++1z -Wall -Wextra -Wformat=2 -Wstrict-aliasing=2 \ | |
-Wcast-qual -Wcast-align -Wwrite-strings -Wconversion \ | |
-Wfloat-equal -Wpointer-arith -Wswitch-enum \ | |
-O3 -g -mtune=native -funroll-loops \ | |
-fthreadsafe-statics \ | |
-I$(INCDIR) | |
LFLAGS = -lpthread -lrt -lshogi -lboost_system | |
endif | |
endif | |
all: $(SERVER) $(CLIENT) | |
%.o: %.cpp $(HEADERS) | |
$(CC) $(CFLAGS) -c -o $@ $< | |
$(SERVER): server.o $(HEADERS) $(OBJS) | |
$(CC) $(CFLAGS) -o $@ $< $(OBJS) $(LFLAGS) | |
$(CLIENT): client.o $(HEADERS) $(OBJS) | |
$(CC) $(CFLAGS) -o $@ $< $(OBJS) $(LFLAGS) | |
clean: | |
rm -f *.o $(EXEC) |
// Copyright (C) 2017 roki | |
#include"board_manager.hpp" | |
#include"tcp_server.hpp" | |
#include<iostream> | |
template<class RandomSeed> | |
void main_loop(tcp_server& server,board::shogi_board<RandomSeed>& shogi) | |
{ | |
for(boost::asio::streambuf receive_buffer;; receive_buffer.consume(receive_buffer.size())){ | |
try{ | |
server >> receive_buffer; | |
}catch(const std::exception& exp){ | |
std::cout << exp.what() << std::endl; | |
break; | |
} | |
std::string handedly = boost::asio::buffer_cast<const char*>(receive_buffer.data()); | |
std::cout << handedly << std::endl; | |
const auto opt0 = shogi.get_board(handedly); | |
if(!opt0){ | |
break; | |
}else{ | |
server << opt0.value(); | |
std::cout << opt0.value() << std::endl; | |
} | |
const auto opt1 = shogi.get_board(board::input()); | |
if(!opt1){ | |
break; | |
}else{ | |
std::cout << opt1.value() << std::endl; | |
server << opt1.value(); | |
} | |
} | |
} | |
template<class Integer,std::enable_if_t<std::is_integral_v<std::decay_t<Integer>>,std::nullptr_t> = nullptr> | |
void exec(Integer&& ip) | |
{ | |
using namespace std::string_literals; | |
game::Shogi::initialize(); | |
game::Position::setValue(game::Evaluation::Value); | |
game::Position::handsValue(game::Evaluation::Hands); | |
game::Position sw; | |
sw.init(); | |
std::random_device seed_gen; | |
board::shogi_board<std::mt19937> shogi(sw,seed_gen); | |
boost::asio::io_service io_service; | |
tcp_server server(io_service,std::forward<Integer>(ip)); | |
server.accept(); | |
server << shogi.get_board(); | |
std::cout << shogi.get_board() << std::endl; | |
main_loop(server,shogi); | |
} | |
int main(const int argc,const char* argv[]) | |
{ | |
if(argc != 2){ | |
std::cerr << "Usage: server <port>" << std::endl; | |
return EXIT_FAILURE; | |
} | |
exec(static_cast<unsigned short int>(std::stoi(argv[1]))); | |
} |
// Copyright (C) 2017 roki | |
#ifndef INCLUDED_TCP_CLIENT_HPP | |
#define INCLUDED_TCP_CLIENT_HPP | |
#include"tcp_wrapper.hpp" | |
struct tcp_client final : detail::tcp_wrapper{ | |
explicit tcp_client(boost::asio::io_service& io):tcp_wrapper(io,1645){} | |
void connect(std::string ip_address,short unsigned int port) | |
{ | |
std::cout << "Connecting to " << ip_address << ":" << port << std::endl; | |
sock.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(std::move(ip_address)),std::move(port))); | |
std::cout << "Connected!" << std::endl; | |
} | |
}; | |
#endif |
// Copyright (C) 2017 roki | |
#ifndef INCLUDED_TCP_SERVER_HPP | |
#define INCLUDED_TCP_SERVER_HPP | |
#include"tcp_wrapper.hpp" | |
struct tcp_server final : detail::tcp_wrapper { | |
explicit tcp_server(boost::asio::io_service& io,short unsigned int ip) | |
:tcp_wrapper(io,1), | |
acceptor(io,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),ip)){} | |
void accept() | |
{ | |
std::cout << "Waiting connection request..." << std::endl; | |
acceptor.accept(sock); | |
std::cout << "Connected. Waiting for client responce..." << std::endl; | |
} | |
private: | |
boost::asio::ip::tcp::acceptor acceptor; | |
}; | |
#endif |
// Copyright (C) 2017 roki | |
#ifndef INCLUDED_BOOST_ASIO_TCP_WRAPPER_HPP | |
#define INCLUDED_BOOST_ASIO_TCP_WRAPPER_HPP | |
#include<boost/asio.hpp> | |
#include<iostream> | |
#include<string> | |
namespace detail{ | |
struct tcp_wrapper : private boost::noncopyable { | |
explicit tcp_wrapper(boost::asio::io_service& io,std::size_t read_size):sock(io),read_size(std::move(read_size)){} | |
protected: | |
void* operator new(std::size_t) = delete; | |
void operator delete(void*,std::size_t) = delete; | |
void* operator new[](std::size_t,std::size_t) = delete; | |
void operator delete[](void*,std::size_t) = delete; | |
friend tcp_wrapper& operator>>(tcp_wrapper& tcp,boost::asio::streambuf& receive_buffer) | |
noexcept(false) | |
{ | |
using namespace std::string_literals; | |
boost::system::error_code error; | |
boost::asio::read(tcp.sock,receive_buffer,boost::asio::transfer_at_least(tcp.read_size),error); | |
if(error and error != boost::asio::error::eof){ | |
std::cerr << "receive failed: " << error.message() << std::endl; | |
} | |
return tcp; | |
} | |
friend tcp_wrapper& operator<<(tcp_wrapper& tcp,std::string str) | |
{ | |
boost::asio::write(tcp.sock,boost::asio::buffer(str)); | |
return tcp; | |
} | |
friend tcp_wrapper& operator<<(tcp_wrapper& tcp,const char* str) | |
{ | |
std::string mes_ = str; | |
boost::asio::write(tcp.sock,boost::asio::buffer(mes_)); | |
return tcp; | |
} | |
boost::asio::ip::tcp::socket sock; | |
std::size_t read_size; | |
}; | |
} // namespace detail | |
#endif |