Tuesday, February 28, 2023

Coding Challenge #11 Job Scheduler

Daily Coding Challenge #10

Goal: Make a job scheduler that calls function Fn after T miliseconds

// Part 1 / 2 just the simple delayed function call
// JavaScript
function procrastinate(fn, delay){
    setTimeout(fn, delay);
}
procrastinate(()=>{console.log('hi');}, 1000);

// C++
void procrastinate(void*(*fn)(void), int delay){
    Sleep(delay);
    fn();
}
void hi(){
    cout << "hi" << endl;
}
procrastinate((void*(*)(void))hi, 1000);



// Part 2 / 2 full JavaScript scheduler
// interact with it: call sched.start() to start regular checks.
// call sched.register(fn, delay) to add an event
// call sched.stop() if you want it to stop for any reason
// it checks at a user-definable interval
// it executes all events that are scheduled for that moment or prior one time
// you can also schedule it to stop using its own sched.register()

// Note to self: setTimeout,etc make call the function in isolation, where 'this' in the function's body is not defined. To get around this, we pass the object's saved reference to itself ('me') to check(me) each time it is called. And instead of using 'this', we use 'me' to access its properties.
// Note 2: to pass args to a function called by setTimeout, put the args to the called function after the functionToCall and delayToCall. setTImeout(urFn, delayUntilItsCalled, urFnsArg1, urFnsArg2, ...). Each check(me) must pass 'me' again in the next setTimeout() call.

function scheduledEvent(fn, time){
    this.fn = fn;
    this.time = time;
}
function Scheduler(checkInterval){
    this.schedule = [];
    this.checkInterval = checkInterval == undefined ? 1000 : checkInterval;
    this.shouldStop = false;
    this.me = this;
    this.start = function(){
        this.check(this.me);
    }
    this.register = function(fn, delay){ // delay in miliseconds
        this.schedule.push(new scheduledEvent(fn, (new Date()).valueOf() + delay));
        this.schedule.sort((a,b)=>{return a.time > b.time}); // sort from nearest to furthest (smallest time value is at lowest index)
    }
    this.check = function(me){
        var now = (new Date()).valueOf();
        while(me.schedule.length > 0 && now >= me.schedule[0].time){
            me.schedule[0].fn(); // call the function
            me.schedule.splice(0,1); // remove executed scheduledEvent
        }
        if(!me.shouldStop) setTimeout(me.check, me.checkInterval, me);
    }
    this.stop = function(){
        this.shouldStop = true;
    }
}
function test_fn_1(){console.log('i am test_fn_1, hear me rawr :3');}
function test_fn_dos(){console.log('yo soy test_fn_2, dos es dulces xD');}
function test_fn_trois(){console.log('je suis test_fn_3, je suis ton livre');}
function test_fn_si(){console.log('我是test_fn_4。 我的朋友叫我李四。我的朋友是張三和王五。');}
function test_fn_go(){console.log('私の名前はtest_fn_5、五語を話します!');}
function test_fn_kr(){console.log('저는test_fn_6입니다.저것은 체브인입니다!');}
function test_fn_pt(){console.log('Eu sou test_fn_7. Tem leite? Que briga!');}
function test_fn_id(){console.log('test_fn_8, saya juga buku-buku kamu');}
var sched = new Scheduler(1000); // check every second
sched.register(test_fn_1, 1000);
sched.start();
sched.register(test_fn_dos, 2000);
sched.register(test_fn_trois, 3000);
sched.register(test_fn_si, 4000);
sched.register(test_fn_go, 5000);
sched.register(test_fn_kr, 6000);
sched.register(test_fn_pt, 7000);
sched.register(test_fn_id, 8000);
sched.register(()=>{sched.stop();}, 9000); // scheduling stopping the scheduler with its own functions. Have to use a global reference.
sched.register(test_fn_1, 10000); // should not be called. sched should be stopped by now.

Monday, February 27, 2023

Creepy Shounen Jump Ads

Shounen Jump had some odd ads... In particular, the creepy 'arm out of the belly button' hot dog ads... and of course the Condemned: Criminal Origins ads. Faceless mannequins to advertise a scary M-rated game about drug addicts over town becoming homicidal? In a magazine aimed kids-teens?! Madness.

 Though I still love my dear old Shounen Jump issues and admit that being able to think of such depths of discomfort and creepiness as only added spice to life and not scarred me, check out the creepy ads from a 2006 Shounen Jump!





Creepy. And funny. Freepy.

Sunday, February 26, 2023

Mini Audio Recorder - HTML/JavaScript

Mini Recorder Timeout (seconds):
    Recording


*Durations in table are approximations.
Tip: Hold down Spacebar to start recording. Release Spacebar to stop.
Created to practice speaking Korean, and maybe to have some fun with guitar.
Based off of copy-pasted code from Bryan Jennings @ Medium.com. Thanks!

Saturday, February 25, 2023

Coding Chalenge #10 Binary Search

Programming: Principles and Practice Using C++
Chapter 26: Testing


So if I'm not mistaken, the idea of a binary search is to:

  1. Go to the middle index of an array. Check if the value is the same as the value we're looking for.
  2. If the value is the same, return the index the value was found at.
  3. If the value is greater than the value we're looking for, look at the half with the lower value. If the value is less than the value we're looking for, look at the half with the higher values.
  4. Rinse & Repeat: Go to the center index of the new half and check the value.Eventually we'll have determined whether the value is in the array or absent. If absent, return -1.


For it, we make a binary search function which takes an array (of int's here) and returns the index where the int's value matches the value of the index of the array, or returns -1 if the value is not present in the array.
"Binary search;" what a fun little project! To discover that in only 16 iterations with a relatively small amount of instructions per iteration, it could determine the index or absence of a value in an ordered array with 100,000 members! That's... well, that's sexy!

 

// compiled & tested @ OnlineGDB
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// binary search, return index where value was found or -1 if not found.
// the std::vector<int> input should be sorted in increasing order.
int findVal(int val, std::vector<int> a){
    int len = a.size();
    if(len == 0){
        cout << "Empty array; value not present. (-1)" << endl;
        return -1; // empty array, impossible to find a value
    }
    int cur; // current index we're checking
    int lcur = 0; // left cursor. lowest index we consider still in valid range (inclusive)
    int rcur = len - 1; // right cursor; highest index in valid range (inclusive)
    cout << "\n==== starting test ====" << endl;
    int loop = 0;
    while(lcur != rcur){
        loop++;
        cout << "\nLoop # " << loop << endl;
        cout << "Cursors: [" << lcur << ", " << rcur << "]" << endl;
        cur = (( rcur - lcur ) / 2 ) + lcur; // get the center of the cursors
        cout << "cur (now " << cur << ") is ((" << rcur << " - " << lcur << ") / 2) + " << lcur << endl;
        if(a[cur] == val){
            cout << "a[" << cur << "](" << a[cur] << ") = " << val << ". done." << endl;
            return cur; // found our value. Hurray!
        }
        else if(a[cur] < val){
            lcur = cur + 1; // the value up to and including left cursor is not what we want. search rightward
            cout << "a[" << cur << "](" << a[cur] << ") < " << val << ". L-cur now " << lcur << endl;
        }
        else{
            rcur = cur - 1; // a[cur] > val. search leftward. move right cursor.
            cout << "a[" << cur << "](" << a[cur] << ") > " << val << ". R-cur now " << rcur << endl;
        }
        if(rcur < lcur){
            cout << "Right cursor is on the left side of Left cursor; error" << endl;
            return -1;
        }
        
        if(rcur < 0){
            cout << "rcur has become negative, value  not found" << endl;
            return -1; // rcur can become negative, which is an indicator we didn't find the value.
        }
    }
    // if we get here, we assume lcur == rcur
    if(a[lcur] == val){
        cout << "The last index was correct; (a[" << lcur << "] (" << a[lcur] << ") == " << val << ")" << endl;
        return lcur; // the last index to check is the correct value
    }
    else return -1;
}

int ran(int max){ // return [0,max] inclusive
    return rand() % (max+1);
}

void test(const char *name, int prelen=10, int *preA=nullptr){ // make test array and let user play with findVal()
    std::vector<int> a;
    // generate values for the vector with incrementing (sorted) values.
    int nextVal = 0;
    int len = prelen;
    if(preA == nullptr){ // make our own array
        for(int xint = 0;xint < len;xint++){ // 10 numbers that will be in order, skipping 1 or 2 numbers between each entry.
            nextVal += ran(1) + 1; // next number will be [1,2] inclusive greater than previous number
            a.push_back(nextVal);
        }
    }else{ // import pre-defined array
        for(int xint = 0;xint < len;xint++)
            a.push_back(preA[xint]);
    }
    
    cout << "\n=== Now Testing: " << name << " ===" << endl;
    while(1){
        cout << "\n\nPlease enter number to get the index (or -1) in the array.\n'q' to quit." << endl;
        if(len <= 10 && len > 0){ // can change len to big amounts. only display array if len is small
            cout << "Array: [0] = " << a[0];
            for(int xint = 1;xint < len;xint++)
                cout << ", [" << xint << "] = " << a[xint];
        }
        cout << endl << "Value to search for: ";
        std::string input = "";
        getline(cin, input);
        if(input == "q") break;
        else{
            try{
                int val = stoi(input);
                int ret = findVal(val, a);
                if(ret == -1) cout << "Could not find value '" << val << "' anywhere in the array. (-1)" << endl;
                else cout << "Found value '" << val << "' at index " << ret << " in the array." << endl;
            }catch(...){
                cout << "The entered value appears to have not been a number. Please enter a number or 'q'" << endl;
            }
        }
    }
}
int aryLen(int *ary){ // use -1 as array-terminating value
    int len = 0;
    while(ary[len] != -1) len++;
    return len;
}
int main()
{
    cout << "Starting up... " << endl;
    
    test("Normal, generated, ordered"); // 10 indices
    test("Large, generated, ordered", 100000); // 10,000 indices
    
    int t1[] = {0,1,2,3,4,5, -1}; // normal ordered array
    test("Normal ordered array", aryLen(t1), t1);
    
    int t2[] = {5,4,3,2,1,0,-1}; // reverse order array. doesn't work.
    test("Reverse ordered array", aryLen(t2), t2);
    
    int t3[] = {2,5,1,0,3,4,-1};
    test("Random, disordered array", aryLen(t3), t3); // random. doesn't work.
    
    int t4[] = {0,0,0,0,0,-1};
    test("All 0s", aryLen(t4), t4); // all zeros. Works as normal. Can only return 0 or -1.
    
    int t5[] = {0,0,0,0,1,-1};
    test("All 0s + ending 1", aryLen(t5), t5); // works normally
    
    int t6[] = {1,0,0,0,0,-1};
    test("Starting 1 + all 0s", aryLen(t6), t6); // won't work. 1 is not in ordered place
    
    test("Empty Array", 0); // works normally. Always -1
    
    cout << "Thanks, bye!" << endl;

    return 0;
}
 

Friday, February 24, 2023

Diary #3 Forwarding Keyboard Strokes Through Websocket, C++

 A couple years ago I made a program in C++ that I've been using all day, every day since. It lets me use one keyboard to send keyboard input to not only the computer attached to the keyboard, but also another computer that's running this program as the server.

(source code here)

It's relatively simple and pretty short. It also has things that could be improved but I'll never be motivated to pursue, so it's more of a proof of concept.


The premise is that using the Websocket protocol, it communicates to the server which keys/mouse events it wants it to simulate.

Then the server uses mouse_event() or keybd_event() to simulate the mouse or keyboard events respectively on the local machine.


Not sure if it's the Websocket protocol, the Websocket++ library, or configurations of one or both, but there is a delay of about 200 to 250 miliseconds for most messages. This prevents fluent 30 FPS mouse simulation and inhibits actioney gameplay, as keys will not properly simulate fast enough for non-menu-based games.

Thursday, February 23, 2023

Coding Challenge #9

Check if One Array Can Be Nested In The Other (here)

Given two arrays, check first can be nested in the second.

Array 1 can be nested if:

  1. Array 1's min value > Array 2's min value
  2. Array 2's max value < Array 2's max value

Using yesterday's challenge to quickly get the min/max value of an array to get a head start...

 function getExtremes(ary){
    var x = {min:null,max:null}; // return null if ary length is 0
    if(ary.length < 1) return x;
    
    x.min = ary[0]; // default to first index of array
    x.max = ary[0];
    for(var xint = 1, len = ary.length;xint < len;xint++){
        x.min = Math.min(x.min, ary[xint]);
        x.max = Math.max(x.max, ary[xint]);
    }
    return x;
}

function test(){
    var ary = [];
    var len = Math.round(Math.random() * 3) + 2; // [2,5] inclusive
    for(var xint = 0;xint < len;xint++)
        ary.push(Math.round(Math.random() * 100)); // [0,100] inclusive
    
    var polarz = getExtremes(ary);
    
    var ary2 = [];
    var len2 = Math.round(Math.random() * 3) + 2; // [2,5] inclusive
    for(var xint = 0;xint < len2;xint++)
        ary2.push(Math.round(Math.random() * 100)); // [0,100] inclusive
    
    var polarz2 = getExtremes(ary2);
    
    if(polarz.min > polarz2.min && polarz.max < polarz2.max){
        console.log("Array A: " + ary.toString() + " has min: " + polarz.min + ", max: " + polarz.max + ", and Array B: " + ary2.toString() + " has min: " + polarz2.min + ", max: " + polarz2.max + ". Can it be nested? YES.");
    }else{
        console.log("Array A: " + ary.toString() + " has min: " + polarz.min + ", max: " + polarz.max + ", and Array B: " + ary2.toString() + " has min: " + polarz2.min + ", max: " + polarz2.max + ". Can it be nested? NO.");
    }
}

test();
test();
test();
test();
test();

Wednesday, February 22, 2023

Coding Challenge #8

Find the Smallest and Biggest Number (here)

 Given an array, return an object with properties 'min', holding the smallest number in the array, and 'max', holding the largest number in the array.


function getExtremes(ary){
    var x = {min:null,max:null}; // return null if ary length is 0
    if(ary.length < 1) return x;
    
    x.min = ary[0]; // default to first index of array
    x.max = ary[0];
    for(var xint = 1, len = ary.length;xint < len;xint++){
        x.min = Math.min(x.min, ary[xint]);
        x.max = Math.max(x.max, ary[xint]);
    }
    return x;
}

function test(){
    var ary = [];
    var len = Math.round(Math.random() * 10) + 1; // [1,11] inclusive
    for(var xint = 0;xint < len;xint++)
        ary.push(Math.round(Math.random() * 100)); // [0,100] inclusive
    
    var polarz = getExtremes(ary);
    console.log("Array " + ary.toString() + " has min: " + polarz.min + ", max: " + polarz.max);
}

test();
test();
test();
test();
test();

Tuesday, February 21, 2023

Diary #2 Convert JavaScript Event.key to Virtual Key Codes

Next for my webapp to remotely control a desktop, I need to send messages to the server with the information: which key & pressed or released?

I thought and came to the conclusion that the easiest way would be to use an object and call its properties with JavaScript's brackets n' strings... thingy.

 

Note: these are for US keyboard (QWERTY specifically); other layouts may not correctly pick up the input or output the virtual key code as-is

(mostly punctuation keys on the right side of letters)
example: VK_OEM_4,VK_OEM_5,VK_OEM_6,VK_OEM_7 for '[', '\', ']', and '\'' keys respectively, as well as their shift versions.

I guess they mapped the values to the locations on the keyboard, and not to expected character messages for these keys, huh?

 

Since the code is vertically long, I'll post the example of its usage first, followed by the code.

Example:

function keyPressed(myEvent){
    var kc = vkCodes[myEvent.key];
    if(kc == undefined){
        alert('Unsupported key cannot be simmed: ' + myEvent.key + ' (code: ' + myEvent.keyCode + ')');
        return;
    }
    sendHTTPmessage('blah/keyPressedDown/' + kc);
}

 

If the key that is pressed is not in the vkCodes object, it the get would return null.

Note: I didn't flesh out the vkCodes with all possible codes, just those that would be relevant or useful to me.

Now for the code:  

var vkCodes = {
    'Enter':0x0D,
    'Alt':18,
    'Control':17,
    'Tab':0x09,
    'Shift':0x10,
    'CapsLock':0x0D,
    'Backspace':8,
    'OS':0x0D,
    'Escape':0x1B,
    'Delete':0x0D,
    'Insert':0x0D,
    'PageUp':33,
    'PageDown':34,
    'End':35,
    'Home':36,
    'ArrowLeft':37,
    'ArrowRight':39,
    'ArrowUp':38,
    'ArrowDown':40,
    'PrintScreen':0x2C,
    'Insert':45,
    'Delete':46,
    '0':0x30, // both numpad and numbers above letters will be used as numbers above letters
    '1':49,
    '2':50,
    '3':51,
    '4':52,
    '5':53,
    '6':54,
    '7':55,
    '8':56,
    '9':57,
    ' ':0x20,
    'a':0x41, // lowercase
    'b':66,
    'c':67,
    'd':68,
    'e':69,
    'f':70,
    'g':71,
    'h':72,
    'i':73,
    'j':74,
    'k':75,
    'l':76,
    'm':77,
    'n':78,
    'o':79,
    'p':80,
    'q':81,
    'r':82,
    's':83,
    't':84,
    'u':85,
    'v':86,
    'w':87,
    'x':88,
    'y':89,
    'z':90,
    'A':0x41, // uppercase, same keycode output as lowercase
    'B':66,
    'C':67,
    'D':68,
    'E':69,
    'F':70,
    'G':71,
    'H':72,
    'I':73,
    'J':74,
    'K':75,
    'L':76,
    'M':77,
    'N':78,
    'O':79,
    'P':80,
    'Q':81,
    'R':82,
    'S':83,
    'T':84,
    'U':85,
    'V':86,
    'W':87,
    'X':88,
    'Y':89,
    'Z':90,
    '*':105, // assume numpad *
    '+':0x6B, // assume numpad +
    '.':0xBE, // period near letters, not decimal on numpad
    '>':0xBE,
    '<':0xBC,
    ',':0xBC,
    ';':0xBA,
    ':':0xBA,
    '\'':0xDE,
    '"':0xDE,
    '[':0xDB,
    '{':0xDB,
    ']':0xDD,
    '}':0xDD,
    '\\':0xDC,
    '|':0xDC,
    '`':0xC0,
    '~':0xC0,
    '-':0xBD, // minus near 0, not minus on numpad
    '_':0xBD,
    '=':0xBB,
    '/':0xBF, // slash near letters, not divide on numpad
    '?':0xBF,
    'F1':112,
    'F2':113,
    'F3':114,
    'F4':115,
    'F5':116,
    'F6':117,
    'F7':118,
    'F8':119,
    'F9':120,
    'F10':121,
    'F11':122,
    'F12':123,
    'AudioVolumeMute':0xAD,
    'AudioVolumeUp':0xAF,
    'AudioVolumeDown':0xAE,
    'MediaPlayPause':0xB3,
    'MediaPlayNext':0xB0,
    'MediaPlayPrevious':0xB1,
    'MediaPlayStop':0xB2
};

Monday, February 20, 2023

Diary #1 Send Screenshot from Python to HTML Canvas

 I wanted to control a computer from another computer in another room, so here we are. So far, I've just completed the proof of concept, but the idea needs refinement, and won't be nearly as efficient as TeamViewer/etc. But more convenient and requires less CPU than TeamViewer.


What it does:

  • Server: Python. Listens as HTTP server. Upon a GET request, it will take a screenshot and return it.
  • Client: HTML/JavaScript. Webpage with a button. When the button is pressed, it sends a GET request to the server to get a screenshot.


The screenshot data will be scaled down to 512 width & proportionate height. The color palette will be limited to 256 (to attempt to save image size). And the format of the image as sent to the client will be 'raw' RGB image data. To transfer it to the client via HTTP, we'll encode it in hex (doubling its size. This could be changed to base64 to shave off 75% of the added overhead).

The client will receive the data, decode it from hex to a byte array, then apply it to an ImageData object (changing the color format from RGB to RGBA). We will then put it in the context of the canvas at 0,0 x/y offset. 


Since this is an informal diary kind of thing, I'll just paste the relevant code bits:

Server (response to client's GET request after pressing button):

from math import floor # used for my 'byteAryToHex' fn
from PIL import Image # PIL fns for getting screenshot
from PIL import ImageGrab

                        img = ImageGrab.grab() # get whole-screen screenshot
                        size = 512,512
                        img.thumbnail(size) # resize img to thumbnail 512x512
                        img.convert("P", palette=Image.ADAPTIVE, colors=256) # simplify color palette to reduce size
                        bytes = img.tobytes('raw', 'RGB')
                        self.wfile.write(byteAryToHex(bytes).encode('utf-8'))


Client (after got GET response from server):

console.log("got img msg. loading img from it...");
                imgRaw = decodeHex(args[1]);
                // now read it into canvas (rgb to rgba)
                px = new ImageData(512,512);
                idx = 0;
                for(var xint = 0, len = imgRaw.length;xint < len;xint++){
                    px.data[idx++] = imgRaw[xint++];
                    px.data[idx++] = imgRaw[xint++];
                    px.data[idx++] = imgRaw[xint];
                    px.data[idx++] = 255;
                }
                c.putImageData(px, 0,0);

 

Also noteworthy pearl of frustration from my past:  Firefox blocks the response received by the client's GET request if the address of the request does not match the current web page (CORS). So the python server that's taking the screenshot also has to host an HTTP server and serve the webpage.

It is working in my system, and at any time I can get a screenshot of the computer's screen by pressing the button. Just getting that far took a few hours of  hours of frustration, after attempting to store it as the entire image's data (PNG/JPEG) as base64 in a data:image/png, but no success for reasons I couldn't understand and didn't want to spend time debugging. I went ahead and sent them as pixels from server->client, as I am far more familiar with drawing pixels into a canvas.

Sunday, February 19, 2023

Coding Challenge #7

Daily Programmer Challenge #397 (here)

Roman Numeral Comparison

Compare two strings of faux roman numerals. The function should return true if the first string's numeral value is less than the second.
Note: These are not real roman numerals in the sense that their order does not impact their value. A simplification for convenience.
 

// Example: "II" "V" => true (2 < 5)
// "VV" "VI" => false (5+5 < 5+1)

// convert faux roman numeral to number
function calc(ronum){
    var num = 0;
    for(var xint = 0, len = ronum.length;xint < len;xint++){
        if(ronum.charAt(xint) == 'M') num += 1000;
        else if(ronum.charAt(xint) == 'D') num += 500;
        else if(ronum.charAt(xint) == 'C') num += 100;
        else if(ronum.charAt(xint) == 'L') num += 50;
        else if(ronum.charAt(xint) == 'X') num += 10;
        else if(ronum.charAt(xint) == 'V') num += 5;
        else if(ronum.charAt(xint) == 'I') num += 1;
    }
    return num;
}

// payload comparison. one < two = true, one >= two = false
function compare(ronum_one, ronum_two){
    var num_one = calc(ronum_one);
    var num_two = calc(ronum_two);
    
    return num_one < num_two;
}

// The values are not roman numeral format, but represent a number,
// so they will be randomly generated outside conventional order.
var ronums = ['M', 'D', 'C', 'L', 'X', 'V', 'I'];
function makeRonum(){
    var str = "";
    var len = Math.round(Math.random()*10) + 1;
    for(var xint = 0;xint < len;xint++)
        str += ronums[(Math.round(Math.random()*(ronums.length-1)))];
    return str;
}
function test(){
    var one = makeRonum();
    var two = makeRonum();
    if(compare(one, two)){
        console.log("true, " + calc(one) + " < " + calc(two) + " | " + one + " < " + two);
    }else{
        console.log("false, " + calc(one) + " >= " + calc(two) + " | " + one + " >= " + two);
    }
}

test();
test();
test();
test();

Saturday, February 18, 2023

Coding Challenge #6

Daily Programmer Challenge #395 (here)

 // Given a binary array (defined as containing only values 0 and 1),
// create an array where the indices represent the lengths of the
// continuous streaks of 1's.

// Example: [0,0,1,0] => [1] (1 streak, length 1)
// [0,1,1,0] => [2] (1 streak, length 2)
// [1,0,1,0] => [1,1] (2 streaks, length 1 each)
// [1,1,1,0] => [3] (1 streak, length 3)

function calc(ary){
    var streak = 0;
    var out = [];
    for(var xint = 0, len = ary.length;xint < len;xint++){
        if(ary[xint] == 1) streak++;
        else if(streak > 0){
            out.push(streak);
            streak = 0;
        }
    }
    if(streak > 0) out.push(streak); // in case it ends in 1
    return out;
}

function test(){
    var ary = [];
    var len = Math.round(Math.random()*10) + 1;
    for(var xint = 0;xint < len;xint++)
        ary.push(Math.round(Math.random()*1));
    
    var out = calc(ary);
    console.log("Testing array: " + ary.toString() + " ===> " + out.toString());
}

test();
test();
test();
test();

Friday, February 17, 2023

Coding Challenge #5

Daily Coding Problem #4


Given an array of integers, find the missing lowest-value positive integer. The array is not organized by value.
The integers in the array can be either negative or positive, and the array can contain duplicates as well.
Examples: [3, 4, -1, 1] => 2 is the answer (only 1+ can be the answer, the soonest number not in the array is it)
[1,2,0] => 3
[-100, 1, 2, 97] => 3
This was listed as hard, but it seems super easy; hopefully I understood the problem correctly.
To give a little more substance to this post, let's give a solution in a few languages:

// JavaScript
function get(ary){
    var lowest = 1;
    for(var xint = 0, len = ary.length;xint < len;xint++){
        if(ary[xint] == lowest){
            lowest++;
            xint = -1; // restart loop, to check for number that's 1 higher than new lowest
        }
    }
    return lowest;
}

// PHP
function get($ary){
    $lowest = 1;
    for($xint = 0, $len = sizeof($ary);$xint < $len;$xint++){
        if($ary[$xint] == $lowest){
            $lowest++;
            $xint = -1;
        }
    }
    return $lowest;
}

# Python
def get(ary):
    lowest = 1
    for ia in range(len(ary)): # can't manipulate loop index in py, so nest a loop
        for ib in ary[ia:]:
            if ib == lowest:
                lowest += 1
    return lowest

// C++
int get(int* ary, int len){
    int lowest = 1;
    for(int xint = 0;xint < len;xint++){
        if(ary[xint] == lowest){
            lowest++;
            xint = -1;
        }
    }
    return lowest;
}

Thursday, February 16, 2023

Coding Challenge #4 Binary Tree (De)Serialization

 Daily Coding Problem #3: Binary tree (de)serialization

 
Goal: serialize and deserialize a binary tree and node
By my quick search and understanding, a "binary tree" is one node with two attached to it
Serializing one is to convert it into a format that can be stored without changing the tree's structure.
Deserializing is to restore the stored version to its live data structure, with matching structure as pre-serialization.

Constraints:
The node class is as given:
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


The following should work out:
node = Node('root', Node('left', Node('left.left')), Node('right'))
assert deserialize(serialize(node)).left.left.val == 'left.left'

So to make a little diagram of the above constraint test tree
    o
   / \
  o   o
 /
o

So the premise is that we are passing the node to serialize() to get Modified_form_X,
and then passing the Modified_form_X to deserialize() to get the original node,
making the following semantically viable:
class NodeWrapper:
    def __init__(self, myNode, extra):
        self.val = myNode.val
        self.left = myNode.left
        self.right = myNode.right
        self.extra = extra
def serialize(n):
    Modified_node = NodeWrapper(n, 'xyz')
    return Modified_node
def deserialize(mn):
    Original_node = Node(mn.val, mn.left, mn.right)
    return Original_node




But we might as well turn it into an array of bytes as if to prepare it for storage
The word 'serialize' makes me think of adding extra data, so that we can recreate the sequence even if it is completely disorganized (like the volume number on the spine of a manga mook: we can reorder them properly by this even if we arrange them randomly). So that's what I'll do. I'll even randomize it :v
def serialize(n):
    # turn node tree into an array for easier handling
    ary = []
    returnForRight = []
    cur = n # we know n is the root
    
    while cur != 'Done':
        while cur != None: # log lefts first. then return for right later
            ary.append(nodeByte(cur)) # log the node as a byte
            if cur.right != None:
                returnForRight.append(cur.right)
            cur = cur.left # can be None or another node
        # cur now is None, so try to get the next right
        if len(returnForRight) > 0:
            cur = returnForRight[0]
            returnForRight.pop(0) # remove the first element, instead of keeping track of progress with an index of returnForRight
        else:
            cur = 'Done' # finally hit all of the branches
    
    
    # randomize to prove a point that nobody asked for
    out = []
    nodesLen = len(ary)
    left = nodesLen
    for inc in range(nodesLen):
        idx = ran(0,left-1)
        out.append(ary[idx])
        ary.pop(idx)
        left -= 1
    
    # now we have random serialized nodes from the tree
    # so return them
    return out
def serialize(n):
    # turn node tree into an array for easier handling
    ary = []
    returnForRight = []
    cur = n # we know n is the root
    
    while cur != 'Done':
        while cur != None: # log lefts first. then return for right later
            ary.append(nodeByte(cur)) # log the node as a byte
            if cur.right != None:
                returnForRight.append(cur.right)
            cur = cur.left # can be None or another node
        # cur now is None, so try to get the next right
        if len(returnForRight) > 0:
            cur = returnForRight[0]
            returnForRight.pop(0) # remove the first element, instead of keeping track of progress with an index of returnForRight
        else:
            cur = 'Done' # finally hit all of the branches
    
    
    # randomize to prove a point that nobody asked for
    out = []
    nodesLen = len(ary)
    left = nodesLen
    for inc in range(nodesLen):
        idx = ran(0,left-1)
        out.append(ary[idx])
        ary.pop(idx)
        left -= 1
    
    # now we have random serialized nodes from the tree
    # so return them
    return out
    
    
def deserialize(x): # x is the byte array from serialize()
    # first find the root
    # then find nodes with trailSize of only 1 (level 1 children)
    # then trailSize of only 2 (level 2 children)
    # theoretically: etc
    
    maxLv = getMaxNodeLevel(x) + 1 # ending idx includes value of max lv
    lvls = []
    for lv in range(maxLv):
        lvls.append(findAllNodesOfLevel(x, lv))
    
    # now we have [ [root], [root.left, root.right], [root.left.left] ] though not necessarily in that order
    #now let's transform them into Node's
    root = Node('root')
    nodeLvls = [[root]] # like lvls but Node's instead of bytes
    
    # now let's go through each level starting with lv 1 and attach them to the proper parent
    for lv in range(maxLv)[1:]:
        nodeLvls.append([])
        for idx in lvls[lv]: # note: for each level, each node's parent would have already been defined.
            # find this node's parent within the upper level & within the root Node
            myParent = matchTrail(nodeLvls[lv-1], idx)
            if myParent == None:
                print('unable to match a parent to this byte: ' + str(idx))
            else:
                if localRelativity(idx) == True: # true=right? or false=left
                    myParent.right = Node(stringifyTrail(idx)) # with left/right as None, its children will claim it l8r
                    nodeLvls[lv].append(myParent.right) # log the Node for its kids to find
                else:
                    myParent.left = Node(stringifyTrail(idx))
                    nodeLvls[lv].append(myParent.left)
    
    # now we have the root Node, which has had children nodes attached to it
    return root # return the root Node

# [min,max]
def ran(min, max):
    return min + (round(random()*(max-min)))


nodeByte format description:
0000 0000
 ^^^ trail size [0,7] inclusive (effective values [0,4], as there are only 4 bits to descsribe the trail)
^ is root? (set, but unused)
     |--| the trail; left-to-right, 0 is 'left' and 1 is 'right'

 

Done


Well, that took around 3 hours lol
The final working code in Python (as it was the language the problem used):

from random import seed # seed for & generate random numbers
from random import random

class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def nodeByte(n): #we're gonna wrap the node data into a single byte (we know there won't be many levels of the tree)
    x = 0
    if n.val == "root":
        return 128 # root is just 128
    
    trail = n.val.split('.') # 'left.left' => [left,left]
    trailSize = 0
    for lr in trail:
        if lr == 'right':
            x += (8 >> trailSize)
        trailSize += 1
        if trailSize == 4: # only room for 4 trail bits, the problem's example has a max trail of only 2 anyway
            break

    x += (trailSize & 7) << 4
    return x
def findAllNodesOfLevel(nodes, Lv): # for ease in deserialize(). get all nodes with trailSize=Lv
    a = []
    for byte in nodes:
        if ((byte & 112)>>4) == Lv:
            a.append(byte)
    return a
def localRelativity(nodeByte): # am i left or right? (in relation to my direct parent node)
    return ((nodeByte & 8) >> (4 - ((nodeByte & 112)>>4))) == 1 # True = right, False = left
def getMaxNodeLevel(nodes):
    max = 0
    for byte in nodes:
        lv = ((byte & 112)>>4)
        if lv > max:
            max = lv
    return max
def matchTrail(nodes, byte):
    myTrail = stringifyTrail(byte)
    trailSize = (byte & 112) >> 4
    if trailSize == 1:
        myTrail = 'root' # is a direct child of the root node
    else:
        if localRelativity(byte): # check if left/right. We turn myTrail: left.left into left, to match parent lineage
            myTrail = myTrail[:-6] # - str '.right'
        else:
            myTrail = myTrail[:-5] # - str '.left'
    
    
    for n in nodes:
        if n.val == myTrail:
            return n
    return None
def stringifyTrail(byte):
    o = ''
    trailSize = (byte & 112) >> 4
    if trailSize == 0:
        return o
    
    if (byte & 8) == 8:
        o += 'right'
    else:
        o += 'left'
    
    if trailSize > 1:
        curTrailIdx = 1
        while curTrailIdx < trailSize:
            if (byte & (8 >> curTrailIdx)) > 0:
                o += '.right'
            else:
                o += '.left'
            curTrailIdx += 1
    
    # done. turned 0101 into 'left.right.left.right', etc
    return o
def serialize(n):
    # turn node tree into an array for easier handling
    ary = []
    returnForRight = []
    cur = n # we know n is the root
    
    while cur != 'Done':
        while cur != None: # log lefts first. then return for right later
            ary.append(nodeByte(cur)) # log the node as a byte
            if cur.right != None:
                returnForRight.append(cur.right)
            cur = cur.left # can be None or another node
        # cur now is None, so try to get the next right
        if len(returnForRight) > 0:
            cur = returnForRight[0]
            returnForRight.pop(0) # remove the first element, instead of keeping track of progress with an index of returnForRight
        else:
            cur = 'Done' # finally hit all of the branches
    
    
    # randomize to prove a point that nobody asked for
    out = []
    nodesLen = len(ary)
    left = nodesLen
    for inc in range(nodesLen):
        idx = ran(0,left-1)
        out.append(ary[idx])
        ary.pop(idx)
        left -= 1
    
    # now we have random serialized nodes from the tree
    # so return them
    return out
    
    
def deserialize(x): # x is the byte array from serialize()
    # first find the root
    # then find nodes with trailSize of only 1 (level 1 children)
    # then trailSize of only 2 (level 2 children)
    # theoretically: etc
    
    maxLv = getMaxNodeLevel(x) + 1 # ending idx includes value of max lv
    lvls = []
    for lv in range(maxLv):
        lvls.append(findAllNodesOfLevel(x, lv))
    
    # now we have [ [root], [root.left, root.right], [root.left.left] ] though not necessarily in that order
    #now let's transform them into Node's
    root = Node('root')
    nodeLvls = [[root]] # like lvls but Node's instead of bytes
    
    # now let's go through each level starting with lv 1 and attach them to the proper parent
    for lv in range(maxLv)[1:]:
        nodeLvls.append([])
        for idx in lvls[lv]: # note: for each level, each node's parent would have already been defined.
            # find this node's parent within the upper level & within the root Node
            myParent = matchTrail(nodeLvls[lv-1], idx)
            if myParent == None:
                print('unable to match a parent to this byte: ' + str(idx))
            else:
                if localRelativity(idx) == True: # true=right? or false=left
                    myParent.right = Node(stringifyTrail(idx)) # with left/right as None, its children will claim it l8r
                    nodeLvls[lv].append(myParent.right) # log the Node for its kids to find
                else:
                    myParent.left = Node(stringifyTrail(idx))
                    nodeLvls[lv].append(myParent.left)
    
    # now we have the root Node, which has had children nodes attached to it
    return root # return the root Node

# [min,max]
def ran(min, max):
    return min + (round(random()*(max-min)))



node = Node('root', Node('left', Node('left.left')), Node('right'))
assert deserialize(serialize(node)).left.left.val == 'left.left'
print('Success! U haz smartz!')

Wednesday, February 15, 2023

Coding Challenge #3

 Daily Coding Problem #2
with an array of integers, return an array where each index of the new array is the product of all other indices of the old array.

// [1,2,3] example input
// [6,3,2] example output (6 is 2*3 (skip 1), 3 is 1*3 (skip 2), 2 is 1*2 (skip 3))

// [4,5,6] example input
// [30,24,20] example output (30 is 5 * 6 (skip 4), 24=4*6 (skip 5), 20=4*5 (skip 6))


var a = [];
function makeArray(){
    a = [];
    var len = ran(3) + 3; // array len [3,6]
    for(var xint = 0;xint < len;xint++)
        a.push(ran(9) + 1); // ran num [1,10]
}
function ran(max){ // [0,max] inclusive
    return Math.round(Math.random() * max);
}

// payload algorithm
function payload(){
    var o = [];
    for(var xint = 0, len = a.length;xint < len;xint++){
        var product = 1; // placeholder that will adapt to any value, instead of starting at value x
        for(var yint = 0, len2 = len;yint < len2;yint++){
            if(xint == yint) continue;
            product *= a[yint];
        }
        o.push(product);
    }
    return o;
}


function test(){
    makeArray();
    var o = payload();
    console.log("\n========\nArray input: " + a.toString() + "\nyields the output: " + o.toString());
}

// tests
test();
test();
test();
test();

Tuesday, February 14, 2023

Coding Challenge #2

 Daily Coding Problem #1 2023-02-13

Problem: Given an array of numbers and second number N, check whether any two of the numbers in the list add up to number N.

// ary of random size [3,33] with random numbers in range [0,30]
var a = [];
function makeAry(){
    var o = [];
    var cuanto = Math.round(Math.random() * 30) + 3;
    for(var xint = 0;xint < cuanto;xint++)
        o.push(Math.floor(Math.random() * 30));
    return o;
}
function ran(max){
    return Math.round(Math.random() * max);
}
function check(n){
    for(var xint = 0, len = a.length;xint < len;xint++){
        for(var yint = 0, len2 = len;yint < len2;yint++){
            if(xint == yint) continue;
            if(a[xint] + a[yint] == n){
                console.log("Math: xint(" + a[xint] + ") + yint(" + a[yint] + ") = n(" + n + ")");
                return true;
            }
        }
    }
    return false;
}
function test(n){
    if(check(n)) console.log("Success! Two of the " + a.length + " numbers added up to " + n + "!");
    else console.log("None of the " + a.length + " numbers added up to " + n + ".");
}

a = makeAry();
test(ran(50));
test(ran(50));
test(ran(50));

Monday, February 13, 2023

Coding Challenge #1

Answer to Challenge #399 from https://www.reddit.com/r/dailyprogrammer/

 // add up all letters in a string, with 'a' being 1 and 'z' being 26. Other characters have value 0.
// we will elect to change uppercase to lowercase to make this solution a little more flexible.

var aVal = 'a'.charCodeAt(0);
function letterVal(s){
    if(s >= "a" && s <= "z") return s.charCodeAt(0) - aVal;
    else if(s >= "A" && s <= "Z") return s.toLowerCase().charCodeAt(0) - aVal;
    else return -1;
}
function evaluate(str){
    var o = 0;
    for(var xint = 0, len = str.length;xint < len;xint++)
        o += letterVal(str.charAt(xint)) + 1;
    return o;
}

For example, evaluate('a') would return 1, evaluate('b') would return 2, and evaluate('5') would return 0.

Sunday, February 12, 2023

JS + Canvas: Animated Health Bar, Varying Speeds

Was playing Pokemon 8 (Sword/Shield) and noticed that the opponent pokemon's HP bar moved slower when it only had a little HP left. But I used the same attack, no crits, no atk/def stage changes. So the speed of the bar was limited so that the animation could play out for a set period of time. It made me wrongly think the pokemon was going to endure the hit due to slow bar depletion speed, kind of annoying misinformation >.> though just a chance roll of the numbers that made it so slow. But anyway that made me want to do a bar that has a variable change speed but eforced min/max speed.

P.S. I just today realized Hitmonchan & Hitmonlee -> Jackie Chan & Bruce Lee. I thought Hitmonchan was like -chan honorific in Japanese xD

This bar will be on a canvas (rather than a CSS transition,etc) In this, you can specify a number and hit/heal by that number. The HP bar will change in accordance to the settings set. Note: personally, I don't like the way Pokemon 8 HP bars can feel much slower when the bar is lower: this bar is still a little slower at low HP, but was made to lighten the effect: hitting 85% of HP twice in a row will be quick to deplete both times. On the bar, light green is HP and dark green is empty bar

	
	Default Animation Speed  (seconds, limited to [minSpeed,maxSpeed] inclusively)
	
	
min | max
 
Speed (seconds, min & max time the animation can go on for)
|
current / max
 
Health
/

Saturday, February 11, 2023

Where to find the Game ID in a .WBFS file

 So you have a few .wbfs files from your wii game backups. You want their IDs so you can get cheats or cover art for them. Where do you find the ID?

The ID is in the .wbfs file, at offset 512 from the beginning.

To read it, you can:

  •  Open the .wbfs file in a hex editor and go to offset 512 from the beginning. 

 

Or programmatically, you could:

  1. (Make sure the file is at least 800 bytes long, which all .wbfs files should be) and read 800 bytes into a buffer.
  2. Make sure the first 4 bytes are 'W', 'B', 'F', 'S' - without this, we can't be sure it's the expected format or may be corrupted.
  3. Bytes of indices 512 through 534 inclusive should be the ID we seek. Start reading at 512, until you reach a null byte ('\0') or have read byte 534, which is the last byte before a different section. Bam! Done!
  4. But we can also get the game title from bytes of indices 544 through 799 inclusive, again starting at 544 and ending with a '\0' or at byte 799, whichever comes first. IIRC there are more zeroes, and I don't know/didn't look up the 'official format', but the longest game title I found by googling is 103 characters. And I think that longest title is Japanese, so if we figure UTF-16 (2 bytes per char), then that's 206 bytes, but we could assume 256 just to be safe, in case there are even longer titles than the longest I found.

Bam! Now you have the game ID and title of your WBFS file.

View a working example of a console application on GitHub here

Friday, February 10, 2023

Gecko Codes to .gct file (GameCube / Wii)



Please click the blue cheat code title to activate it, and click again to turn it off. Then just save the file into sd:/codes/ for USB Loader GX Wii games, and into usb:/codes/ for Nintendont GameCube games

Force uppercase when opening file (info in tooltip)

Please load a file

Coding Challenge #54 C++ int to std::string (no stringstream or to_string())

Gets a string from an integer (ejemplo gratis: 123 -> "123") Wanted to come up with my own function for this like 10 years ago ...