Although I'm not a big fan of mushrooms, I consider myself a pretty fun-gi. Anyways, here are some of the fun things that I've done that I wanted to share with all of you. Hopefully it inspires you to do fun things as well. There's links to download all of the code on the page, or run the application (where applicable).

Block Breaker is a classic game, it's been around forever. So, I thought I would give it a go and try and make my own version. But what game isn't better with powerups. So, I also added some powerups to make gameplay more interesting. There are 6 levels, give it a shot and try to beat the game. Good luck. The controls are very basic, use the left and right arrow keys on the computer to move the paddle.

Click one of the options below to download:

Javascript Code

Many games where a player (Human) plays against a computer involves some form of what’s called a min-max algorithm. I will try and explain the min-max algorithm, but if you want to learn more, there’s tons of information online. You can download the Javascript code for this application and play against the AI using the links below.

Play Tic Tac Toe

Click one of the options below to download:

Javascript Code

The basic principle of the min-max algorithm, is the computer tries to maximize its score while minimizing the opponents score, hence min-max. The computer also assumes that both people will play the best move every time.

The code begins with the player (Human) clicking on a square. The row and column of that button are passed in to the makemove() function. The pseudocode for tictactoe is as follows:

makemove(row, col)

A = new 3x3 array. //Lets assume 0 is an empty square. 1 is the player, 2 is the computer.

Insert the player’s move.

If the game is over.

endgame(A)

return; // Quit the program.

result <— move(A)

put the rows and columns onto the board

if the game is over

endgame(A)

return // Quit the program

Now let's cover the endgame function, since it’s pretty straightforward and short.

endgame(A)

if player 1 won

display “Player 1 Won!”

else if computer won

display “Computer Won!”

else

display “The game Ended In A Draw”

And now that we got that out of the way, let's go on to the move function, where the fun really begins.

move(A)

// Here we pass in the current board, the starting depth, and the player that will move next (computer). We will come back to this.

result <— minmax(A, 0, “computer”)

// result is an array as follows: [bestscore, bestRow, bestCol] We will explore this in minmax()

row<— result[1]

col <— result[2]

return [row, col] // return an array containing the best row and best column

minmax(A, depth, player)

moves[] = get_available_moves(A)

// These four variables we will use throughout the code, so let’s just declare them here.

initialize currscore for later

bestRow <— -1

bestCol <— -1

initialize bestscore for later

if player 1 won OR computer won OR the game is over

bestscore <— score(A, depth)

else

if player = “computer”

bestscore = -Infinity

for every move, i, in moves

row <— row in current move

col <— column in current move

insert that place as the computer’s move

// Here we pass in depth+1, because it’s one more recursive call. We will use this later. We also want the opponent to “play” now, so we alternate who makes a move. And we get the [0] index, because that is where the score found will be returned at the end of the code.

currscore <— minmax(A, depth+1, “opponent”)[0]

if currscore > bestscore

bestscore <— currscore

bestRow = row

bestCol = col

undo that move we just tried above

else if player = “opponent”

bestscore = Infinity

for every move, i, in moves

row <— row in current move

col <— column in current move

insert that place as the opponent’s move

// Here we pass in depth+1, because it’s one more recursive call. We will use this later. We also want the computer to “play” now, so we alternate who plays. And we get the [0] index, because that is where the score found will be returned at the end of the code.

currscore <— minmax(A, depth+1, “computer”)[0]

if currscore < bestscore

bestscore <— currscore

bestRow = row

bestCol = col

undo that move we just tried above

// Return an array containing the best score, row, and column found so far.

return [bestscore, bestRow, bestCol]

There are 8 other helper methods in the code, but first I want to explain how this algorithm works, because if you’re not familiar with recursion, it can be a little tricky.

At every call of the recursive algorithm, the computer gathers all of the empty square, store in moves. It then tries them on at a time, recursively. Meaning it will consider the board in that state, then it will keep playing that version of the game until somebody wins, or the there are no move possible moves.

The tree of calls, if you will, might look like the following. This is a simplification for the sake of both your time and my time.

And now for the helper methods, starting with get_available_moves.

get_available_moves(A)

if player 1 won OR player 2 won

return an empty array

moves = empty array

for every row, i in A

for every column, j, in A

if A[i][j] is empty

sq <— [i, j] //an array containing the current row and column

add sq to moves.

return moves // return the list of all the moves found

gameover(A)

for every row, i, in A

for every column, j, in A

if the current square is not empty

return false

return true

If it never hits an empty square, then there must be at least one more move, so return true.

score(A, depth)

if player 1 won

return depth-100

else if computer won

return 100-depth

else

return 0

At the end of the recursive calls, meaning there are no more free squares, or somebody won, the minmax algorithm will call score. If the computer won, by subtracting depth from the arbitrary score of 100 for winning, we ensure that the computer will try to win in the least number of moves. If the player won, then it returns depth-100, meaning a smaller score for the player will result in least number of moves. This means that the minimal algorithm can consider both people beating the other person in the least number of moves.

And finally, the won method. This is a pretty simple algorithm, although there are a lot of parts to it, so let’s go through them one at a time. There are obviously many ways of writing this code, this is just one way.

won(val, A)

return checkCol(val, A) || checkRow(val, A) || diag(val, A) || diag2(val, A)

In order to win tic tac toe, you only have to win on one axis. I’ve defined diag() to be top left to bottom right, and diag2() to be top right to bottom left.

checkCol(val, A)

for every row, i, in A

check <— true

for every column, j, in A

if A[j][i] does not equal val

check = false

if check = true

return true

return false

checkRow(val, A)

for every row, i, in A

check <— true

for every column, j, in A

if A[i][j] does not equal val

check = false

if check = true

return true

return false

diag(val, A)

for every column, i, in A

if A[i][i] does not equal val

return false

return true

diag2(val, A)

for every column, i, in A

if A[Length of A - i][i] does not equal val

return false

return true

checkRow and checkCol work on the same principle. Because we know what value we are looking for, it simplifies the process. Assume that any column or row is true. Go through that column or row and if it never hits a value that isn't the value we are looking, val, then all the values in that column must be that val. So return true. If one of them isn’t val, then we go on to the next column or row. If no column or row meets the criteria, then return false.

diag() and diag2() work because the board is a sqaure. By going through the columns, to go top right to bottom left, subtract the number of the columns from the column you’re on and increment the rows. To go the other way, simply plug the current increment the row and column at the same time, and you move along the diagonal.

Although making a computer to solve a sudoku puzzle may seem difficult, it’s actually one of the easier recursive algorithms to program. You can download the code below in Javascript, or Java and test it yourself. You can also plug in your own sudoku board with the button linked below.

Open Sudoku Solver

Click one of the options below to download:

Java Code Javascript Code

The pseudocode for the algorithm is as follows:

I am assuming that we are passed in a 9x9 array containing the few values given on the board.

sudokusolver(A)

for i in every row of A

for j in every column of A

if the current space is not empty

continue

for num in [1-9]

if legalSquare(num, i, j, A)

A[i][j] = num

if sudokusolver(A)

return true

else

A[i][j] = empty

return false

return true

The algorithm recursively tries every number at every square, one at a time. If it gets to a point where it cannot insert a number, then it backtracks until it finds a number it can put in a square, and continues on from there.

There are a few helper methods used to implement legalsquare(). The pseudocode for those is as follows:

legalSquare(val, col, row, A)

return checkSquare(val, col, row, A) AND checkRow(val, row, A) AND checkCol(val, col, A)

checkSquare(val, col, row, A)

col = FLOOR(col/3) * 3

row = FLOOR(row/3) *3

for i in [col —> col+3] //go through columns

for j in [row —> row+3] // go through rows

if A[i][j] == val

return false

return true

checkRow(val, row, A)

for i in columns of A

if A[i][row] = val

return false

return true

checkCol(val, col, row, A)

for i in rows of A

if A[col][i] = val

return false

return true

LegalSquare assumes that there cannot already be a value (val) in either the closest box (3x3), current column or current row. If one of the helper methods (checkSquare, checkRow, or checkCol) return false, it means that one of them encountered that value. Meaning that is not a legal square for num. So legalSquare returns false.

I think checkCol and checkRow are pretty self-explanatory. They are passed in the column or row, respectively. They go through every item of that column or row, and if they hit a value, val, they return false. If they never do, return true.

checkSquare has another interesting problem, given any square, it must be able to find the start of the 3x3 box it’s in. This calculation we do in the first two lines of the function. The for loops then go 3 to the right, and 3 down, meaning it will cover all 9 squares in that 3x3 box, and check for the value in that box.

I worked with another student, Ali Siddiqui, while attending the University of Victoria, and together we developed a new way of sorting integers using a linked list of stacks.

Click one of the options below to download:

Java Code

The pseudocode for the main function of the algorithm is as follows

sort(A)

Create new linked list of stacks

for i in 0 —> length of A

insert(a[i])

i <— 0

for i in 0 —> length of A

a[i] = remove()

increment i

The sort() method simply reads every value of the array, A, and calls the insert method to insert them into the list. It then calls the remove method to systematically insert the items back into the array in sorted order.

The pseudocode for the insert function is as follows:

insert(value)

newNode = new node() //make a new node

if head == null // if the list is empty

push value onto the stack of the new node

head = newNode

else

node curr

if top of head stack >= value

push value onto head stack

return

for every node in list

if value <= top of current node stack

push value onto node stack

return

push the value onto newNode

add newNode to end of the list

The insert function creates a new node. If there are no nodes in the list, it inserts the value passed in on the new node. It then makes head node equal to the new node. If there is at least one element in the list, it checks to see if the value is smaller than the top of the first list. If it is, it pushes the node onto the top of the first stack and returns. If it is not, it continues through the list and checks the top of every stack until it finds a stack such that the top element is larger than the value. If it finds a stack, it adds the value to the top of the stack. If it gets to the end of the list, without finding a stack, it creates a new node at the end of the list, and puts the value on the stack of the newly created node.

The pseudocode for the remove function is as follows:

remove()

create new node min

keep track of previous node, initialize to null.

for every node in list

if top of min > top of next node

min = next node

previous = current node

a <— pop min

if stack on min is empty

if head = min

head = head.next // remove first node

if min is the end of the list

prev.next = null //remove last node

else

prev.next = min.next //remove node from middle of the list

return a

The remove function goes through the list every time, and pops the stack with the smallest element. It then checks to see if that stack is now empty, if it is, it removes that node from the list.

Here is a diagram of what the stack might look like after the insertion step:

Sample Input: [5 3 8 4 6 10 7 8 5 5]

So how does this algorithm do in terms of performance? Below is a graph comparing our algorithm to a number of other popular algorithms. You can download all of the code to test it yourself. In the testing functions, we created an array of varying size, and generated random numbers, and ran tests where each algorithm would sort the same array. We do this multiple times, and take the average between tests. When running the algorithm, you can specify the maximum size of the array you want to test, as well as the number of times you want to run each test. The code provided is written in Java.

You may have noticed that there are 3 versions of the algorithm in the graph above. The first version of the stack sorter algorithm used the pseudocode described above and used the built-in Java stack library. The second version was exactly the same as the first version, except we implemented stacks ourselves using linked lists. Going from the first to second version made a huge difference in performance, meaning out algorithm was now faster than Insertion sort. It turns out the built-in stacks library was written with Java 1.0 and never updated. So it isn't very well optimized for performance. The third version we introduced a hash table. The hash table makes an array based on powers of 10. We did this so that each list would be smaller, meaning it should theoretically take less time to sort. I thought I would explain version 2 in pseudocode for simplicity. The code available to download is version 3. (as of Nov. 2015)

Although we didn't implement them, we also came up with some theoretical ways of making our algorithm faster. If there was a way to further hash the values, such as by multiples of 10 or 100, each linked list would be shorter, meaning when inserting and removing, performance would be improved. Another possible way would be to store the minimum and second minimum from the stacks. And as long as the minimum stack is less than the top of the second minumum, remove from that stack, then return an array. This means that it cuts down on the number of times we go through the entire linked list. Also, if there was a way for a node to point to the next one during the insert process, then the remove function would be linear.

Our system specs and Java version are as follows:

No other programs were open on the machine at the time.