Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import pygame
- import random
- from itertools import count
- from pygame.sprite import Group, Sprite
- # Interface
- class State:
- def __init__(self, engine):
- self.engine = engine
- def on_draw(self, surface): pass
- def on_event(self, event): pass
- def on_update(self, delta, ticks): pass
- # Engine
- class DisplayEngine:
- def __init__(self, caption, width, height, flags=0):
- # Basic Pygame Setup
- pygame.display.set_caption(caption)
- self.surface = pygame.display.set_mode((width, height), flags)
- self.rect = self.surface.get_rect()
- self.clock = pygame.time.Clock()
- self.running = True
- self.delta = 0
- self.fps = 60
- # Handle what state is active.
- self._state = State(self)
- self.next_state = None
- # Main Loop
- def run(self, state=None):
- if state:
- self._state = state
- while self.running:
- # State Changer
- if self.next_state:
- self._state = self.next_state
- self.next_state = None
- # Event Loop
- for event in pygame.event.get():
- # Just send the events to state to handle
- self._state.on_event(event)
- ticks = pygame.time.get_ticks()
- self._state.on_draw(self.surface)
- self._state.on_update(self.delta, ticks)
- pygame.display.flip()
- self.delta = self.clock.tick(self.fps)
- def quit(self):
- self.running = False
- class SimpleSprite(Sprite):
- def __init__(self, image):
- super().__init__()
- self.image = image
- self.rect = image.get_rect()
- class Callback:
- def __init__(self, callback, user_data=None):
- self.parent = None
- self.callback = callback
- self.user_data = user_data
- def link(self, parent):
- self.parent = parent
- return self
- def call(self):
- self.callback(self)
- class Pen:
- def __init__(self, font, color):
- self.font = font
- self.color = color
- def render(self, text):
- return self.font.render(text, 1, self.color)
- def write(self, text):
- return SimpleSprite(self.render(text))
- class ButtonImages:
- def __init__(self, normal, hover, pushed):
- self.normal = normal
- self.hover = hover
- self.pushed = pushed
- class ButtonGroup:
- def __init__(self):
- self.buttons = Group()
- self.text = Group()
- def add(self, button):
- self.buttons.add(button)
- self.text.add(button.tsprite)
- def draw(self, surface):
- self.buttons.draw(surface)
- self.text.draw(surface)
- class Button(Sprite):
- def __init__(self, images, pen, text, position, callback):
- super().__init__()
- self.pen = pen
- self.images = images
- self.image = images.normal
- self.rect = self.images.normal.get_rect(topleft=position)
- self.is_mouse_over = False
- self.is_pushed = False
- self.callback = callback.link(self)
- self.update_text(text)
- def mouse_over(self, event):
- self.is_mouse_over = self.rect.collidepoint(event.pos)
- self.update_image()
- def click(self, event):
- self.mouse_over(event)
- if self.is_mouse_over:
- #self.is_pushed = False
- self.callback.call()
- def update_image(self):
- if self.is_pushed:
- self.image = self.images.pushed
- elif self.is_mouse_over:
- self.image = self.images.hover
- else:
- self.image = self.images.normal
- def update_text(self, text):
- self.tsprite = self.pen.write(text)
- self.tsprite.rect.center = self.rect.center
- # Store images. Because you want to create/load, convert, and/or size once.
- class Images:
- def __init__(self):
- self.dice = self.create_dice(40, 'snow', 'black', 3)
- self.hdice = self.create_dice(40, 'skyblue', 'black', 3)
- self.sdice = self.create_dice(40, 'lightgreen', 'black', 3)
- self.button_images = self.create_button((100, 30), 'blue', 'dodgerblue', 'navy')
- def create_dice(self, size, color, dot_color, dot_size):
- surface = pygame.Surface((size, size))
- surface.fill(color)
- rect = surface.get_rect()
- inner = rect.inflate(-rect.centerx, -rect.centery)
- images = []
- for i in range(1, 7):
- s = surface.copy()
- if i in [1, 3, 5]:
- pygame.draw.circle(s, dot_color, rect.center, dot_size)
- if i != 1: # 2-6
- pygame.draw.circle(s, dot_color, inner.topleft, dot_size)
- pygame.draw.circle(s, dot_color, inner.bottomright, dot_size)
- if i > 3:
- pygame.draw.circle(s, dot_color, inner.topright, dot_size)
- pygame.draw.circle(s, dot_color, inner.bottomleft, dot_size)
- if i == 6:
- pygame.draw.circle(s, dot_color, inner.midleft, dot_size)
- pygame.draw.circle(s, dot_color, inner.midright, dot_size)
- images.append(s)
- return images
- def create_button(self, size, color, hcolor, pcolor):
- surface = pygame.Surface(size)
- surface.fill(color)
- hsurface = surface.copy()
- hsurface.fill(hcolor)
- psurface = surface.copy()
- psurface.fill(pcolor)
- return ButtonImages(surface, hsurface, psurface)
- class Die(Sprite):
- def __init__(self, images, position):
- super().__init__()
- # These are just reference
- self.images = images
- self.rect = images[0][0].get_rect(topleft=position)
- self.is_mouse_over = False
- self.is_selected = False
- self.roll()
- def roll(self):
- self.value = random.randint(1, 6)
- self.is_selected = False
- self.update_image()
- def mouse_over(self, mpos):
- self.is_mouse_over = self.rect.collidepoint(mpos)
- self.update_image()
- def selected(self):
- if self.is_mouse_over:
- self.is_selected = not self.is_selected
- self.update_image()
- def update_image(self):
- if self.is_selected:
- self.image = self.images[2][self.value - 1]
- elif self.is_mouse_over:
- self.image = self.images[1][self.value - 1]
- else:
- self.image = self.images[0][self.value - 1]
- class DisplayLines:
- def __init__(self, pen, position):
- self.position = position
- self.lines = []
- self.pen = pen
- def add(self, text):
- self.lines.append(self.pen.render(text))
- def clear(self):
- self.lines = []
- def draw(self, surface):
- y = count(self.position[1], self.pen.font.get_linesize() + 2)
- for line in self.lines:
- surface.blit(line, (self.position[0], next(y)))
- class GameState(State):
- def __init__(self, engine):
- super().__init__(engine)
- self.dice_space = 50
- self.dice_fromedgex = 30
- self.dice_fromedgey = 30
- self.images = Images()
- self.roll_button = self.create_roll_button()
- self.bgroup = ButtonGroup()
- self.dice = Group()
- self.set_up()
- def create_roll_button(self):
- pen = Pen(pygame.font.Font(None, 28), 'snow')
- pos = self.dice_space * 5 - 100 + self.dice_fromedgex, 80
- callback = Callback(self.push_rolled)
- return Button(self.images.button_images, pen, "Roll", pos, callback)
- def set_up(self):
- images = self.images.dice, self.images.hdice, self.images.sdice
- for i in range(5):
- pos = self.dice_space * i + self.dice_fromedgex, self.dice_fromedgey
- self.dice.add(Die(images, pos))
- self.bgroup.add(self.roll_button)
- pos = self.engine.rect.centerx, 10
- pen = Pen(pygame.font.Font(None, 22), 'lawngreen')
- self.lines = DisplayLines(pen, pos)
- self.get_data()
- def push_rolled(self, callback):
- for d in self.dice:
- if d.is_selected:
- d.roll()
- self.get_data()
- def get_data(self):
- self.lines.clear()
- values = [d.value for d in self.dice]
- set_v = set(values)
- if len(set_v) == 1:
- self.lines.add("Yahtzee")
- self.lines.add("4 of a kind")
- self.lines.add("3 of a kind")
- if len(set_v) == 2:
- for v in set_v:
- if values.count(v) == 4:
- self.lines.add("4 of a kind")
- elif values.count(v) == 3:
- self.lines.add("Fullhouse")
- self.lines.add("3 of a kind")
- if len(set_v) == 3:
- data = [values.count(i) for i in set_v]
- if 3 in data:
- self.lines.add("3 of a kind")
- if len(set_v) == 4:
- data = list(set_v)
- data.sort()
- if ([1, 2, 3, 4] == data or
- [2, 3, 4, 5] == data or
- [3, 4, 5, 6] == data):
- self.lines.add("small straight")
- if len(set_v) == 5:
- data = list(set_v)
- data.sort()
- if [1, 2, 3, 4, 5] == data or [2, 3, 4, 5, 6] == data:
- self.lines.add("large straight")
- if ([1, 2, 3, 4] == data[:-1] or
- [2, 3, 4, 5] == data[:-1] or
- [2, 3, 4, 5] == data[1:] or
- [3, 4, 5, 6] == data[1:]):
- self.lines.add("small straight")
- # Override. From state interface
- def on_draw(self, surface):
- surface.fill('gray10')
- self.dice.draw(surface)
- self.bgroup.draw(surface)
- self.lines.draw(surface)
- # Override. From state interface
- def on_event(self, event):
- if event.type == pygame.QUIT:
- self.engine.quit()
- elif event.type == pygame.MOUSEMOTION:
- for d in self.dice:
- d.mouse_over(event.pos)
- for b in self.bgroup.buttons:
- b.mouse_over(event)
- elif event.type == pygame.MOUSEBUTTONDOWN:
- if event.button == 1:
- self.roll_button.click(event)
- for d in self.dice:
- d.selected()
- if __name__ == '__main__':
- pygame.init()
- engine = DisplayEngine("Dice", 800, 600)
- game = GameState(engine)
- engine.run(game)
- pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement