Ramen Junkie

Duolingo’s Music and Math Courses

Man, talk about both exciting and frustrating all at once. Duolingo launched both a Math and Music course recently, but it was iOS only, initially, and I use Android. It would come eventually though, and it apparently has, and I missed it, or at least, missed the announcement, if there was one. I have been periodically checking and they were not there until fairly recently.

I don’t really have a lot of need or interest in the Math course, but I wasn’t in a good place to try out the music course, so I started off on the Math one for a bit. I am already great at math, I mean, seriously, I have probably done more math than most people have, between school and hobbies and work. But hey, why not.

From what I have done, it’s, kind of weird? It’s all pretty basic Adding, subtracting, multiplying, and fractions so far. But there are often these blocks instead of actual numbers. Which I kind of get is intended to encourage counting, but some of the presentation on the groupings isn’t as consistent as it could be. Plus it just, feels like adding an extra counting step to slow you down. And no, I am not individually counting blocks, I used to count as a job, I can count groups very quickly. Which is also why I noticed the occasional inconsistency that almost felt like it was done purposely as a trip.

Maybe it was.

The real fun part though is that, it’s smart enough to recognize “goofy answers”. Like it has a block of squares to shade, 3/5ths or something. You can shade a random assortment of the 100 squares, just so long as it’s 60 total shaded. Or if it gives you an open ended question like “2/6+1/6”. Sure, you could put 3/6, or 1/2, but it will also take 3987/7974.

But enough math nonsense, my real interest is in the Music course. I really want to learn music, it was one of my “Decade resolutions” in 2020. To be done by 2030. I have really been looking forward to the music course.

And I like it. Even if so far it’s just banging out C, D, and E on the scales. It’s that repetition I want so I can better read sheet music.

But oh my God it’s frustrating as hell to actually do.

And not because it’s hard, but because there is a lot of weird lag and stutter. Every few courses you do a song snipped using notes you know, and so many times I miss a few because it… Just… rand… om… ly… stop…s and… stu… tt…ers…. As it slides along.

At the bare minimum, it’s distracting.

I don’t honestly understand WHY either. I would blame processing power, but I have a decent enough phone that can do other rhythm based games, just fine, often at a much much faster BPM.

I feel like part of the problem is the weird “holding” it sometimes asks for on notes. Like if I could just tap the notes to the beat, everything would run fine, but it often requires these half beat holds, which only exacerbates the stuttering issue since it causes more stutter, and means you can’t just move on and get the next note and try to compensate for the stutter.

It’s just really frustrating. I doubt I go very far in the course as is, as much as I really want to.

Keyboard Jiggler with Python and Raspberry Pi

So I did a pretty simple but amusing little project recently, a bit on a whim. Let’s say, I have a few games that it would be useful to just, let idle for experience or whatever. The problem is, that these games also have built-in idle deterrence. Your character falls asleep, or you just time out of the game after five or ten minutes.

I initially start off trying to use AutoHotkey, a program that basically does what I wanted here, you program it to press keys at certain intervals, basically just a simple keep-alive movement every couple of minutes.

It turns out, at least one of these games detects Autohotkey as a cheat, and won’t launch when it’s running.

I got to thinking, I could probably program one of my Arduino boards to emulate a keyboard. And sure enough, there are libraries for this very task. Then I discovered that, the keyboard library does not work on my old Uno boards. But I found an alternative route with my Raspberry Pi Pico that I picked up a few years ago. The Pico could probably do what I needed as well.

After some digging online, I found plenty of guides on how to build a full-sized Keyboard using GPIO pins on the Pico, but nothing quite exactly what I needed, but there was enough Python Code available, I could figure it out pretty easily by stripping apart some full keyboard code. Instead, I just started with a simpler macro button keyboard script. Most of the scripts I came across have code to detect and save a button press, then send the command using the Python Keyboard library. I just stripped all that out and put it on a timer loop with some simple, regular input. A set of repeated w presses, follow d by repeat d presses of a, s, and d.

Essentially, “walk in a little square loop.”

Step one was to set up Circuit Pi on the Pi Pico, which is detailed here, though only the initial setup is needed.

The test using Notepad worked perfectly, aside from one annoying issue, I could not easily edit the code while the device was plugged in, because the test loop would spit out wwwaaasssddd every 5 seconds.

After some careful quick timing, I adjusted that out to every 300 seconds (5 minutes).

It was time to test things out. Before work, I set the game running and the keyboard Jiggler working. When I came back later it was working just fine.

But there were some issues, one of which I could mostly address.

Firstly, the thing just runs, forever. It doesn’t really need to, I only need it going for around 3-4 hours. I added a counter variable to the script that would count how many runs through the loop had occured, and if it was more than a set amount, it would break the loop, which would stop the scripted movement and idle out of the game.

The other two issues are less easy to solve.

One, I had a thought that I could remote to my PC and swap games halfway through the day (at lunch). Except when you leave Remote Desktop, it locks the remote PC. Meaning the game loses focus and the keyboard Jiggler stops working. It’s literally a hardware device that pretends to be a keyboard.

The second issue, that could be easy to solve with some habit changes. I, very often, will use Firefox’s Tab Share to send tabs to either my desktop or my laptop. These are articles I want to clip and save, something I may want to buy later, notes for some projects I had done. Basically, it’s a way to send myself a reminder of something I don’t want to deal with on my phone. When I send a tab, on the remote machine, Firefox pops up and takes focus, meaning, once again, the game idle breaker stops working and it idles out.

The solution here is to just, get into the habit of only sending tabs after noon or so.

Another little improvement I added was a bit of randomization. I am not really worried about “detection,” but it’s easy to avoid by simply, adjusting the 5-minute timer to be random movement between 4 and 5 minutes, as well as randomizing what the movement is a bit.  I also added a bit of correction if the player moves too far away from the starting position.

Anyway, the script below is the completed script.

import time
import random

import board
import digitalio
import usb_hid
## Aquired from https://github.com/adafruit/Adafruit\_CircuitPython\_HID
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode

time.sleep(1)
keyboard = Keyboard(usb_hid.devices)
keyboard_layout = KeyboardLayoutUS(keyboard)  # We're in the US :)
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT
total_runs = 0
running = True
# This is the choices for keys to randomly choose from, this is standard WASD
# This could be changed to be whatever to choose from.
keyOptions = ["w","a","s","d"," "]
# "Starting position" is set to 0,0
position = [0,0]

while running:
    # Turn the LED on while doing things
    led.value = True
    
    # Randomly choose 20-50 as an amount of key presses to do
    howMany = random.randint(20, 50)

    for i in range(howMany):
        # For however many key presses, pick a random one and press it
        nextKey = random.choice(keyOptions)
        keyboard_layout.write(nextKey)
        time.sleep(1)
        # This incriments the position above from 0,0 to track how far from start.
        # This whole section could be omitted if movement can be unconstrained
        if nextKey == "w":
            position[1] +=1
        if nextKey == "s":
            position[1] -=1
        if nextKey == "a":
            position[0] +=1
        if nextKey == "d":
            position[0] -=1
        
        # If we get too far in one direction, correct it by moving back to 0.
        if position[0] >= 10:
            keyboard_layout.write(ssssssssss)
        if position[0] <= -10:
            keyboard_layout.write(aaaaaaaaaa)
        if position[1] >= 10:
            keyboard_layout.write(dddddddddd)
        if position[1] <= -10:
            keyboard_layout.write(aaaaaaaaaa)

    led.value = False
    time.sleep(0.1)
    keyboard.release_all()
    # Sleep a random number of seconds between 200 and 300 seconds
    nextSleep = random.randint(200, 300)
    time.sleep(nextSleep)

    # Incriment how many runs have been done
    total_runs = total_runs+1

    # If the total runs is too many, break the loop and essentially "stop".
    if total_runs > 48:
        running = False