From bc598375da7b9a20a35e958afb61dcd690d3d7b7 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Wed, 13 Feb 2019 23:32:08 +0100 Subject: Play interactively against AI --- .gitmodules | 3 ++ Makefile | 4 +-- board.cpp | 7 ++-- board.h | 5 ++- main.cpp | 15 +++++++-- termio | 1 + ui.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui.h | 10 ++++++ 8 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 .gitmodules create mode 160000 termio create mode 100644 ui.cpp create mode 100644 ui.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..034d1af --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "termio"] + path = termio + url = https://github.com/tomsmeding/termio diff --git a/Makefile b/Makefile index 1a1e21d..1d3addf 100644 --- a/Makefile +++ b/Makefile @@ -18,9 +18,9 @@ clean: rm -f $(TARGET) rm -rf $(OBJDIR) -$(TARGET): $(OBJ_FILES) +$(TARGET): $(OBJ_FILES) termio/libtermio.a @echo LD $@ - @$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) + @$(CXX) $(CXXFLAGS) -o $@ $^ termio/libtermio.a $(LDFLAGS) $(OBJDIR)/%.o: %.cpp @mkdir -p $(dir $@) diff --git a/board.cpp b/board.cpp index c84e72f..fcb82ae 100644 --- a/board.cpp +++ b/board.cpp @@ -177,9 +177,6 @@ Bounds Board::computeBounds() const { } void Board::write(ostream &os) const { - static const char *edgeStr = "\x1B[36m+\x1B[0m"; - static const char *openStr = "·"; - Bounds bounds = computeBounds(); for (int y = bounds.top; y <= bounds.bottom; y++) { @@ -188,8 +185,8 @@ void Board::write(ostream &os) const { int idx = BSZ * y + x; if (bd[idx] != 0) os << Stone(bd[idx]); - else if (checkEdge(idx)) os << edgeStr; - else os << openStr; + else if (checkEdge(idx)) os << EDGE_STR; + else os << OPEN_STR; } os << endl; } diff --git a/board.h b/board.h index a144ed7..03f096c 100644 --- a/board.h +++ b/board.h @@ -57,6 +57,7 @@ public: void write(ostream &os) const; Bounds computeBounds() const; + bool checkEdge(int idx) const; private: // 0 = empty, 1...NC = coloured stones @@ -73,7 +74,6 @@ private: int countStones(uint8_t clr, int idx, int delta) const; void newEdgeCand(int idx); - bool checkEdge(int idx) const; }; struct Stone { @@ -81,5 +81,8 @@ struct Stone { inline Stone(uint8_t clr) : clr(clr) {} }; +#define EDGE_STR "\x1B[36m+\x1B[0m" +#define OPEN_STR "·" + ostream& operator<<(ostream &os, Stone stone); ostream& operator<<(ostream &os, const Board &bd); diff --git a/main.cpp b/main.cpp index 80d0fb8..c53f5ae 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include "board.h" #include "mc.h" +#include "ui.h" #include "util.h" using namespace std; @@ -15,15 +16,23 @@ int main() { Board bd = Board::makeEmpty(); cerr << "Initial stone at " << Idx(BSZ * BMID + BMID) << endl; - bd.put(BSZ * BMID + BMID, 1); + bd.put(BSZ * BMID + BMID, bd.bag.drawRandom()); cout << bd << endl; - uint8_t onturn = 2; + uint8_t onturn = 1; while (bd.bag.totalLeft() > 0) { cout << "--- NEXT TURN: " << Stone(onturn) << " ---" << endl; - int idx = MC::calcMove(bd, onturn); + int idx; + + if (onturn == 1) { + cout << "YOUR TURN." << endl; + idx = UI::getMove(bd); + } else { + idx = MC::calcMove(bd, onturn); + } + uint8_t clr = bd.bag.drawRandom(); uint8_t win = bd.putCW(idx, clr); diff --git a/termio b/termio new file mode 160000 index 0000000..0f498cf --- /dev/null +++ b/termio @@ -0,0 +1 @@ +Subproject commit 0f498cf54d8ecbfc81cf8b03ed2fcf3995b513f3 diff --git a/ui.cpp b/ui.cpp new file mode 100644 index 0000000..82b9158 --- /dev/null +++ b/ui.cpp @@ -0,0 +1,109 @@ +#include +#include +#include "ui.h" +#include "termio/termio.h" + +using namespace std; + + +static void cursorMove(int dx, int dy) { + if (dx < 0) cout << "\x1B[" << -dx << "D"; + if (dx > 0) cout << "\x1B[" << dx << "C"; + if (dy < 0) cout << "\x1B[" << -dy << "A"; + if (dy > 0) cout << "\x1B[" << dy << "B"; + cout << flush; +} + +int UI::getMove(const Board &bd) { + Bounds bounds = bd.computeBounds(); + const int l = bounds.left; + const int t = bounds.top; + const int w = bounds.right - bounds.left + 1; + const int h = bounds.bottom - bounds.top + 1; + + const auto toIdx = [l, t](int x, int y) { + return BSZ * (t + y) + l + x; + }; + + // -1: edge, 0: open, 1...: stones + vector> cells(h); + for (int y = 0; y < h; y++) { + cells[y].resize(w); + for (int x = 0; x < w; x++) { + int idx = toIdx(x, y); + cells[y][x] = bd[idx]; + if (cells[y][x] == 0 && bd.checkEdge(idx)) { + cells[y][x] = -1; + } + } + } + + for (int y = 0; y < h; y++) { + if (y != 0) cout << endl; + for (int x = 0; x < w; x++) { + if (x != 0) cout << ' '; + if (cells[y][x] == -1) cout << EDGE_STR; + else if (cells[y][x] == 0) cout << OPEN_STR; + else cout << Stone(cells[y][x]); + } + } + + cout << flush; + + cursorMove(-2 * w - 1, -h + 1); + int curx = 0, cury = 0; + const auto cursorXY = [&curx, &cury](int x, int y) { + cursorMove(2 * (x - curx), y - cury); + curx = x; cury = y; + }; + const auto cursorDXDY = [w, h, &curx, &cury, &cursorXY](int dx, int dy) { + int newx = curx + dx, newy = cury + dy; + newx = max(0, min(w - 1, newx)); + newy = max(0, min(h - 1, newy)); + cursorXY(newx, newy); + }; + + bool quit = false; + + initkeyboard(false); + + while (true) { + int key = tgetkey(); + bool done = false; + switch (key) { + case KEY_LEFT: cursorDXDY(-1, 0); break; + case KEY_RIGHT: cursorDXDY(1, 0); break; + case KEY_UP: cursorDXDY(0, -1); break; + case KEY_DOWN: cursorDXDY(0, 1); break; + + case KEY_LF: + case KEY_CR: + if (cells[cury][curx] == -1) done = true; + else bel(); + break; + + case 'q': + quit = true; + done = true; + break; + + default: + bel(); + break; + } + if (done) break; + } + + endkeyboard(); + + int retidx = toIdx(curx, cury); + + cursorXY(0, h - 1); + cout << endl << endl; + + if (quit) { + exit(0); + } + + return retidx; +} diff --git a/ui.h b/ui.h new file mode 100644 index 0000000..8a7c9e6 --- /dev/null +++ b/ui.h @@ -0,0 +1,10 @@ +#pragma once + +#include "board.h" + +using namespace std; + + +namespace UI { + int getMove(const Board &bd); +} -- cgit v1.2.3-54-g00ecf