0% found this document useful (0 votes)
13 views12 pages

411 Report

Uploaded by

dustintobrien
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views12 pages

411 Report

Uploaded by

dustintobrien
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

HW 1 Lab Report

Section 1: Description

The program contains 8 functions 4 of which are functions being overridden from
the QWidth super class below are the functions and their uses

Subsection 1: init()

The init function creates the needed functionality and initial setup of the
gameboard. First it creates a 1D array and fills it to represent each index of the of the
gameboard. Then various variables used throughout the game combined with various
functions setting up windows are used for initial running. Finally the board is shuffled to
prepare user to play the game.

Subsection 2: mousePressEvent()

This is the function that activates whenever the window has been clicked. Firstly
it checks if board is solved and if so does nothing are requested by assignment. It then
calculates index clicked by user and sends to swapcell which handles the change in
board. The screen is then updated to show this change.

Subsection 3: paintEvent()

This is the function responsible for drawing the screen; it first grabs the size of
the window for positioning purposes. Afterwards, the painter function calculates the
necessary location to center game board on x axis and a set place to lower the board
into nice spot. The boardSize and cellSizes are than calculated such that the cells fit
inside the board and that the board fits within screen and looks decent. The board is
then drawn followed by all cell indexes. Then there is an if statement used to display the
win textif applicable and number of moves done so far.

Subsection 4: show()

The show function is a simple gram its main function is to call the parent
functions show and to set a reasonable size to the window.
Subsection 5: shuffle()

The shuffle function's job is to generate a random order of cells such that there is
only 1 of each number and one empty cell. I have represented the empty cell with a -1 as
it is a value no matter the number of cells that wont be used. The algorithm I used was to
create and array of all allowed indexes and to remove a random one and set the front
most not set cell to that number. I felt this solution was computationally simple and
unlikely to cause need major debuggings

Subsection 6: isSolved()

Since a function is solved when all numbers are in order and the last element is
empty of -1 implementation of this was rather simple as it ends up being and if
statement checking if first if that -1 is at end followed by if the array sorted and
therefore in order combined with the -1 removed since it doesnt need to be considered
is same as the array if not the array is not in order and therefore not solved. This
algorithm similar to last one left little room for debugging and error.

Subsection 7: isSolveable()

For this algorithm I first find the row of the empty index which is needed as the
algorithm given requires the knowledge of it. After that I use an algorithm to determine
number of inversions however inverted the other way as I thought working with
incrementing rather than decrementing for loops would be easier to work with. After
calculating inversions we simply returned true if it met and of 3 conditions to be
solvable.

Subsection 8: swapCell()

The job of the swap cell function is to move indexes around according to the rules
of the assignment. The function considers two cases first is if you clicked on same row as
the empty cell second is if the column is the same as the empty cell if neither is true
nothing is done and therefore not considered. The row function works by simply moving
the -1 to the clicked cell this naturall displaces everything properly although doesn’t
work on columns as it will push lower columns over columns. For columns I simmplete
loop through swapping each cell. For the first algorithm I calculate the amount of moves
that would’ve happened which is simply the amount of cells between. For loop I simply
increment by 1 and then decrease by 1 to remove the -1 swap move with itself.

Section 2: Pictures

Image 1: Initial Configuration

Image 2: Move Left


Image 3: Move Right (From Intial State Notice Moves = 1)

Image 4: Move one Down


Image 4: Move Up One

Image 5: Move Multiple Cells Down


Image 6: Move Multiple Cells Up

Image 7: Move Muliple Right


Image 8: Move Multiple Left

Image 9: Solved Game


Section 3: Python Code

#Imports
import sys
import math as m
import random as r
from PyQt5.QtGui import QPainter, QPen, QBrush, QColor, QFont
from PyQt5.QtWidgets import QWidget, QApplication, QDesktopWidget, QLabel
from PyQt5.QtCore import Qt, QRect, QPoint

#Class Object Declaration


class gameBoard(QWidget):
#Generates Game Board
def __init__(self, gridWidth) -> None:
super().__init__()

#Generates GameBoard
self.gameGrid = [i+1 for i in range(gridWidth**2 - 1)] #We want to do a square because thats the
shape of the game
self.gameGrid.append(-1)

#Gets Screen size for object size purposes


self.windowSize = self.size()
self.width = self.windowSize.width()
self.height = self.windowSize.height()

#Sets Geometry Window


self.setGeometry(0, 0, self.height, self.height)

#Sets Title of Game


self.setWindowTitle('Fifteen Puzzle Game')

#Sets Various needed variables for game such as the games move count and the amount of cells
wide the board is
self.gridWidth = gridWidth
self.moves = 0

#Shuffles Board to Random Solveable State


self.shuffle()
while(not self.isSolveable() and not self.isSolved()):
self.shuffle()

#Draws Grid
self.show()
def mousePressEvent(self, event):
if(self.isSolved()):
return

#gets X and Y positions of click


x = event.x()
y = event.y()

#Gets Cell Index


index = int((x - self.gridStartX) / self.cellSize) + self.cellWidth * int((y - self.gridStartY) /
self.cellSize )
self.swapCell(index)

self.update()
return

def isSolved(self):
if self.gameGrid[len(self.gameGrid) - 1] == -1 and sorted(self.gameGrid[:-1]) == self.gameGrid[:-
1]:
return True
else:
return False

#Swaps Index Wanted with Cell clicked on


def swapCell(self, cellIndex):

#Gets Index of empty cell to swap with


emptyIndex = self.gameGrid.index(-1)
if (int(emptyIndex / self.gridWidth) == int(cellIndex / self.gridWidth) ):
self.gameGrid.pop(emptyIndex)
self.gameGrid.insert(cellIndex, -1)
self.moves += abs(cellIndex - emptyIndex)
elif (int(emptyIndex % self.gridWidth) == int(cellIndex % self.gridWidth)):
for i in range(emptyIndex, cellIndex + 2 * (emptyIndex < cellIndex) - 1, self.gridWidth *( 2 *
(emptyIndex < cellIndex) - 1)):
self.gameGrid[emptyIndex] = self.gameGrid[i]
self.gameGrid[i] = -1
emptyIndex = i
self.moves += 1
self.moves -= 1 #Because we dont count moving empty cell
def isSolveable(self):
#Keeps track of number of inversions
inversions = 0

#Gets Empty index to determine row


emptyIndex = self.gameGrid.index(-1)

#Gets row that is empty counting from the bottom


emptyRow = self.gridWidth - int(emptyIndex / self.gridWidth) - 1

#Counts Number of Inversion


for index in range(len(self.gameGrid)):
for testIndex in range(index + 1, len(self.gameGrid)):
if(self.gameGrid[testIndex] > self.gameGrid[index] and index != emptyIndex and testIndex +
index != emptyIndex):
inversions += 1

if (inversions % 2 == 0 and self.gridWidth % 2 == 1):


return True
elif (inversions % 2 == 1 and emptyRow % 2 == 0 and self.gridWidth % 2 == 0):
return True
elif (inversions % 2 == 0 and emptyRow % 2 == 1 and self.gridWidth % 2 == 0):
return True

return False

def shuffle(self):
unusedIndexes = [i+1 for i in range(self.gridWidth**2 - 1)] #We want to do a square because
thats the shape of the game
unusedIndexes.append(-1)

for i in range(len(self.gameGrid)):
randomNum = r.randint(0,len(unusedIndexes) - 1)
self.gameGrid[i] = unusedIndexes[randomNum]
unusedIndexes.pop(randomNum)

#puts the game grid onto the screen


def paintEvent(self, event):
#Gets Window size for sizing purposes
self.windowSize = self.size()
self.width = self.windowSize.width()
self.height = self.windowSize.height()
#Intializes Starts the Painter
painter = QPainter()
painter.begin(self)

#Sets starting indexes for game board


self.gridStartX = int(self.width / 2 - (self.height - 100) / 2)
self.gridStartY = 75

#Sets Proper size for gameboard and Cells


self.boardSize = self.height - 100
self.cellSize = int(self.boardSize // self.gridWidth)

#Number of cells in one row of board


self.cellWidth = int(self.boardSize // self.cellSize)

#Draws Dynaimcally Changing sized Board


painter.fillRect(self.gridStartX, self.gridStartY, self.boardSize, self.boardSize, QColor(100, 100,
110))

#Draws each of square


for index, indexNumber in enumerate(self.gameGrid):
if(indexNumber != -1):
#Draws Square
painter.fillRect(self.gridStartX + self.cellSize * (index % self.cellWidth), self.gridStartY +
self.cellSize * int(index / self.cellWidth) , self.cellSize - 3, self.cellSize - 3, QColor(100, 100, 210))

fontSize = 65
#Adds Number to square
painter.setFont(QFont('Arial', fontSize, QFont.Bold))
#painter.setBold(True)
painter.drawText(self.gridStartX + self.cellSize * (index % self.cellWidth) + int(self.cellSize / 2 -
fontSize / 2) , self.gridStartY + self.cellSize * int(index / self.cellWidth) + int(self.cellSize / 2 +
fontSize / 2),str(indexNumber))

if(self.isSolved()):
painter.setPen(QColor(0,150,0))
painter.drawText(int(self.width / 2) - int(fontSize / 2) * len("YOU WIN!!!"),fontSize + 8,"YOU
WIN!!!")
print(self.moves)

painter.setPen(QColor(0,0,0))
painter.setFont(QFont('Arial', 25, QFont.Bold))
painter.drawText(int(self.width / 2 * 1.5),fontSize + 8,f"Moves: {self.moves}")

#Closes things up
painter.end()

#New Generate Function that resizes screen to what I want


def show(self) -> None:
super().show()
self.resize(800,800)
self.__x = -135
self.__y = -1
super().show()

if __name__ == '__main__':
#Generates Application Object
app = QApplication(sys.argv)

#Initializes Game board and Displays


game = gameBoard(gridWidth=4)
game.show()

#closes Application
sys.exit(app.exec_())

Section 4: Sources
I made a lot of use of documentation and in class examples for getting functions.
There was occsional usage of python functions such as pop and insert which is
particularly exclusive to my algorithms.

Section 5: Sources
I received minor help for Cole Barbes who told me that the functions had to be named a
specific thing to override the Widget classes functions

You might also like