summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2019-02-13 23:32:08 +0100
committerTom Smeding <tom.smeding@gmail.com>2019-02-13 23:32:08 +0100
commitbc598375da7b9a20a35e958afb61dcd690d3d7b7 (patch)
tree764398251e30ae68920e53aa256d7e30b4cf55a0
parent6175cb1c53772cc92d91a39a254c38bdf8f64905 (diff)
Play interactively against AI
-rw-r--r--.gitmodules3
-rw-r--r--Makefile4
-rw-r--r--board.cpp7
-rw-r--r--board.h5
-rw-r--r--main.cpp15
m---------termio0
-rw-r--r--ui.cpp109
-rw-r--r--ui.h10
8 files changed, 142 insertions, 11 deletions
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 <sys/time.h>
#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
+Subproject 0f498cf54d8ecbfc81cf8b03ed2fcf3995b513f
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 <sstream>
+#include <vector>
+#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<vector<int>> 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);
+}