Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added ARIALUNI.TTF
Binary file not shown.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# InteractiveProgramming
This is the base repo for the interactive programming project for Software Design, Spring 2016 at Olin College.
# TypingGame
A matrix styled typing game that is designed to help teach people how to type and have fun in the process.

![example screenshot](Sample.png)
Binary file added Sample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
144 changes: 144 additions & 0 deletions UserInterface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import sys, pygame, time, random, unicodeGen
from modely import Model, Letter

speed = 3
runTime = 60 # seconds

pygame.init()

size = width, height = 1200, 600 # window size
black = 0, 0, 0
white = 255, 255, 255
grey = 50, 50, 50
red = 255, 0, 0

font = 'ARIALUNI.TTF'
textFont = pygame.font.Font(font, 40)
scoreFont = pygame.font.Font(font, 20)

screen = pygame.display.set_mode(size) # make the window

mod = Model(runTime) # make a game that will run for runTime seconds

letters = []
for i in range(10): # Generate our random list of Letters
letters.append(Letter())


def randExclude(exclude, start, stop):
'''returns a random column in range of x-values excluding the values given
to exclude. This prevents letters dropping into the same column and
covering each other.
'''
r = None
while r in exclude or r is None:
r = random.randrange(start, stop)
return r


def replaceLet(let, start, stop):
'''Ensures that there are no letters in the same column. If there are,
replace them.
'''
xVals = []
for i in range(len(let)):
if let[i].x in xVals:
a = randExclude(xVals, start, stop)
let[i].x = a
xVals.append(a)
else:
xVals.append(let[i].x)
return(let)


letters = replaceLet(letters, 0, 19)
# make sure that there are no overlapping letters in the original list


def xInLetters(l):
'''returns a list of all the occupied columns'''
xV = []
for i in range(len(l)):
xV.append(l[i].x)
return xV


letterSize = textFont.size('X')
targetStart = 100
# Distance from the bottom of the screen to the top of the target

target = pygame.Surface((width, 70))

# curTime = time.clock() - startTime
clock = pygame.time.Clock()
startTime = pygame.time.get_ticks()
fps = 30

while not mod.gameover: # This is the main loop
clock.tick(fps) # This determines how often the loop runs
screen.fill(black)
target.fill(grey)
screen.blit(target, (0, height - targetStart))
potentials = []

for i in range(len(letters)):
# Go through all the letters to update their positions and
# determine whether they are on the screen and whether they are in the
# target zone.
thisLetter = letters[i]
letters[i].y += speed
screen.blit(thisLetter.surf, ((width/20)*thisLetter.x, thisLetter.y))

if thisLetter.getEnd() >= 600: # If letter off the screen, replace it
xs = xInLetters(letters)
letters[i] = Letter()
letters[i].x = randExclude(xs, 0, 19)
print(' X')
timeRunning = pygame.time.get_ticks() - startTime
mod.updateScore('m', timeRunning)

if thisLetter.getEnd() > height - targetStart:
# If bottom of letter has reached top of target box, add it to the
# list of correct letters
potentials.append(thisLetter.value)

for event in pygame.event.get(): # When something happens
if event.type == pygame.QUIT: # Terminate the program if window closed
sys.exit()
if event.type == pygame.KEYDOWN:
keyPressed = event.key
if keyPressed in potentials: # Hit!
for i in range(len(letters)):
# scan through to find letter(s) that was pressed and is in
# target box, replace it, and update score
if (keyPressed == letters[i].value
and letters[i].getEnd() >= height - targetStart):
print('X')
timeRunning = pygame.time.get_ticks() - startTime
mod.updateScore('h', timeRunning)
xs = xInLetters(letters)
letters[i] = Letter()
letters[i].x = randExclude(xs, 0, 19)
else: # Pressed wrong key
print(' X')
timeRunning = pygame.time.get_ticks() - startTime
mod.updateScore('w', timeRunning)

# Add the scoreboard and update the dispay:
scoreboard = scoreFont.render(
('Score: ' + str(round(mod.score(), 1))), 1, red)
screen.blit(scoreboard, (width - 100, 10))
pygame.display.flip()

while mod.gameover:
clock.tick(fps)
screen.fill(black)
endFont = pygame.font.Font(font, 100)
endText = endFont.render(('Score: ' + str(round(mod.score(), 1))), 1, red)
endTextSize = endText.get_size()
screen.blit(endText, (width/2 - endTextSize[0]/2,
height/2 - endTextSize[1]/2))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
94 changes: 94 additions & 0 deletions modely.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import pygame, random, unicodeGen, math

allUnicodeChoices = unicodeGen.get_all_unicode() # Run this once to generate the list

white = 255, 255, 255
green = 0, 255, 0

class Model:
'''Model keeps track of the game state, including running time and
score-related info'''

def __init__(self, runTime=60, hits=0, misses=0, wrongKey=0, gameOver=False):
'''keeps track of hits misses and game state and initializes the class.
When undefined, hits and misses equal zero and gameover is false.
'''
self.hits = hits
self.misses = misses
self.wrongKey = wrongKey
self.gameover = gameOver
self.runTime = runTime

def score(self):
'''Keeps track of score'''
total = self.hits + self.misses + self.wrongKey
if(total == 0):
return 0
return (self.hits / total) * 100

def updateScore(self, event, timeRunning):
'''Updates score statistics by modifying values in the class model'''
if event == 'h':
self.hits += 1
elif event == 'm':
self.misses += 1
else:
self.wrongKey += 1
if timeRunning/1000 >= self.runTime: # Game over after runTime seconds
self.gameover = True


class Letter:
'''Letter objects include the letter to be typed, its location on the
screen, size, and related information, and the random unicode string that
follows it'''

def __init__(self,
font='ARIALUNI.TTF', value=None, x=None, y=None, surf=None):
# arguments not passed in are randomly generated
self.font = font
self.textFont = pygame.font.Font(self.font, 40)
self.tailFont = pygame.font.Font(self.font, 40)

charWidth = 40
# by experimentation, the widest characters appear to be about 40
# pixels in this font and size
charHeight = self.textFont.size('X')[1]
# all characters should be the same height

if(value == None):
self.value = random.randint(97, 122)
# this is the range a-z in ascii
else:
self.value = value

self.tail = [] # tail is the random unicode string
# Add a random number of random characters to the tail:
self.tailLength = random.randint(3, 12)
for i in range(self.tailLength):
self.tail.append(random.choice(allUnicodeChoices))

self.surf = pygame.Surface((charWidth, charHeight*(self.tailLength+1)))
# Create a new object for the character and tail to be on
targetChar = self.textFont.render(chr(self.value), 1, white)
# This is the character at the bottom that you're supposed to type
self.surf.blit(targetChar, (0, (self.tailLength)*charHeight))
for i in range(len(self.tail)):
uni = self.tailFont.render(self.tail[i], 1, green)
self.surf.blit(uni, (0, ((i)*charHeight)))

self.height = self.surf.get_height()

if y == None:
self.y = 0 - (random.randint(0, 600) + self.height)
# Place the surface off the screen
else:
self.y = y
if(x == None):
self.x = random.randint(0, 19)
else:
self.x = x

def getEnd(self):
# return the coordinates of the bottom end of the surface
return self.y + self.height
33 changes: 33 additions & 0 deletions unicodeGen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# import random
# import pickle


def get_all_unicode():
'''Generates all unicode characters in the specified ranges and stores
it in a list which can randomly be selected from'''

try:
get_char = unichr
except NameError:
get_char = chr

# Update this to include code point ranges to be sampled
include_ranges = [ # these ranges selected for interesting non-alphanumeric characters with minimal gaps

(0x2200, 0x22FF), # Mathematical Operators
(0x0400, 0x04FF), # Cyrillic
(0x0250, 0x02AF), # IPA Extensions
(0x30A0, 0x30FF), # Katakana, almost no missing characters
(0x0600, 0x06FF), # Arabic
(0x03A3, 0x03FF), # Greek
(0x05D0, 0x05EA), # Hebrew, no missing characters
(0x0904, 0x0939), # Devanagari
(0xF900, 0xFA6D), # CJK compatibility ideographs, almost no missing characters
]

alphabet = [ # generate all unicode in ranges
get_char(code_point) for current_range in include_ranges
for code_point in range(current_range[0], current_range[1] + 1)
]

return alphabet