Compare commits
5 Commits
157b7e3c90
...
44cb7a697b
Author | SHA1 | Date |
---|---|---|
|
44cb7a697b | |
|
d815281abc | |
|
9ce1ae0ff7 | |
|
de5af7cb44 | |
|
b7eba38f0f |
|
@ -1,9 +1,9 @@
|
||||||
# About
|
# About
|
||||||
This is just a Sudoku program written in python using the PyQt5 library. It's supposed to be a learning experience
|
This is just a Sudoku program written in python using the PySide2 library. It's supposed to be a learning experience
|
||||||
about the graphics system of PyQt. The goal(?) is to make it as animated as possible.
|
about the graphics system of PyQt.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
Requires `Python 3`, `PyQt5`, and `Numpy`.
|
Requires `Python 3`, `PySide2`, and `Numpy`.
|
||||||
|
|
||||||
Use the requirements.txt to install the dependencies.
|
Use the requirements.txt to install the dependencies.
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,12 @@ def generate_completed_grid(n):
|
||||||
|
|
||||||
def generate_dig_sequence(difficulty):
|
def generate_dig_sequence(difficulty):
|
||||||
if difficulty <= 1:
|
if difficulty <= 1:
|
||||||
|
# Random Digging
|
||||||
random_number = list(range(81))
|
random_number = list(range(81))
|
||||||
while len(random_number) > 0:
|
while len(random_number) > 0:
|
||||||
yield random_number.pop(random.randint(0, len(random_number)-1))
|
yield random_number.pop(random.randint(0, len(random_number)-1))
|
||||||
elif difficulty == 2:
|
elif difficulty == 2:
|
||||||
|
# Skip one cell
|
||||||
current = 0
|
current = 0
|
||||||
while current < 162:
|
while current < 162:
|
||||||
actual = current % 81
|
actual = current % 81
|
||||||
|
@ -57,6 +59,7 @@ def generate_dig_sequence(difficulty):
|
||||||
yield (row+1) * 9 - 1 - (actual % 9) % 81
|
yield (row+1) * 9 - 1 - (actual % 9) % 81
|
||||||
current += 2
|
current += 2
|
||||||
elif difficulty == 3:
|
elif difficulty == 3:
|
||||||
|
# S wandering
|
||||||
current = 0
|
current = 0
|
||||||
while current < 81:
|
while current < 81:
|
||||||
row = int(current / 9)
|
row = int(current / 9)
|
||||||
|
@ -66,6 +69,7 @@ def generate_dig_sequence(difficulty):
|
||||||
yield (row+1) * 9 - 1 - (current % 9)
|
yield (row+1) * 9 - 1 - (current % 9)
|
||||||
current += 1
|
current += 1
|
||||||
elif difficulty == 4:
|
elif difficulty == 4:
|
||||||
|
# Left-to-right, top-to-bottom
|
||||||
current = 0
|
current = 0
|
||||||
while current < 81:
|
while current < 81:
|
||||||
yield current
|
yield current
|
||||||
|
|
|
@ -3,7 +3,7 @@ of the boards."""
|
||||||
|
|
||||||
from PySide2.QtGui import QPen
|
from PySide2.QtGui import QPen
|
||||||
from PySide2.QtWidgets import QSizePolicy, QGraphicsWidget
|
from PySide2.QtWidgets import QSizePolicy, QGraphicsWidget
|
||||||
from PySide2.QtCore import (QAbstractAnimation, Qt, QLineF, QPropertyAnimation, Property, Signal, QSizeF, QRectF)
|
from PySide2.QtCore import (QAbstractAnimation, Qt, QLineF, QPropertyAnimation, Property, Signal, QSizeF, QRectF, QTimer)
|
||||||
|
|
||||||
from . import sudoku_graphics as sdk_grap
|
from . import sudoku_graphics as sdk_grap
|
||||||
from . import menu_graphics as menu_grap
|
from . import menu_graphics as menu_grap
|
||||||
|
@ -147,7 +147,7 @@ class GameBoard(BoxBoard):
|
||||||
self.numring = sdk_grap.NumberRing(parent=self)
|
self.numring = sdk_grap.NumberRing(parent=self)
|
||||||
self.playmenu = sdk_grap.PlayMenu(parent=self)
|
self.playmenu = sdk_grap.PlayMenu(parent=self)
|
||||||
|
|
||||||
self.gamegrid.setFocus(Qt.MouseFocusReason)
|
#self.gamegrid.setFocus(Qt.MouseFocusReason)
|
||||||
self.show_grid(False)
|
self.show_grid(False)
|
||||||
self.show_playmenu(False)
|
self.show_playmenu(False)
|
||||||
|
|
||||||
|
@ -161,6 +161,10 @@ class GameBoard(BoxBoard):
|
||||||
self.anim.finished.connect(lambda: self.show_playmenu(True))
|
self.anim.finished.connect(lambda: self.show_playmenu(True))
|
||||||
self.toggle_anim(True)
|
self.toggle_anim(True)
|
||||||
|
|
||||||
|
self.refocus_timer = QTimer()
|
||||||
|
self.refocus_timer.timeout.connect(self.game_refocus)
|
||||||
|
self.refocus_timer.setSingleShot(True)
|
||||||
|
|
||||||
def show_number_ring(self, x=0, y=0, scribbling=False):
|
def show_number_ring(self, x=0, y=0, scribbling=False):
|
||||||
"""Display the Number Ring if it is not visible, while setting the focus to it
|
"""Display the Number Ring if it is not visible, while setting the focus to it
|
||||||
|
|
||||||
|
@ -174,6 +178,7 @@ class GameBoard(BoxBoard):
|
||||||
True to set Scribble mode, False otherwise
|
True to set Scribble mode, False otherwise
|
||||||
"""
|
"""
|
||||||
if not self.numring.isVisible():
|
if not self.numring.isVisible():
|
||||||
|
self.game_unfocus()
|
||||||
self.numring.setPos(x, y)
|
self.numring.setPos(x, y)
|
||||||
self.numring.setVisible(True)
|
self.numring.setVisible(True)
|
||||||
self.numring.setFocus()
|
self.numring.setFocus()
|
||||||
|
@ -201,9 +206,17 @@ class GameBoard(BoxBoard):
|
||||||
"""Enable the grid and give it grid focus
|
"""Enable the grid and give it grid focus
|
||||||
"""
|
"""
|
||||||
self.gamegrid.set_disabled(False)
|
self.gamegrid.set_disabled(False)
|
||||||
self.gamegrid.setFocus()
|
#self.gamegrid.setFocus()
|
||||||
self.gamegrid.scribbling = self.numring.scribbling # To update the grid scribbling mode
|
self.gamegrid.scribbling = self.numring.scribbling # To update the grid scribbling mode
|
||||||
|
|
||||||
|
def game_unfocus(self):
|
||||||
|
"""Enable the grid and give it grid focus
|
||||||
|
"""
|
||||||
|
self.gamegrid.set_disabled(True)
|
||||||
|
#self.gamegrid.setFocus()
|
||||||
|
#self.gamegrid.scribbling = self.numring.scribbling # To update the grid scribbling mode
|
||||||
|
|
||||||
|
|
||||||
def show_grid(self, state):
|
def show_grid(self, state):
|
||||||
"""Show the grid, if it is not; Hide the grid, if it is.
|
"""Show the grid, if it is not; Hide the grid, if it is.
|
||||||
Note: Animation only plays when showing the grid.
|
Note: Animation only plays when showing the grid.
|
||||||
|
|
|
@ -64,6 +64,7 @@ class AnimBox(QGraphicsObject):
|
||||||
|
|
||||||
self.line_order = [self.up, self.right, self.down, self.left]
|
self.line_order = [self.up, self.right, self.down, self.left]
|
||||||
|
|
||||||
|
self.accepted_buttons = Qt.LeftButton
|
||||||
self.set_freeze(False)
|
self.set_freeze(False)
|
||||||
|
|
||||||
self.length = 0
|
self.length = 0
|
||||||
|
@ -85,7 +86,7 @@ class AnimBox(QGraphicsObject):
|
||||||
self.setAcceptedMouseButtons(Qt.NoButton)
|
self.setAcceptedMouseButtons(Qt.NoButton)
|
||||||
self.setAcceptHoverEvents(False)
|
self.setAcceptHoverEvents(False)
|
||||||
else:
|
else:
|
||||||
self.setAcceptedMouseButtons(Qt.LeftButton)
|
self.setAcceptedMouseButtons(self.accepted_buttons)
|
||||||
self.setAcceptHoverEvents(True)
|
self.setAcceptHoverEvents(True)
|
||||||
|
|
||||||
def toggle_anim(self, toggling):
|
def toggle_anim(self, toggling):
|
||||||
|
@ -201,7 +202,7 @@ class RingButton(AnimBox):
|
||||||
buttonClicked: Signal(str)
|
buttonClicked: Signal(str)
|
||||||
Emitted when it is clicked. Sends the text of the button
|
Emitted when it is clicked. Sends the text of the button
|
||||||
"""
|
"""
|
||||||
buttonClicked = Signal(str)
|
buttonClicked = Signal(str, int)
|
||||||
|
|
||||||
# Initialisation
|
# Initialisation
|
||||||
def __init__(self, x, y, width, height, text, parent=None):
|
def __init__(self, x, y, width, height, text, parent=None):
|
||||||
|
@ -216,6 +217,7 @@ class RingButton(AnimBox):
|
||||||
super().__init__(x, y, width, height, parent=parent)
|
super().__init__(x, y, width, height, parent=parent)
|
||||||
self.text = text
|
self.text = text
|
||||||
self.transparent = False
|
self.transparent = False
|
||||||
|
self.accepted_buttons = self.accepted_buttons | Qt.RightButton
|
||||||
|
|
||||||
def set_transparent(self, state):
|
def set_transparent(self, state):
|
||||||
"""Make the button transparent
|
"""Make the button transparent
|
||||||
|
@ -252,7 +254,7 @@ class RingButton(AnimBox):
|
||||||
"""
|
"""
|
||||||
event.accept()
|
event.accept()
|
||||||
self.toggle_anim(False)
|
self.toggle_anim(False)
|
||||||
self.buttonClicked.emit(self.text)
|
self.buttonClicked.emit(self.text, event.button())
|
||||||
|
|
||||||
|
|
||||||
class MenuButton(AnimBox):
|
class MenuButton(AnimBox):
|
||||||
|
|
|
@ -84,23 +84,19 @@ class TimerDisplayer(QGraphicsWidget):
|
||||||
|
|
||||||
|
|
||||||
class DifficultyDisplayer(QGraphicsWidget):
|
class DifficultyDisplayer(QGraphicsWidget):
|
||||||
<<<<<<< HEAD
|
|
||||||
notFocus = Signal()
|
|
||||||
difficultySelected = Signal(str)
|
|
||||||
=======
|
|
||||||
"""Display the current difficulty. Clicking on it displays the difficulty menu.
|
"""Display the current difficulty. Clicking on it displays the difficulty menu.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
notFocus: pyqtSignal
|
notFocus: Signal
|
||||||
Emitted when it loses focus
|
Emitted when it loses focus
|
||||||
|
|
||||||
difficultySelected = pyqtSignal(str)
|
difficultySelected = Signal(str)
|
||||||
Emitted when a difficulty is selected. Emits the selected difficulty
|
Emitted when a difficulty is selected. Emits the selected difficulty
|
||||||
"""
|
"""
|
||||||
notFocus = pyqtSignal()
|
notFocus = Signal()
|
||||||
difficultySelected = pyqtSignal(str)
|
difficultySelected = Signal(str)
|
||||||
>>>>>>> Document menu_graphics
|
menuClicked = Signal(str)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
"""Create the box and the text.
|
"""Create the box and the text.
|
||||||
|
@ -119,6 +115,7 @@ class DifficultyDisplayer(QGraphicsWidget):
|
||||||
self.diff_menu = DifficultyMenu(self.width, self.height, self)
|
self.diff_menu = DifficultyMenu(self.width, self.height, self)
|
||||||
self.diff_menu.setY(-self.diff_menu.height)
|
self.diff_menu.setY(-self.diff_menu.height)
|
||||||
self.diff_menu.setVisible(False)
|
self.diff_menu.setVisible(False)
|
||||||
|
self.diff_menu.menuClicked.connect(self.menuClicked.emit)
|
||||||
|
|
||||||
self.box_pen = QPen()
|
self.box_pen = QPen()
|
||||||
self.box_pen.setColor(Qt.white)
|
self.box_pen.setColor(Qt.white)
|
||||||
|
@ -167,6 +164,7 @@ class DifficultyDisplayer(QGraphicsWidget):
|
||||||
if not self.diff_menu.isVisible():
|
if not self.diff_menu.isVisible():
|
||||||
self.diff_menu.setFocus()
|
self.diff_menu.setFocus()
|
||||||
self.diff_menu.setVisible(True)
|
self.diff_menu.setVisible(True)
|
||||||
|
#self.clicked.emit()
|
||||||
else:
|
else:
|
||||||
self.diff_menu.setVisible(False)
|
self.diff_menu.setVisible(False)
|
||||||
self.notFocus.emit()
|
self.notFocus.emit()
|
||||||
|
@ -247,7 +245,7 @@ class DifficultyMenu(QGraphicsWidget):
|
||||||
return QRectF(0, 0, self.width, self.height)
|
return QRectF(0, 0, self.width, self.height)
|
||||||
|
|
||||||
def clicked_on(self, string):
|
def clicked_on(self, string):
|
||||||
"""Emits the menuCLicked signal with the selected difficulty, when one of the buttons is pressed.
|
"""Emits the menuClicked signal with the selected difficulty, when one of the buttons is pressed.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -192,7 +192,7 @@ class SudokuGrid(BaseSudokuItem):
|
||||||
|
|
||||||
self.setAcceptHoverEvents(True)
|
self.setAcceptHoverEvents(True)
|
||||||
self.setAcceptedMouseButtons(Qt.LeftButton)
|
self.setAcceptedMouseButtons(Qt.LeftButton)
|
||||||
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
|
#self.setFlag(QGraphicsItem.ItemIsFocusable, True)
|
||||||
self.set_disabled(False)
|
self.set_disabled(False)
|
||||||
|
|
||||||
# Set up the animation
|
# Set up the animation
|
||||||
|
@ -326,18 +326,19 @@ class SudokuGrid(BaseSudokuItem):
|
||||||
|
|
||||||
if not self.sudoku_grid.get_cell_status(self.mouse_h, self.mouse_w) == sdk.FIXED:
|
if not self.sudoku_grid.get_cell_status(self.mouse_h, self.mouse_w) == sdk.FIXED:
|
||||||
self.buttonClicked.emit(w, h, self.scribbling)
|
self.buttonClicked.emit(w, h, self.scribbling)
|
||||||
|
self.set_disabled(True)
|
||||||
else:
|
else:
|
||||||
self.buttonClicked.emit(0, 0, self.scribbling)
|
self.buttonClicked.emit(0, 0, self.scribbling)
|
||||||
|
|
||||||
def focusInEvent(self, event):
|
#def focusInEvent(self, event):
|
||||||
"""Reimplemented from QGraphicsObject. Unfreeze the grid on focus
|
"""Reimplemented from QGraphicsObject. Unfreeze the grid on focus
|
||||||
"""
|
"""
|
||||||
self.set_disabled(False)
|
#self.set_disabled(False)
|
||||||
|
|
||||||
def focusOutEvent(self, event):
|
#def focusOutEvent(self, event):
|
||||||
"""Reimplemented from QGraphicsObject. Freeze the grid when out of focus
|
"""Reimplemented from QGraphicsObject. Freeze the grid when out of focus
|
||||||
"""
|
"""
|
||||||
self.set_disabled(True)
|
#self.set_disabled(True)
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
"""Reimplemented from QGraphicsObject. Check if scribble key is held, toggling on scribbling mode.
|
"""Reimplemented from QGraphicsObject. Check if scribble key is held, toggling on scribbling mode.
|
||||||
|
@ -465,7 +466,7 @@ class NumberRing(BaseSudokuItem):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def send_button_press(self, val):
|
def send_button_press(self, val, btn):
|
||||||
"""Emits the keyPressed signal if any of the buttons is pressed, and attempts to close the ring
|
"""Emits the keyPressed signal if any of the buttons is pressed, and attempts to close the ring
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
|
@ -473,8 +474,10 @@ class NumberRing(BaseSudokuItem):
|
||||||
val : str
|
val : str
|
||||||
The digit to be emitted
|
The digit to be emitted
|
||||||
"""
|
"""
|
||||||
self.keyPressed.emit(val, self.scribbling)
|
scribble = btn == 2
|
||||||
self.close_menu()
|
self.keyPressed.emit(val, scribble)
|
||||||
|
if not scribble:
|
||||||
|
self.close_menu()
|
||||||
|
|
||||||
def freeze_buttons(self, freeze):
|
def freeze_buttons(self, freeze):
|
||||||
"""Freezes the button
|
"""Freezes the button
|
||||||
|
|
3
main.py
3
main.py
|
@ -43,7 +43,8 @@ class SudokuWindow(QGraphicsView):
|
||||||
self.gameboard.gridDrawn.connect(lambda: self.menuboard.show_children(True))
|
self.gameboard.gridDrawn.connect(lambda: self.menuboard.show_children(True))
|
||||||
self.gameboard.newGameSelected.connect(self.menuboard.set_difficulty_text)
|
self.gameboard.newGameSelected.connect(self.menuboard.set_difficulty_text)
|
||||||
self.gameboard.sudokuDone.connect(self.menuboard.finish_the_game)
|
self.gameboard.sudokuDone.connect(self.menuboard.finish_the_game)
|
||||||
self.menuboard.diff_display.notFocus.connect(self.gameboard.game_refocus)
|
self.menuboard.diff_display.menuClicked.connect(self.gameboard.game_unfocus)
|
||||||
|
self.menuboard.diff_display.notFocus.connect(lambda: self.gameboard.refocus_timer.start(10))
|
||||||
self.menuboard.diff_display.difficultySelected.connect(self.gameboard.new_game)
|
self.menuboard.diff_display.difficultySelected.connect(self.gameboard.new_game)
|
||||||
|
|
||||||
def resizeEvent(self, event):
|
def resizeEvent(self, event):
|
||||||
|
|
Loading…
Reference in New Issue