Skip to content

Commit c263161

Browse files
committedAug 30, 2024
added test and cleaned code
1 parent fead5b5 commit c263161

6 files changed

+567
-104
lines changed
 

‎DominoGame.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def play_game(self):
9191
games_tied = 0 # Number of tied games
9292
round_scores = [] # List to store scores for each round
9393

94-
winning_score = 100 if self.variant != 'international' else 1500
94+
winning_score = 100 if self.variant != 'international' else 1
9595

9696
while max(self.scores) < winning_score:
9797
round_winner, round_score = self.play_round()

‎domino_game_tracker.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,8 @@ def generate_sample_from_game_state(
324324
raise ae
325325

326326
# Generate a sample
327-
sample = generate_sample(list(remaining_tiles), not_with, known_with, player_tiles)
327+
sample = generate_sample(list(remaining_tiles), not_with, player_tiles)
328+
# sample = generate_sample(list(remaining_tiles), not_with, known_with, player_tiles)
328329

329330
return sample
330331

‎domino_probability_calc.py

+256-90
Large diffs are not rendered by default.

‎generate-sample-unit-tests.py

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import unittest
2+
from typing import List, Tuple, Set
3+
from domino_game_analyzer import DominoTile, PlayerPosition
4+
from domino_probability_calc import generate_sample, PlayerTiles
5+
6+
class TestGenerateSample(unittest.TestCase):
7+
def setUp(self):
8+
self.remaining_tiles = [
9+
DominoTile(0, 1), DominoTile(0, 2), DominoTile(1, 2),
10+
DominoTile(1, 3), DominoTile(2, 3), DominoTile(3, 3)
11+
]
12+
13+
def test_basic_functionality(self):
14+
not_with = {'N': set(), 'E': set(), 'W': set()}
15+
# known_with = {}
16+
player_tiles = PlayerTiles(N=2, E=2, W=2)
17+
18+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
19+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
20+
21+
self.assertEqual(len(sample), 3) # Should have 3 players
22+
self.assertEqual(sum(len(tiles) for tiles in sample.values()), 6) # Total tiles should be 6
23+
self.assertEqual(len(sample['N']), 2)
24+
self.assertEqual(len(sample['E']), 2)
25+
self.assertEqual(len(sample['W']), 2)
26+
27+
def test_not_with_constraint(self):
28+
not_with = {'N': {DominoTile(0, 1), DominoTile(0, 2)}, 'E': set(), 'W': set()}
29+
known_with = {}
30+
player_tiles = PlayerTiles(N=2, E=2, W=2)
31+
32+
for _ in range(25):
33+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
34+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
35+
36+
self.assertNotIn(DominoTile(0, 1), sample['N'])
37+
self.assertNotIn(DominoTile(0, 2), sample['N'])
38+
39+
# def test_known_with_constraint(self):
40+
# not_with = {}
41+
# # known_with = {'E': {DominoTile(1, 2), DominoTile(2, 3)}}
42+
# player_tiles = PlayerTiles(N=2, E=2, W=2)
43+
44+
# for _ in range(25):
45+
# sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
46+
# # sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
47+
48+
# self.assertIn(DominoTile(1, 2), sample['E'])
49+
# self.assertIn(DominoTile(2, 3), sample['E'])
50+
51+
def test_uneven_distribution(self):
52+
not_with = {'N': set(), 'E': set(), 'W': set()}
53+
# known_with = {}
54+
player_tiles = PlayerTiles(N=3, E=2, W=1)
55+
56+
for _ in range(25):
57+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
58+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
59+
60+
self.assertEqual(len(sample['N']), 3)
61+
self.assertEqual(len(sample['E']), 2)
62+
self.assertEqual(len(sample['W']), 1)
63+
64+
def test_all_tiles_assigned(self):
65+
not_with = {'N': set(), 'E': set(), 'W': set()}
66+
# known_with = {}
67+
player_tiles = PlayerTiles(N=2, E=2, W=2)
68+
69+
for _ in range(25):
70+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
71+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
72+
73+
all_assigned_tiles = set().union(*sample.values())
74+
self.assertEqual(set(self.remaining_tiles), all_assigned_tiles)
75+
76+
def test_no_duplicate_assignments(self):
77+
not_with = {'N': set(), 'E': set(), 'W': set()}
78+
# known_with = {}
79+
player_tiles = PlayerTiles(N=2, E=2, W=2)
80+
81+
for _ in range(25):
82+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
83+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
84+
85+
all_assigned_tiles = list(sample['N']) + list(sample['E']) + list(sample['W'])
86+
self.assertEqual(len(all_assigned_tiles), len(set(all_assigned_tiles)))
87+
88+
def test_conflicting_constraints(self):
89+
not_with = {'N': {DominoTile(0, 1), DominoTile(0, 2)}, 'E': {DominoTile(0, 1)}, 'W': {DominoTile(0, 1)}}
90+
# known_with = {'N': {DominoTile(0, 1)}}
91+
player_tiles = PlayerTiles(N=2, E=2, W=2)
92+
93+
with self.assertRaises(AssertionError) as context:
94+
for _ in range(25):
95+
generate_sample(self.remaining_tiles, not_with, player_tiles)
96+
# generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
97+
self.assertEqual(str(context.exception), "Tile in remaining_tiles and not with any player!")
98+
99+
def test_double_not_with_constraint(self):
100+
not_with = {'N': {DominoTile(0, 1), DominoTile(0, 2)}, 'E':{DominoTile(0,1),DominoTile(1,2)}, 'W': set()}
101+
# known_with = {}
102+
player_tiles = PlayerTiles(N=2, E=2, W=2)
103+
104+
# with self.assertRaises(AssertionError):
105+
for _ in range(25):
106+
sample = generate_sample(self.remaining_tiles, not_with, player_tiles)
107+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
108+
self.assertIn(DominoTile(0, 1), sample['W'])
109+
self.assertNotIn(DominoTile(0, 1), sample['N'])
110+
self.assertNotIn(DominoTile(0, 1), sample['E'])
111+
self.assertNotIn(DominoTile(0, 2), sample['N'])
112+
self.assertNotIn(DominoTile(1, 2), sample['E'])
113+
114+
115+
def test_double_not_with_constraint2(self):
116+
remaining_tiles = set([
117+
DominoTile(0, 0), DominoTile(0, 1), DominoTile(0, 2), DominoTile(0, 6),
118+
DominoTile(1, 3), DominoTile(1, 4), DominoTile(1, 5), DominoTile(1, 6),
119+
DominoTile(2, 2), DominoTile(2, 3), DominoTile(2, 6), DominoTile(3, 3),
120+
DominoTile(5, 6)
121+
# DominoTile(2, 4), DominoTile(3, 6) # Tiles in human player's hand
122+
])
123+
124+
# Define not_with based on _knowledge_tracker
125+
not_with = {
126+
'E': set(),
127+
'N': {DominoTile(5, 6), DominoTile(1, 4)},
128+
'W': {DominoTile(1, 4)}
129+
}
130+
131+
# Define player_tiles (assuming 7 tiles per player at the start)
132+
player_tiles = PlayerTiles(N=1, E=1, W=1)
133+
134+
player_tiles = PlayerTiles(N=4, E=4, W=5)
135+
# with self.assertRaises(AssertionError):
136+
for _ in range(25):
137+
sample = generate_sample(remaining_tiles, not_with, player_tiles)
138+
# sample = generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
139+
self.assertIn(DominoTile(1, 4), sample['E'])
140+
self.assertNotIn(DominoTile(1, 4), sample['N'])
141+
self.assertNotIn(DominoTile(1, 4), sample['W'])
142+
self.assertNotIn(DominoTile(5, 6), sample['N'])
143+
144+
145+
def test_invalid_player_tiles(self):
146+
not_with = {'N': set(), 'E': set(), 'W': set()}
147+
known_with = {}
148+
player_tiles = PlayerTiles(N=3, E=2, W=2) # Total is 7, but we only have 6 tiles
149+
150+
with self.assertRaises(AssertionError):
151+
generate_sample(self.remaining_tiles, not_with, player_tiles)
152+
# generate_sample(self.remaining_tiles, not_with, known_with, player_tiles)
153+
154+
if __name__ == '__main__':
155+
unittest.main()

‎probability_test.py

+107-9
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,24 @@ def test_known_not_with(self):
2626
self.assertAlmostEqual(probabilities[DominoTile(1, 2)]['E'], 0.5)
2727
self.assertAlmostEqual(probabilities[DominoTile(1, 2)]['W'], 0.5)
2828

29-
def test_known_with(self):
30-
player_tiles = PlayerTiles(N=1, E=1, W=1)
31-
remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
32-
not_with = {'N': {DominoTile(1, 2)}, 'E': {DominoTile(1, 2)}, 'W':set()}
33-
probabilities = calculate_tile_probabilities(remaining_tiles, not_with, player_tiles)
29+
# Invalid test!
30+
# def test_known_with(self):
31+
# player_tiles = PlayerTiles(N=1, E=1, W=1)
32+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
33+
# not_with = {'N': {DominoTile(1, 2)}, 'E': {DominoTile(1, 2)}, 'W':set()}
34+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, player_tiles)
3435

35-
self.assertEqual(probabilities[DominoTile(1, 2)]['W'], 1.0)
36-
self.assertEqual(probabilities[DominoTile(1, 2)]['N'], 0.0)
37-
self.assertEqual(probabilities[DominoTile(1, 2)]['E'], 0.0)
36+
# self.assertEqual(probabilities[DominoTile(1, 2)]['W'], 1.0)
37+
# self.assertEqual(probabilities[DominoTile(1, 2)]['N'], 0.0)
38+
# self.assertEqual(probabilities[DominoTile(1, 2)]['E'], 0.0)
3839

3940
def test_uneven_distribution(self):
4041
remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6), DominoTile(1, 3)]
4142
player_tiles = PlayerTiles(N=2, E=1, W=1)
4243
not_with = {'N':set(),'E':set(),'W':set()}
4344
probabilities = calculate_tile_probabilities(remaining_tiles, not_with, player_tiles)
4445

45-
print(probabilities)
46+
# print(probabilities)
4647
total_outcomes = comb(4,2)*comb(2,1)
4748
for tile in remaining_tiles:
4849
self.assertAlmostEqual(sum(probabilities[tile].values()), 1.0)
@@ -54,6 +55,7 @@ def test_uneven_distribution(self):
5455

5556
def test_empty_remaining_tiles(self):
5657
remaining_tiles = []
58+
not_with = {'N':set(),'E':set(),'W':set()}
5759
probabilities = calculate_tile_probabilities(remaining_tiles, not_with, self.player_tiles)
5860

5961
self.assertEqual(probabilities, {})
@@ -85,3 +87,99 @@ def test_probability_sum(self):
8587

8688
if __name__ == '__main__':
8789
unittest.main()
90+
91+
92+
# import unittest
93+
# from domino_probability_calc import calculate_tile_probabilities, PlayerTiles, DominoTile
94+
# from math import comb
95+
96+
# class TestCalculateTileProbabilities(unittest.TestCase):
97+
98+
# def setUp(self):
99+
# self.player_tiles = PlayerTiles(N=1, E=1, W=1)
100+
101+
# def test_basic_scenario(self):
102+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
103+
# not_with = {'N':set(),'E':set(),'W':set()}
104+
# known_with = {}
105+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, self.player_tiles)
106+
107+
# for tile in remaining_tiles:
108+
# self.assertAlmostEqual(sum(probabilities[tile].values()), 1.0)
109+
# for prob in probabilities[tile].values():
110+
# self.assertAlmostEqual(prob, 1/3)
111+
112+
# def test_known_not_with(self):
113+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
114+
# not_with = {'N': {DominoTile(1, 2)},'E':set(),'W':set()}
115+
# known_with = {}
116+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, self.player_tiles)
117+
118+
# self.assertEqual(probabilities[DominoTile(1, 2)]['N'], 0.0)
119+
# self.assertAlmostEqual(probabilities[DominoTile(1, 2)]['E'], 0.5)
120+
# self.assertAlmostEqual(probabilities[DominoTile(1, 2)]['W'], 0.5)
121+
122+
# def test_known_with(self):
123+
# player_tiles = PlayerTiles(N=1, E=1, W=1)
124+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
125+
# not_with = {'N': set(), 'E': set(), 'W': set()}
126+
# known_with = {'W': {DominoTile(1, 2)}}
127+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, player_tiles)
128+
129+
# self.assertEqual(probabilities[DominoTile(1, 2)]['W'], 1.0)
130+
# self.assertEqual(probabilities[DominoTile(1, 2)]['N'], 0.0)
131+
# self.assertEqual(probabilities[DominoTile(1, 2)]['E'], 0.0)
132+
133+
# def test_uneven_distribution(self):
134+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6), DominoTile(1, 3)]
135+
# player_tiles = PlayerTiles(N=2, E=1, W=1)
136+
# not_with = {'N':set(),'E':set(),'W':set()}
137+
# known_with = {}
138+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, player_tiles)
139+
140+
# total_outcomes = comb(4,2)*comb(2,1)
141+
# for tile in remaining_tiles:
142+
# self.assertAlmostEqual(sum(probabilities[tile].values()), 1.0)
143+
# for player, prob in probabilities[tile].items():
144+
# if player == 'N':
145+
# self.assertAlmostEqual(prob, comb(3,1)*comb(2,1)/total_outcomes)
146+
# else:
147+
# self.assertAlmostEqual(prob, comb(3,2)/total_outcomes)
148+
149+
# def test_empty_remaining_tiles(self):
150+
# remaining_tiles = []
151+
# not_with = {'N':set(),'E':set(),'W':set()}
152+
# known_with = {}
153+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, self.player_tiles)
154+
155+
# self.assertEqual(probabilities, {})
156+
157+
# def test_all_tiles_known(self):
158+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6)]
159+
# not_with = {'N':set(),'E':set(),'W':set()}
160+
# known_with = {
161+
# 'N': {DominoTile(1, 2)},
162+
# 'E': {DominoTile(3, 4)},
163+
# 'W': {DominoTile(5, 6)}
164+
# }
165+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, self.player_tiles)
166+
167+
# expected = {
168+
# DominoTile(1, 2): {'N': 1.0, 'E': 0.0, 'W': 0.0},
169+
# DominoTile(3, 4): {'N': 0.0, 'E': 1.0, 'W': 0.0},
170+
# DominoTile(5, 6): {'N': 0.0, 'E': 0.0, 'W': 1.0}
171+
# }
172+
# self.assertEqual(probabilities, expected)
173+
174+
# def test_probability_sum(self):
175+
# remaining_tiles = [DominoTile(1, 2), DominoTile(3, 4), DominoTile(5, 6), DominoTile(1, 3)]
176+
# not_with = {'N': {DominoTile(1, 2)},'E':set(),'W':set()}
177+
# known_with = {}
178+
# player_tiles = PlayerTiles(N=1, E=2, W=1)
179+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, known_with, player_tiles)
180+
181+
# for tile in remaining_tiles:
182+
# self.assertAlmostEqual(sum(probabilities[tile].values()), 1.0)
183+
184+
# if __name__ == '__main__':
185+
# unittest.main()

‎test.py

+46-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
# local_not_with {'E': {1|3}, 'N': set(), 'W': {1|3}}
3131

3232

33-
from domino_probability_calc import calculate_tile_probabilities, PlayerTiles,generate_scenarios
33+
from domino_probability_calc import calculate_tile_probabilities, PlayerTiles,generate_scenarios, generate_sample
3434
from domino_game_analyzer import DominoTile
3535
import copy
3636

@@ -62,6 +62,49 @@ def test_calculate_probabilities():
6262
print(f" P({player} has {tile}) = {prob:.6f}")
6363
print()
6464

65+
def test_calculate_probabilities2():
66+
# tile 0|6
67+
# probabilities[tile] {'N': 0.3333333333333333, 'E': 0.0, 'W': 0.0}
68+
# not_with {'E': set(), 'N': {5|6, 1|4}, 'W': {1|4}}
69+
# not_with_local {'E': set(), 'N': {5|6, 1|4}, 'W': {1|4}}
70+
# known_with_local {'W': {0|6}}
71+
# prob.sum 0.3333333333333333
72+
# scenarios []
73+
# player_tiles PlayerTiles(N=1, E=1, W=1)
74+
# Remaining tiles: [0|0, 0|1, 0|2, 0|6, 1|3, 1|4, 1|5, 1|6, 2|2, 2|3, 2|6, 3|3, 5|6]
75+
76+
remaining_tiles = set([
77+
DominoTile(0, 0), DominoTile(0, 1), DominoTile(0, 2), DominoTile(0, 6),
78+
DominoTile(1, 3), DominoTile(1, 4), DominoTile(1, 5), DominoTile(1, 6),
79+
DominoTile(2, 2), DominoTile(2, 3), DominoTile(2, 6), DominoTile(3, 3),
80+
DominoTile(5, 6)
81+
# DominoTile(2, 4), DominoTile(3, 6) # Tiles in human player's hand
82+
])
83+
84+
# Define not_with based on _knowledge_tracker
85+
not_with = {
86+
'E': set(),
87+
'N': {DominoTile(5, 6), DominoTile(1, 4)},
88+
'W': {DominoTile(1, 4)}
89+
}
90+
91+
# Define player_tiles (assuming 7 tiles per player at the start)
92+
player_tiles = PlayerTiles(N=1, E=1, W=1)
93+
94+
# Call calculate_tile_probabilities
95+
# probabilities = calculate_tile_probabilities(remaining_tiles, not_with, player_tiles)
96+
# Print the results
97+
# for tile, probs in probabilities.items():
98+
# print(f"Tile {tile}:")
99+
# for player, prob in probs.items():
100+
# print(f" P({player} has {tile}) = {prob:.6f}")
101+
# print()
102+
103+
player_tiles = PlayerTiles(N=4, E=4, W=5)
104+
sample = generate_sample(remaining_tiles, not_with, player_tiles)
105+
print('sample',sample)
106+
107+
65108

66109
def test_generate_scenarios():
67110
player_tiles = [DominoTile(5,6)]
@@ -79,5 +122,5 @@ def test_generate_scenarios():
79122
print('not_with_local',not_with_local)
80123

81124
if __name__ == "__main__":
82-
# test_calculate_probabilities()
83-
test_generate_scenarios()
125+
test_calculate_probabilities2()
126+
# test_generate_scenarios()

0 commit comments

Comments
 (0)
Please sign in to comment.