summaryrefslogtreecommitdiff
path: root/minimax.cpp
blob: c4011daa39ccd008bd5ef6f25ba1c439cab323a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <array>
#include <memory>
#include "minimax.h"

using namespace std;

#define LARGE MINIMAX_LARGE


static int win_score[4] = {
	[WIN_NONE] = 0,
	[WIN_P0] = 1,
	[WIN_P1] = -1,
	[WIN_DRAW] = -1,
};

struct TransItem {
	Board B = Board::empty();
	int score = 0;
};

static unique_ptr<array<TransItem, 10000019>> transTable =
	make_unique<decltype(transTable)::element_type>();

static void transTableStore(uint64_t index, const Board &B, int score) {
	TransItem &entry = (*transTable)[index];
	// if (entry.B.isEmpty() || B.numFilled() < entry.B.numFilled()) {
		entry.B = B;
		entry.score = score;
	// }
}

static uint64_t transHits = 0, transTotal = 0;
static uint64_t transHitDepthSum = 0;

template <int player>
int minimax(const Board &B, int alpha, int beta, int depth) {
	uint64_t transIndex = B.hash() % transTable->size();
	transTotal++;
	if (!B.isEmpty() && (*transTable)[transIndex].B == B) {
		transHits++;
		transHitDepthSum += depth;
		return (*transTable)[transIndex].score;
	}

	win_t win = B.checkWin();
	if (win != WIN_NONE) {
		transTableStore(transIndex, B, win_score[win]);
		return win_score[win];
	}

	if (depth == 0) return win_score[WIN_NONE];

	if (depth >= 42) {
		printf("depth=%d alpha=%d beta=%d transHitrate=%lf (avg depth %lf)\n",
				depth, alpha, beta,
				(double)transHits / transTotal, (double)transHitDepthSum / transTotal);
	}

	int best = player == 0 ? -LARGE : LARGE;

	// Returns true if iteration should be stopped
	auto tryMove = [&](int i) {
		if (B.stkFull(i)) return false;

		Board C(B);
		C.drop(i, player);

		int sc = minimax<1 - player>(C, alpha, beta, depth - 1);

		if constexpr (player == 0) {
			best = max(sc, best);
			alpha = max(best, alpha);
		} else {
			best = min(sc, best);
			beta = min(best, beta);
		}

		return beta <= alpha;
	};

	for (int i = 0; i < 16; i++) {
		if (tryMove(i)) break;
	}

	transTableStore(transIndex, B, best);
	return best;
}

template int minimax<0>(const Board &B, int alpha, int beta, int depth);
template int minimax<1>(const Board &B, int alpha, int beta, int depth);