diff options
Diffstat (limited to 'game.py')
-rw-r--r-- | game.py | 282 |
1 files changed, 282 insertions, 0 deletions
@@ -0,0 +1,282 @@ +import pygame
+import numpy as np
+import sys
+
+
+class Game:
+ def __init__(self):
+ self.grid_size = 10 # default
+ if len(sys.argv) > 1:
+ self.grid_size = int(sys.argv[1])
+
+ # It turns out that there are nice structures when setting ~0.75 walls per slot
+ self.start_walls = int(0.75 * self.grid_size ** 2)
+
+ self.accept_clicks = True
+
+ # variables for the boxes for each player (x would be computer)
+ self.a_boxes = 0
+ self.b_boxes = 0
+ self.x_boxes = 0
+
+ self.turn = "X"
+ self.caption = "'s turn "
+
+ # 0 empty 1 is A 2 is B and 3 is X
+ self.grid_status = np.zeros((self.grid_size, self.grid_size), np.int)
+ self.upper_walls_set_flags = np.zeros((self.grid_size, self.grid_size), np.dtype(bool))
+ self.left_walls_set_flags = np.zeros((self.grid_size, self.grid_size), np.dtype(bool))
+
+ # set the outer walls
+ for column in range(self.grid_size):
+ for row in range(self.grid_size):
+ if column == 0:
+ self.left_walls_set_flags[column][row] = True
+ if row == 0:
+ self.upper_walls_set_flags[column][row] = True
+
+ # initialize pygame
+ pygame.init()
+
+ # set the display size (one slot has 30x30 pixels; Walls: 4x26 Box: 26x26)
+ self.screen = pygame.display.set_mode([30 * self.grid_size + 4, 30 * self.grid_size + 4])
+
+ # load all images
+ self.empty = pygame.image.load("pics/empty.png")
+ self.A = pygame.image.load("pics/A.png")
+ self.B = pygame.image.load("pics/B.png")
+ self.X = pygame.image.load("pics/X.png")
+ self.block = pygame.image.load("pics/block.png")
+ self.lineX = pygame.image.load("pics/lineX.png")
+ self.lineXempty = pygame.image.load("pics/lineXempty.png")
+ self.lineY = pygame.image.load("pics/lineY.png")
+ self.lineYempty = pygame.image.load("pics/lineYempty.png")
+
+ tries = 0
+ # set the start walls randomly but do not create any opportunity to directly close boxes
+ while self.start_walls > 0 and tries < 4*self.grid_size**2:
+ x = np.random.randint(self.grid_size)
+ y = np.random.randint(self.grid_size)
+ up = np.random.randint(2)
+
+ if up:
+ if not self.upper_walls_set_flags[x][y] \
+ and self.get_number_of_walls(x, y) < 2 \
+ and self.get_number_of_walls(x, y - 1) < 2:
+ self.upper_walls_set_flags[x][y] = True
+ self.start_walls -= 1
+ else:
+ if not self.left_walls_set_flags[x][y] \
+ and self.get_number_of_walls(x, y) < 2 \
+ and self.get_number_of_walls(x - 1, y) < 2:
+ self.left_walls_set_flags[x][y] = True
+ self.start_walls -= 1
+
+ tries += 1
+
+ # now it's the first players turn
+ self.turn = "A"
+ self.show()
+
+ while True:
+ # go through all events and check the types
+ for event in pygame.event.get():
+ # quit the game when the player closes it
+ if event.type == pygame.QUIT:
+ pygame.quit()
+ exit(0)
+
+ # left click
+ elif event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
+ if not self.accept_clicks:
+ continue
+
+ # get the current position of the cursor
+ x = pygame.mouse.get_pos()[0]
+ y = pygame.mouse.get_pos()[1]
+
+ # check whether it was a not set wall that was clicked
+ wall_x, wall_y = self.get_wall(x, y)
+
+ if not (wall_x >= 0 and wall_y >= 0):
+ continue
+
+ upper_wall = wall_y % 30 == 0
+
+ if upper_wall:
+ if not self.upper_walls_set_flags[wall_x//30][wall_y//30]:
+ self.upper_walls_set_flags[wall_x//30][wall_y//30] = True
+ self.screen.blit(self.lineX, (wall_x, wall_y))
+ else:
+ continue
+ else:
+ if not self.left_walls_set_flags[wall_x//30][wall_y//30]:
+ self.left_walls_set_flags[wall_x//30][wall_y//30] = True
+ self.screen.blit(self.lineY, (wall_x, wall_y))
+ else:
+ continue
+
+ if not self.set_all_slots() > 0:
+ if self.turn == "A":
+ self.turn = "B"
+ elif self.turn == "B":
+ self.turn = "A"
+
+ if self.won():
+ self.accept_clicks = False
+
+ else:
+
+ # set the display caption
+ pygame.display.set_caption(self.turn + self.caption + " A:" + str(
+ self.a_boxes) + " B:" + str(self.b_boxes))
+
+ # update the players screen
+ pygame.display.flip()
+
+ def get_number_of_walls(self, slot_column, slot_row):
+ """
+ Get the number of set walls around the passed slot
+ :param slot_column: x of the slot
+ :param slot_row: y of the slot
+ :return: number of set walls
+ """
+ number_of_walls = 0
+
+ if slot_column == self.grid_size - 1:
+ number_of_walls += 1
+ elif self.left_walls_set_flags[slot_column + 1][slot_row]:
+ number_of_walls += 1
+
+ if slot_row == self.grid_size - 1:
+ number_of_walls += 1
+ elif self.upper_walls_set_flags[slot_column][slot_row + 1]:
+ number_of_walls += 1
+
+ if self.left_walls_set_flags[slot_column][slot_row]:
+ number_of_walls += 1
+
+ if self.upper_walls_set_flags[slot_column][slot_row]:
+ number_of_walls += 1
+
+ return number_of_walls
+
+ @staticmethod
+ def get_wall(pos_x, pos_y):
+ rest_x = pos_x % 30
+ rest_y = pos_y % 30
+
+ wall_slot_x = pos_x//30
+ wall_slot_y = pos_y//30
+
+ # in a corner
+ if rest_x < 4 and rest_y < 4:
+ return -1, -1
+
+ if rest_x < 4:
+ # is left wall of the slot
+ return wall_slot_x*30, wall_slot_y*30 + 4
+
+ if rest_y < 4:
+ # is upper wall of the slot
+ return wall_slot_x*30 + 4, wall_slot_y*30
+
+ # inside the box => not a wall
+ return -1, -1
+
+ def set_all_slots(self):
+ """
+ Find all newly closed boxes and close them for the current player
+ :return: number of closed boxes
+ """
+ to_return = 0
+
+ for column_ in range(self.grid_size):
+ for row_ in range(self.grid_size):
+ if self.grid_status[column_][row_] != 0 or self.get_number_of_walls(column_, row_) < 4:
+ continue
+
+ if self.turn == "A":
+ self.grid_status[column_][row_] = 1
+ self.screen.blit(self.A, (column_ * 30 + 4, row_ * 30 + 4))
+ self.a_boxes += 1
+ elif self.turn == "B":
+ self.grid_status[column_][row_] = 2
+ self.screen.blit(self.B, (column_ * 30 + 4, row_ * 30 + 4))
+ self.b_boxes += 1
+ elif self.turn == "X":
+ self.grid_status[column_][row_] = 3
+ self.screen.blit(self.X, (column_ * 30 + 4, row_ * 30 + 4))
+ self.x_boxes += 1
+
+ to_return += 1
+
+ return to_return
+
+ def won(self):
+ """
+ Check whether the game was finished
+ If so change the caption to display the winner
+ :return: won or not
+ """
+ if self.a_boxes + self.b_boxes + self.x_boxes == self.grid_size ** 2:
+ if self.a_boxes < self.b_boxes:
+ won_caption = "Player B won! Congrats"
+ elif self.b_boxes < self.a_boxes:
+ won_caption = "Player A won! Congrats"
+ else:
+ won_caption = "It's a tie!"
+
+ # set the display caption
+ pygame.display.set_caption(won_caption)
+
+ # update the players screen
+ pygame.display.flip()
+
+ return True
+ else:
+ return False
+
+ def show(self):
+ """
+ Reload the screen
+ Use the current grid and wall information to
+ update the players screen
+ """
+ self.screen.fill(0)
+
+ # loop over all slots
+ for column in range(self.grid_size):
+ for row in range(self.grid_size):
+ x, y = column * 30, row * 30
+ self.screen.blit(self.block, (x, y))
+ x += 4
+ if not self.upper_walls_set_flags[column][row]:
+ self.screen.blit(self.lineXempty, (x, y))
+ else:
+ self.screen.blit(self.lineX, (x, y))
+ x -= 4
+ y += 4
+ if not self.left_walls_set_flags[column][row]:
+ self.screen.blit(self.lineYempty, (x, y))
+ else:
+ self.screen.blit(self.lineY, (x, y))
+
+ # calculate x and y in pixels
+ x, y = column * 30 + 4, row * 30 + 4
+
+ if self.grid_status[column][row] == 0:
+ self.screen.blit(self.empty, (x, y))
+ elif self.grid_status[column][row] == 1:
+ self.screen.blit(self.A, (x, y))
+ elif self.grid_status[column][row] == 2:
+ self.screen.blit(self.B, (x, y))
+ elif self.grid_status[column][row] == 3:
+ self.screen.blit(self.X, (x, y))
+
+ pygame.display.set_caption(self.turn + self.caption + " A:" + str(self.a_boxes) + " B:" + str(
+ self.b_boxes))
+ pygame.display.flip()
+
+
+game = Game() # start a game
\ No newline at end of file |