aboutsummaryrefslogtreecommitdiffstats
path: root/gin.h
blob: e88c5177beec9f2b1c8064d4fa57789d53fc5ed2 (plain) (blame)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#ifndef WCARDS_GIN_H
#define WCARDS_GIN_H

#include <ostream>
#include <set>
#include <vector>

#include "card.h"
#include "deck.h"
#include "hand.h"

namespace wcards {
namespace gin {
	void print_rules(void) {
		printf("FIXME (aiden@aidenw.net): add rules\n");
	}

	bool isRun(const std::vector<wcards::Card>& meld) {
		if (meld.size() < 3) return false;
		for (size_t i = 1; i < meld.size(); ++i) {
			if (meld[i - 1].suit() != meld[i].suit()) return false;
			if (meld[i - 1].rankNum() != meld[i].rankNum() - 1) return false;
		}
		return true;
	}

	bool isSet(const std::vector<wcards::Card>& meld) {
		if (meld.size() != 3 && meld.size() != 4) return false;
		for (size_t i = 1; i < meld.size(); ++i) {
			if (meld[i - 1].rank() != meld[i].rank()) return false;
		}
		return true;
	}

	class Hand : public wcards::Hand<10> {
	public:
		Hand(wcards::Deck& deck): wcards::Hand<10>::Hand(deck, 10) {
			melds.reserve(10);
		}
		bool canGin(void) const noexcept {
			//FIXME
			return true;
		}
		unsigned score(void) const noexcept {
			std::set<wcards::Card> mcards;
			// Get all meld cards.
			for (std::set<wcards::Card> m : melds) {
				mcards.insert(m.begin(), m.end());
			}
			// Get score of deadwood.
			unsigned sum = 0;
			for (size_t i = 0; i < size(); ++i) {
				if (mcards.count(card(i))) continue; // skip meld cards.
				char r = card(i).rank();
				switch (r) {
				case 'A': sum += 1; break;
				case '?': break;
				case 'T': case 'J': case 'Q': case 'K': sum += 10; break;
				default: sum += r - '0';
				}
			}
			return sum;
		}
		void remove(const Card& c) {
			// Disolve any melds with c.
			for (auto it = melds.begin(); it != melds.end();) {
				if (it->count(c)) it = melds.erase(it);
				else ++it;
			}
			// Remove card from cards.
			wcards::Hand<10>::remove(c);
		}
		void meld(const std::vector<wcards::Card>& mcards) {
			// Confirm this hand has all mcards.
			for (auto it = mcards.begin(); it != mcards.end(); ++it) {
				if (!has(*it)) {
					std::cout << "WARN: this hand does not contain " << *it << std::endl;
					return;
				}
			}
			// Confirm mcards is a valid meld.
			if (!isRun(mcards) && !isSet(mcards)) {
				printf("WARN: not a valid meld.\n");
				return;
			}
			// Disolve any other melds with any of mcards.
			for (const Card& c : mcards) {
				for (auto it = melds.begin(); it != melds.end();) {
					if (it->count(c)) it = melds.erase(it);
					else ++it;
				}
			}
			// Insert the new meld.
			std::set<wcards::Card> smcards(mcards.begin(), mcards.end());
			melds.push_back(smcards);
		}
		friend std::ostream& operator<<(std::ostream& str, const Hand& hand);
	private:
		std::vector<std::set<wcards::Card>> melds;
	};

	void knock(const Hand& hand) {
		printf("FIXME (aiden@aidenw.net): someone is knocking.\n");
	}
	void gin(const Hand& hand) {
		printf("FIXME (aiden@aidenw.net): someone is calling gin.\n");
	}

	std::ostream& operator<<(std::ostream& str, const Hand& hand) {
		std::set<wcards::Card> mcards;
		for (size_t i = 0; i < hand.melds.size(); ++i) {
			mcards.insert(hand.melds[i].begin(), hand.melds[i].end());
			if (i) str << ' ';
			str << i << '(';
			for (auto it = hand.melds[i].begin(); it != hand.melds[i].end(); ++it) {
				if (it != hand.melds[i].begin()) str << ' ';
				str << *it;
			}
			str << ')';
		}
		if (!mcards.empty()) str << ' ';
		for (size_t i = 0, first = 1; i < hand.size(); ++i) {
			auto it = mcards.find(hand.card(i));
			if (!mcards.count(hand.card(i))) {
				if (!first) str << ' ';
				first = 0;
				str << hand.card(i);
			}
		}
		return str;
	}
} // namespace gin
} // namespace wcards

#endif // WCARDS_GIN_H