UCIEndpoint.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "UCIEndpoint.h"
  27. #include <AK/ByteBuffer.h>
  28. #include <AK/String.h>
  29. #include <LibCore/EventLoop.h>
  30. #include <LibCore/File.h>
  31. // #define UCI_DEBUG
  32. namespace Chess::UCI {
  33. Endpoint::Endpoint(NonnullRefPtr<Core::IODevice> in, NonnullRefPtr<Core::IODevice> out)
  34. : m_in(in)
  35. , m_out(out)
  36. , m_in_notifier(Core::Notifier::construct(in->fd(), Core::Notifier::Read))
  37. {
  38. set_in_notifier();
  39. }
  40. void Endpoint::send_command(const Command& command)
  41. {
  42. #ifdef UCI_DEBUG
  43. dbg() << class_name() << " Sent UCI Command: " << String(command.to_string().characters(), Chomp);
  44. #endif
  45. m_out->write(command.to_string());
  46. }
  47. void Endpoint::event(Core::Event& event)
  48. {
  49. switch (event.type()) {
  50. case Command::Type::UCI:
  51. return handle_uci();
  52. case Command::Type::Debug:
  53. return handle_debug(static_cast<const DebugCommand&>(event));
  54. case Command::Type::IsReady:
  55. return handle_uci();
  56. case Command::Type::SetOption:
  57. return handle_setoption(static_cast<const SetOptionCommand&>(event));
  58. case Command::Type::Position:
  59. return handle_position(static_cast<const PositionCommand&>(event));
  60. case Command::Type::Go:
  61. return handle_go(static_cast<const GoCommand&>(event));
  62. case Command::Type::Stop:
  63. return handle_stop();
  64. case Command::Type::Id:
  65. return handle_id(static_cast<const IdCommand&>(event));
  66. case Command::Type::UCIOk:
  67. return handle_uciok();
  68. case Command::Type::ReadyOk:
  69. return handle_readyok();
  70. case Command::Type::BestMove:
  71. return handle_bestmove(static_cast<const BestMoveCommand&>(event));
  72. case Command::Type::Info:
  73. return handle_info(static_cast<const InfoCommand&>(event));
  74. default:
  75. break;
  76. }
  77. }
  78. void Endpoint::set_in_notifier()
  79. {
  80. m_in_notifier = Core::Notifier::construct(m_in->fd(), Core::Notifier::Read);
  81. m_in_notifier->on_ready_to_read = [this] {
  82. while (m_in->can_read_line())
  83. Core::EventLoop::current().post_event(*this, read_command());
  84. };
  85. }
  86. NonnullOwnPtr<Command> Endpoint::read_command()
  87. {
  88. String line(ReadonlyBytes(m_in->read_line(4096).bytes()), Chomp);
  89. #ifdef UCI_DEBUG
  90. dbg() << class_name() << " Received UCI Command: " << line;
  91. #endif
  92. if (line == "uci") {
  93. return make<UCICommand>(UCICommand::from_string(line));
  94. } else if (line.starts_with("debug")) {
  95. return make<DebugCommand>(DebugCommand::from_string(line));
  96. } else if (line.starts_with("isready")) {
  97. return make<IsReadyCommand>(IsReadyCommand::from_string(line));
  98. } else if (line.starts_with("setoption")) {
  99. return make<SetOptionCommand>(SetOptionCommand::from_string(line));
  100. } else if (line.starts_with("position")) {
  101. return make<PositionCommand>(PositionCommand::from_string(line));
  102. } else if (line.starts_with("go")) {
  103. return make<GoCommand>(GoCommand::from_string(line));
  104. } else if (line.starts_with("stop")) {
  105. return make<StopCommand>(StopCommand::from_string(line));
  106. } else if (line.starts_with("id")) {
  107. return make<IdCommand>(IdCommand::from_string(line));
  108. } else if (line.starts_with("uciok")) {
  109. return make<UCIOkCommand>(UCIOkCommand::from_string(line));
  110. } else if (line.starts_with("readyok")) {
  111. return make<ReadyOkCommand>(ReadyOkCommand::from_string(line));
  112. } else if (line.starts_with("bestmove")) {
  113. return make<BestMoveCommand>(BestMoveCommand::from_string(line));
  114. } else if (line.starts_with("info")) {
  115. return make<InfoCommand>(InfoCommand::from_string(line));
  116. }
  117. dbg() << "command line: " << line;
  118. ASSERT_NOT_REACHED();
  119. }
  120. };