Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
To gamify reading
#1
Hi guys!
I wanted to share an idea i have been working on for a while now. My programming skills are still beginner level and i have made a working example for the idea. I was wondering if anyone here is interested to develop it further.

The idea:
Physical activity such as in sports has immediate feedback and dopamine reinforcement. These factors help in attaining the flow state in physical activity easily. Some mental activities (such as programming) also have these attributes and can be flow-conducive.

My goal is to achieve flow even in mundane activities such as reading required text material i have little interest in.

The 'game':
- Components:
1. Key logger: Detects the keyboard input. When you scroll down sufficient length of the text, you get some points. (Can also include touch input for detecting scrolls done using the mouse/ trackpad).

2. Reminders: The program keeps track of time while you are reading and gives you feedback when:
- you are doing well
- you are slacking
- you have beaten your previous score
- you have read for a certain amount of time and it is time for a mandatory relaxation break

3. Score keeper: Keeps track of your score and stores it for future comparison.

4. Audio engine: Plays time-appropriate sounds
- when you gain a point
- when the program determines that you have done well
- when you have beaten your old record
- when you are slacking

5. Visuals: To complement the audio feedback, any simple visual overlay for the same purposes.

6. Note taker: When you highlight and copy a piece of text, the program reads it aloud and stores the audio file for revision in the future.
- These notes are stored as per the reading material and the program has an option to play a specific
reading session's audio files in succession when the player wants to revise.

7. Console: A small area on the screen which gives you the stats regarding your current reading session. Much like Ironman's helmet, it should not be too much of a distraction from the reading material, and instead give simple info such as:
- your score
- how much time has elapsed in the current reading session
- How far away you are from completing this session/ beating your old high score
- your speed
- your overall state (some calculated value that approximates the likelihood that you have achieved flow)


I have made a basic version of this game without several features listed above such as visual feedback, console and score keeper. However, the program gives an illusion of a game by playing the bgm from super Mario brothers and playing the sound of gaining points once for every 10 down key presses.

I could not have made this if awesome working code was not already available for several things i had no clue how to do! That said, my code is still sloppy and could benefit from some pro here who might be interested in such a concept.

i am putting the code here for your review. Please keep in mind that i am a beginner before you tear me apart for bad code. Thanks!

For the note-taking feature i talked about. Code has been copied as it is from the web as i was not able to make it work using pyttsx3.
from keylog import *

def txt_zu_wav(eingabe, ausgabe, text_aus_datei = True, geschwindigkeit = 2, Stimmenname = "Zira"):
    from comtypes.client import CreateObject
    engine = CreateObject("SAPI.SpVoice")

    engine.rate = geschwindigkeit # von -10 bis 10

    for stimme in engine.GetVoices():
        if stimme.GetDescription().find(Stimmenname) >= 0:
            engine.Voice = stimme
            break
    else:
        print("Fehler Stimme nicht gefunden -> Standard wird benutzt")

    if text_aus_datei:
        datei = open(eingabe, 'r')
        text = datei.read()
        datei.close()
    else:
        text = eingabe

    stream = CreateObject("SAPI.SpFileStream")
    from comtypes.gen import SpeechLib

    stream.Open(ausgabe, SpeechLib.SSFMCreateForWrite)
    engine.AudioOutputStream = stream
    engine.speak(text)

    stream.Close()

def gen_name():
    import time
    s = str(round(time.time(), 2))
    return s

def make_audio_file(message):
    # txt_zu_wav("test.txt", "test_1.wav")
    n = "a_notes//" + gen_name()+".wav"
    txt_zu_wav(message, n, False)
    k = pygame.mixer.Sound(n)
    k.play()
The main program file. Again relied heavily on more experienced programmers for a big chunk here.
from pynput.keyboard import Key, KeyCode, Listener
import pygame, openpyxl, datetime, time
import openpyxl, threading, pyperclip
from audiotext import * 

wb          = openpyxl.load_workbook('gameface.xlsx')
curr_game   = wb['Sheet1']
db          = wb['Sheet2']
score       = 0
row_1       = curr_game.max_row
row_2       = db.max_row
time_stamp  = time.time()
speed       = []
running     = True
down_num    = 0
esc_num     = 0

pygame.init()

# Getting all the sounds ready
announcement 	= pygame.mixer.Sound('sounds//announcement.wav')
come_back1 		= pygame.mixer.Sound('sounds//come_back.wav')
come_back2 		= pygame.mixer.Sound('sounds//come_back2.wav')
heart_racing	= pygame.mixer.Sound('sounds//heart_racing.wav')
lets_begin		= pygame.mixer.Sound('sounds//lets_begin.wav')
not_reading1	= pygame.mixer.Sound('sounds//not_reading.wav')
not_reading2	= pygame.mixer.Sound('sounds//not_reading2.wav')
not_reading3	= pygame.mixer.Sound('sounds//not_reading3.wav')
not_reading4	= pygame.mixer.Sound('sounds//not_reading4.wav')
slice_end		= pygame.mixer.Sound('sounds//slice_end.wav')
slice_end2		= pygame.mixer.Sound('sounds//slice_end2.wav')
slice_end3		= pygame.mixer.Sound('sounds//slice_end3.wav')
point			= pygame.mixer.Sound('sounds//point.wav')
power_up		= pygame.mixer.Sound('sounds//power_up.wav')


resume  		= pygame.mixer.Sound('sounds//resume.wav')
paused	    	= pygame.mixer.Sound('sounds//pause.wav')
game_over_well  = pygame.mixer.Sound('sounds//goverw.wav')
game_over_bet   = pygame.mixer.Sound('sounds//goverb.wav')
game_start      = pygame.mixer.Sound('sounds//gstart.wav')
stop_idling     = pygame.mixer.Sound('sounds//read.wav')
welcome         = pygame.mixer.Sound('sounds//welcome.wav')
gameAlPaused    = pygame.mixer.Sound('sounds//gamealreadypaused.wav')
gameOngoing     = pygame.mixer.Sound('sounds//gameongoing.wav')
startGameFirst  = pygame.mixer.Sound('sounds//gamenotstarted.wav')
goFaster        = pygame.mixer.Sound('sounds//goFaster.wav')
exerciseAnn     = pygame.mixer.Sound('sounds//exerciseAnn.wav')
backToZone      = pygame.mixer.Sound('sounds//backToZone.wav')

# 0: end; 1: playing, 2: paused
g_state = 0
bgm_state = 1
e_time = time.time()

def exercise_time():
    global e_time
    pause_game()
    time.sleep(1)
    exerciseAnn.play()
    time.sleep(2)
    heart_racing.play(34)
    # time.sleep(1200)
    time.sleep(120)
    backToZone.play()
    time.sleep(2)
    e_time = time.time()
    resume_game()

def bgm():
    pygame.mixer.music.load("sounds//bgm1.mp3") 
    if g_state == 1 and bgm_state == 1:
        pygame.mixer.music.play(-1,0.0)
    else:
        pygame.mixer.music.pause


def start_game():
    global g_state, time_stamp, speed
    if g_state == 0:
        speed = []
        time_stamp = time.time()
        announcement.play()
        game_start.play()
        g_state = 1
        bgm()
    elif g_state == 1:
        gameOngoing.play()

def end_game():
    global g_state
    if g_state == 1:
        game_over_well.play()
        g_state = 0
        bgm()
    else:
        startGameFirst.play()

def pause_game():
    global g_state, time_stamp
    if g_state == 1: 
        paused.play()
        time_stamp = time_stamp + 100000
        g_state = 2
        bgm()
    elif g_state == 2:
        gameAlPaused.play()
    else:
        startGameFirst.play()

def resume_game():
    global g_state, time_stamp
    if g_state == 2:
        resume.play()
        time_stamp = time.time()
        g_state = 1
        bgm()
        time_stamp = time.time()

def player_event():
    if g_state == 1:
        global time_stamp, down_num
        down_num += 1
        if down_num == 10:
            point.play()
            down_num = 0
            delay = time.time() - time_stamp
            time_stamp = time.time()
            update_speed(delay)
            check_speed()
    # waiter()
    
def check_speed():
    global speed
    if len(speed) > 0:
        print(sum(speed)/len(speed))
    else:
        print('Start playing first!')

def update_speed(s):
    global speed
    if len(speed) > 1:
        speed.pop(0)
    speed.append(s)

def toggle_bgm():
    global bgm_state
    if bgm_state == 1:
        bgm_state = 0
        bgm()
    else:
        bgm_state = 1
        bgm()



# Create a mapping of keys to function (use frozenset as sets/lists are not hashable - so they can't be used as keys)
# Note the missing `()` after function_1 and function_2 as want to pass the function, not the return value of the function
combination_to_function = {
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=71)]): start_game,     # ctrl + alt + g
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=88)]): end_game,       # ctrl + alt + x
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=80)]): pause_game,     # ctrl + alt + p
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=82)]): resume_game,    # ctrl + alt + r
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=83)]): check_speed,    # ctrl + alt + s
    frozenset([Key.ctrl_l, Key.alt_l, KeyCode(vk=66)]): toggle_bgm      # ctrl + alt + b
}

# The currently pressed keys (initially empty)
pressed_vks = set()

def get_vk(key):
    """
    Get the virtual key code from a key.
    These are used so case/shift modifications are ignored.
    """
    return key.vk if hasattr(key, 'vk') else key.value.vk


def is_combination_pressed(combination):
    """ Check if a combination is satisfied using the keys pressed in pressed_vks """
    return all([get_vk(key) in pressed_vks for key in combination])


def on_press(key):
    """ When a key is pressed """
    global running, esc_num
    vk = get_vk(key)  # Get the key's vk
    if key == Key.esc:
        esc_num += 1
        if esc_num == 3:
            running = False
            end_game()
            pyperclip.copy('stop')
            time.sleep(2)
            quit()
    if key == Key.down:
        player_event()
    pressed_vks.add(vk)  # Add it to the set of currently pressed keys

    for combination in combination_to_function:  # Loop through each combination
        if is_combination_pressed(combination):  # Check if all keys in the combination are pressed
            combination_to_function[combination]()  # If so, execute the function


def on_release(key):
    """ When a key is released """
    vk = get_vk(key)  # Get the key's vk
    pressed_vks.remove(vk)  # Remove it from the set of currently pressed keys

def police():
    global time_stamp, esc_num
    while running == True:
        if g_state == 1:
            if time_stamp + 10 < time.time():
                time.sleep(5)
                esc_num = 0
                if time_stamp + 120 < time.time():
                    goFaster.play()
                    time.sleep(10)
        if e_time + 1200 < time.time():
            exercise_time()

def marker():
    while True:
        if pyperclip.paste() != '' and pyperclip.paste() != 'stop':
            print('Marker active')
            make_audio_file(pyperclip.paste())
            print('Saved', pyperclip.paste())
            time.sleep(3)
            pyperclip.copy('')
        time.sleep(1)
        if pyperclip.paste() == 'stop':
            break
        
def starter():
    welcome.play()
    pyperclip.copy('')
    th = threading.Thread(target=marker)
    pol = threading.Thread(target=police)
    th.start()
    pol.start()
    with Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()
    pol.join()
    th.join()


if __name__ == '__main__':
    starter()
I am not including any audio files here, which are placed in a folder called 'Sounds' in the same directory as these program files. Looking forward to making this program better with your help.

Thanks!

PS: I would have worked harder and made this at least a little better before posting here, but i am currently working 12 hour shifts which turn into 14 hour shifts and am barely able to catch enough sleep and go by.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020