1
+ """The main board for game play in the game of Dots."""
2
+
1
3
# Copyright 2021 Curt Bathras
2
4
#
3
5
# Permission is hereby granted, free of charge, to any person obtaining a copy
29
31
30
32
31
33
class Board :
34
+ """A Board is the collection of all of the entities that make up the game.
35
+ Namely, dots, edges, and cells. Entities are grouped into what I call
36
+ superrows and supercolumns. A single element, or supercell, of a superrow
37
+ and supercolumn is the collection of one dot, two edges and one cell. The
38
+ number of superrows is one greater than the number of cells in the board's
39
+ height and the number of supercolumns is one greater than the number of
40
+ cells in the board's width. Superrows and supercolumns allow for a very fast
41
+ lookup of which two edges could possibly contain a point in space. Once the
42
+ supercell is known, it is quick to check if either edge contains the point.
43
+
44
+ The diagram below illustrates the concept of a supercell. D = a dot, E = an
45
+ edge, C = a cell.
46
+
47
+ DDD | EEEEEEEEEEEEEEE
48
+ DDD | EEEEEEEEEEEEEEE
49
+ ---------------------
50
+ EEE | CCCCCCCCCCCCCCC
51
+ EEE | CCCCCCCCCCCCCCC
52
+ EEE | CCCCCCCCCCCCCCC
53
+ EEE | CCCCCCCCCCCCCCC
54
+ EEE | CCCCCCCCCCCCCCC
55
+ EEE | CCCCCCCCCCCCCCC
56
+
57
+ This supercell consists of one dot, two edges (one vertical and one
58
+ horizontal) and one cell. For the last supercolumn, the supercell only
59
+ contains the dot and vertical edge. For the last superrow, the supercell
60
+ only contains the dot and horizontal edge. The upper left corner of a
61
+ supercell and its height and width are well-defined. So the lookup of which
62
+ supercell contains a point is very fast. From there, it is at most two
63
+ comparisons to see if either edge contains the point.
64
+ """
32
65
def __init__ (self , x_shift : int = 0 , y_shift : int = 0 ):
33
66
super ().__init__ ()
34
67
self ._cfg : Config = Config ()
@@ -37,7 +70,7 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
37
70
self ._screen : pg .Surface = pg .display .get_surface ()
38
71
self ._highlighted_edge = None
39
72
40
- # Create the dots
73
+ # Create the dots (a 2D list of Dot objects)
41
74
self ._dots : list [list [Dot ]] = []
42
75
for r in range (0 , self ._cfg .CELL_ROWS + 1 ):
43
76
row = []
@@ -56,7 +89,7 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
56
89
dot .draw ()
57
90
self ._dots .append (row )
58
91
59
- # Create the cells
92
+ # Create the cells (a 2D list of Cell objects)
60
93
self ._cells : list [list [Cell ]] = []
61
94
for r in range (0 , self ._cfg .CELL_ROWS ):
62
95
row = []
@@ -75,7 +108,7 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
75
108
cell .draw ()
76
109
self ._cells .append (row )
77
110
78
- # Create the edges
111
+ # Create the edges (a 2D list of Edge objects)
79
112
# Superrows and supercolumns are rows and columns of a collection
80
113
# of one dot, two edges, and one cell. This allows for easy grouping
81
114
# and lookup of edges based on mouse location.
@@ -98,7 +131,11 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
98
131
)
99
132
h_edge .draw ()
100
133
101
- # Establish cell to edge relationships
134
+ # Establish cell to edge relationships - for checking whether a
135
+ # cell is captured by a user, we need to know which cells the
136
+ # edge touches. An edge always touches one or two cells. Edges
137
+ # that touch one cell are the edges that make up the exterior
138
+ # of the board.
102
139
# top superrow
103
140
if h_edge and r == 0 :
104
141
h_edge .cell2 = self ._cells [r ][c ]
@@ -130,7 +167,10 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
130
167
)
131
168
v_edge .draw ()
132
169
133
- # Establish cell to edge relationships
170
+ # Establish cell to edge relationships - for checking whether a
171
+ # cell is captured by a user, we need to know which edges the
172
+ # cell touches. A cell always touches four edges: top, bottom,
173
+ # left and right.
134
174
# left supercolumn
135
175
if v_edge and c == 0 :
136
176
v_edge .cell2 = self ._cells [r ][c ]
@@ -170,6 +210,7 @@ def __init__(self, x_shift: int=0, y_shift: int=0):
170
210
self .draw ()
171
211
172
212
def get_edge (self , pos : tuple ) -> Edge :
213
+ """Retrieve the edge containing pos."""
173
214
# To look up the edge to see if it contains the x,y you can quickly
174
215
# retrieve the tuple of edges that possibly contains x,y by:
175
216
# row = y // (dd + ch)
@@ -178,12 +219,14 @@ def get_edge(self, pos: tuple) -> Edge:
178
219
# x,y
179
220
try :
180
221
x , y = pos
222
+ # Determine the superrow and supercolumn containing the point
181
223
row = (y - self ._y_shift - self ._cfg .GUTTER_WIDTH ) // \
182
224
(self ._cfg .DOT_DIA + self ._cfg .CELL_HEIGHT )
183
225
col = (x - self ._x_shift - self ._cfg .GUTTER_WIDTH ) // \
184
226
(self ._cfg .DOT_DIA + self ._cfg .CELL_WIDTH )
185
227
edges = self ._edges [row ][col ]
186
228
229
+ # Check to see if either edge contains the point
187
230
for edge in edges :
188
231
if edge .collidepoint (pos ):
189
232
return edge
@@ -192,6 +235,7 @@ def get_edge(self, pos: tuple) -> Edge:
192
235
return None
193
236
194
237
def highlight_edge (self , edge : Edge ) -> None :
238
+ """Highlight the specified edge."""
195
239
if not edge .captured and self ._highlighted_edge != edge :
196
240
if self ._highlighted_edge :
197
241
pg .draw .rect (self ._screen ,
@@ -203,19 +247,22 @@ def highlight_edge(self, edge: Edge) -> None:
203
247
self ._highlighted_edge = edge
204
248
205
249
def unhighlight_edge (self ) -> None :
250
+ """Clear the highlighted edge so it is no longer highlighted."""
206
251
if self ._highlighted_edge :
207
252
pg .draw .rect (self ._screen , EDGE_COLOR_DEFAULT ,
208
253
self ._highlighted_edge )
209
254
pg .display .update (self ._highlighted_edge )
210
255
self ._highlighted_edge = None
211
256
212
257
def capture_edge (self , edge : Edge ) -> None :
258
+ """Capture the specified edge."""
213
259
self ._highlighted_edge = None
214
260
edge .captured = True
215
261
pg .draw .rect (self ._screen , EDGE_COLOR_CAPTURED , edge )
216
262
pg .display .update (edge )
217
263
218
264
def draw (self ) -> None :
265
+ """Draw the entire board."""
219
266
pg .display .flip ()
220
267
221
268
def __str__ (self ) -> str :
0 commit comments