Careercow Narcissa Wright / Cosmo Wright - Former speedrunner tumbling down

Suicide when?

  • When he runs out of money.

    Votes: 2,399 58.4%
  • Never.

    Votes: 826 20.1%
  • >2 years

    Votes: 883 21.5%

  • Total voters
    4,107
I don't know anything about coding. Did he write an entire game as one entity rather than in smaller chunks that each do a specific thing and work together?

It would appear so; even when all the sections of your function operate in sequence, it is still worthwhile to separate sections into more manageable blocks of functionality for the sake of readability and maintainability.

He also appears to have a habit of accessing information as long access chains, which is fine (if confusing) in C where all the accesses can be (relatively) easily optimized into a single access, but I somehow doubt the same goes for java. Ideally he should be saving references to data and reusing them.

If anyone wants to see the source in full it's here apparently Cosmicblocks on github

This would appear to be some code that generates a shape for each playing piece.
Code:
if (blockType !== 'blank') {
        var oShape = '<circle fill="none" class="oShape" stroke="#000000" stroke-width="5" cx="40" cy="40" r="30"/>';
        var oOutline = '<path class="outline" d="M40,74.5C20.977,74.5,5.5,59.023,5.5,40S20.977,5.5,40,5.5S74.5,20.977,74.5,40S59.023,74.5,40,74.5L40,74.5 z"/>';
    
        SVGString += '<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" x="0px" y="0px" width="80px" height="80px" viewBox="0 0 80 80" xml:space="preserve"><defs></defs>';

        if (blockType == 'circle') {
            //SVGString += oOutline;
            SVGString += oShape;
        }
        if (blockType == 'base') {
            SVGString += '<polygon class="shape" points="62.5,45 62.499,34.999 52.071,35 59.445,27.625 52.374,20.555 44.999,27.93 44.999,17.5 35,17.5 35,27.929 27.625,20.555 20.555,27.625 27.928,35 17.5,35 17.5,45 27.929,45 20.555,52.374 27.625,59.445 35,52.072 34.999,62.499 45,62.5 44.999,52.07 52.374,59.445 59.445,52.374 52.071,45 "/>';
            SVGString += '<circle class="jewel" cx="40" cy="40" r="7.5"/>';
        }
        if (blockType == 'star') {
            SVGString += '<polygon class="shape" points="62.5,45 62.499,34.999 52.071,35 59.445,27.625 52.374,20.555 44.999,27.93 44.999,17.5 35,17.5 35,27.929 27.625,20.555 20.555,27.625 27.928,35 17.5,35 17.5,45 27.929,45 20.555,52.374 27.625,59.445 35,52.072 34.999,62.499 45,62.5 44.999,52.07 52.374,59.445 59.445,52.374 52.071,45 "/>';
        }
        if (blockType == 'ostar') {
            SVGString += oShape;
            SVGString += '<polygon class="shape" points="62.5,45 62.499,34.999 52.071,35 59.445,27.625 52.374,20.555 44.999,27.93 44.999,17.5 35,17.5 35,27.929 27.625,20.555 20.555,27.625 27.928,35 17.5,35 17.5,45 27.929,45 20.555,52.374 27.625,59.445 35,52.072 34.999,62.499 45,62.5 44.999,52.07 52.374,59.445 59.445,52.374 52.071,45 "/>';
        }
        if (blockType == 'plus') {
            SVGString += '<polygon class="shape" points="62.5,35 45,35 45,17.5 35,17.5 35,35 17.5,35 17.5,45 35,45 35,62.5 45,62.5 45,45 62.5,45 "/>';
        }
        if (blockType == 'oplus') {
            //SVGString += oOutline;
            SVGString += oShape;
            SVGString += '<polygon class="shape" points="62.5,35 45,35 45,17.5 35,17.5 35,35 17.5,35 17.5,45 35,45 35,62.5 45,62.5 45,45 62.5,45 "/>';
        }
        if (blockType == 'cross') {
            SVGString += '<polygon class="shape" points="59.445,52.374 47.071,40 59.445,27.625 52.374,20.555 40,32.929 27.625,20.555 20.555,27.625 32.929,40 20.555,52.374 27.625,59.445 40,47.071 52.374,59.445 "/>';
        }
        if (blockType == 'ocross') {
            SVGString += oShape;
            SVGString += '<polygon class="shape" points="59.445,52.374 47.071,40 59.445,27.625 52.374,20.555 40,32.929 27.625,20.555 20.555,27.625 32.929,40 20.555,52.374 27.625,59.445 40,47.071 52.374,59.445 "/>';
        }
        if (blockType == 'arrow1') {
            SVGString += '<polygon class="shape" points="22.42,57.58 46.762,52.419 40,47.071 59.445,27.626 52.374,20.555 32.929,40 27.582,33.238 "/>';

        }
        if (blockType == 'arrow11') {
            SVGString += oShape;
            SVGString += '<polygon class="shape" points="22.42,57.58 46.762,52.419 40,47.071 59.445,27.626 52.374,20.555 32.929,40 27.582,33.238 "/>';
        }
        if (blockType == 'arrow2') {
            SVGString += '<polygon class="shape" points="40,64.861 53.563,44 45,45 45,17.5 35,17.5 35,45 26.438,44 "/>';
        }

        // ... it continues for a couple more pages like this

        // Cosmo apparently doesn't know that else if statements are a thing, as such each string comparison must be evaluated every time the function is called.
        //   This is a very bad thing. A good alternative would be switches, or dictionaries of functions.
}
Yes, those are indeed polygons encoded as text. This isn't necessarily a bad thing, but he should probably abstract the idea of a playing piece, and have separate definitions for each type. This will keep things much more orderly, and make it easier to extend the game in future.
 
Last edited:
Oh, God, he doesn't know about "switch", does he?

That's really not the issue. The issue is the plethora of " magic strings" (enum is better IMO) and repeated code that should be organized into a lookup table or equivalent.

Narcissa's code suffers the same issues (the solution is appropriate use of js and maybe jQuery)
 
Is he self-taught? EvaXephon has about the same skill level but I thought he had a degree in some tech-related field.

I imagine a collab of both would result in no progress.
 
  • Thunk-Provoking
Reactions: awoo
Oh, God, he doesn't know about "switch", does he?

I don't know what started this myth about a switch block being in any way better than a lengthy if-else chain, since I see it regurgitated so often in /v/ threads about YandereDev. Sure, it is a little more DRY, but it doesn't solve the piss-poor control flow. In fact it makes it worse since most switch implementations require `break` statements and other fuckery which needs to be maintained

This issue in particular would be better solved as covered by @awoo

As for Narcissa's code I can't say I expect anything better from a crazy person
 
I don't know what started this myth about a switch block being in any way better than a lengthy if-else chain, since I see it regurgitated so often in /v/ threads about YandereDev. Sure, it is a little more DRY, but it doesn't solve the piss-poor control flow. In fact it makes it worse since most switch implementations require `break` statements and other fuckery which needs to be maintained

This issue in particular would be better solved as covered by @awoo

Some people believe the "if else" statements are responsible for the poor performance of the game too, which is another misconception. The game runs like ass because yandereDev uses huge poly count meshes for collision.

But I'll stop here because this thread is about Narci, and I still think his code is not that bad for a single person project, just needs a small refactoring.
 
I don't know what started this myth about a switch block being in any way better than a lengthy if-else chain, since I see it regurgitated so often in /v/ threads about YandereDev. Sure, it is a little more DRY, but it doesn't solve the piss-poor control flow. In fact it makes it worse since most switch implementations require `break` statements and other fuckery which needs to be maintained

Agreed, the problems in the examples we've seen are so multi-faceted that merely changing selection-statement format would solve very little in fixing the root causes. I do want to address your stance on the switch-statement bias, though:

There's nothing objectively "wrong" with if-elif-else chains, nor is there anything objectively "right" about switch statements. However, switch statements tend to be preferred in many situations for a few main reasons:
  • Most modern language compilers convert a switch statement to a jump table which gives you O(1) performance. In a large chain this can yield a significant performance increase.
  • Reducing the amount of branches in a particular selection statement chain reduces the amount of branch predictions in the pipeline, which in turn will reduce the amount of branch mispredictions. A jump table eliminates this risk entirely and only has to concern itself with branch target misprediction.
Choosing the selection-statement format that best works then depends on the context. In situations where you want full coverage in a final branch case, you would likely choose an if-elif-else structure. In situations where you don't want (or don't care about) full coverage, a switch statement is better.
 
Last edited:
He could always just use polymorphism to differentiate the different types of block. :geek:

If that's a little too OOP for him then enums and switches would indeed be the best option, as they would generally produce a O(1) jump table to the various cases. If that's too scary and new for him, he should just add an else in front of each of those ifs. His code as it stands is evaluating every string comparison in sequence; not even stopping when one evaluates true :stress:

It's bizarre frankly, reading through some of his other code he clearly knows what an 'else if' is, but for whatever reason he isn't using them for some of the renderer code.

Also check out this glorious mess;

Code:
function getMoves(blockType) { // used for highlighting blocks
    var blockList = {
        'base': function () { return [[-1,-1], [0,-1], [1,-1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]]; },
        'star': function () { return [[-1,-1], [0,-1], [1,-1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]]; },
        'ostar': function () { return [[-2,-2], [0,-2], [2,-2], [-2, 0], [2, 0], [-2, 2], [0, 2], [2, 2]]; },          // A dictionary of functions is not a bad idea,
        'p1': function () { return [[-1,-1], [0,-1], [1,-1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]]; },                     // but it's probably better to not to allocate one EVERY CALL
        'p2': function () { return [[-1,-1], [0,-1], [1,-1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]]; },
        'plus': function () { return [[0,-1], [-1, 0], [1, 0], [0, 1]]; },
        'oplus': function () { return [[0,-2], [-2, 0], [2, 0], [0, 2]]; },
        'cross': function () { return [[-1,-1], [1,-1], [-1, 1], [1, 1]]; },
        'ocross': function () { return [[-2,-2], [2,-2], [-2, 2], [2, 2]]; },
        'hbar': function () { return [[-1, 0], [1, 0]]; },
        'ohbar': function () { return [[-2, 0], [2, 0]]; },
        'vbar': function () { return [[0, -1], [0, 1]]; },
        'ovbar': function () { return [[0, -2], [0, 2]]; },
        'tlbr': function () { return [[-1, -1], [1, 1]]; },
        'otlbr': function () { return [[-2, -2], [2, 2]]; },
        'bltr': function () { return [[-1, 1], [1, -1]]; },
        'obltr': function () { return [[-2, 2], [2, -2]]; },
        'arrow1': function () { return [[-1, 1]]; },
        'arrow11': function () { return [[-2, 2]]; },
        'arrow2': function () { return [[0, 1]]; },
        'arrow22': function () { return [[0, 2]]; },
        'arrow3': function () { return [[1, 1]]; },
        'arrow33': function () { return [[2, 2,]]; },
        'arrow4': function () { return [[-1, 0]]; },
        'arrow44': function () { return [[-2, 0]]; },
        'arrow6': function () { return [[1, 0]]; },
        'arrow66': function () { return [[2, 0]]; },
        'arrow7': function () { return [[-1, -1]]; },
        'arrow77': function () { return [[-2, -2]]; },
        'arrow8': function () { return [[0, -1]]; },
        'arrow88': function () { return [[0, -2]]; },
        'arrow9': function () { return [[1, -1]]; },
        'arrow99': function () { return [[2, -2,]]; },
        'blockade': function () { return [[]]; },
        'blank': function () { return [[]]; },
        'ice': function () { return [[]]; },
        'knight': function () { return [[1, 2], [2, 1], [-1, 2], [2, -1], [1, -2], [-2, 1], [-1, -2], [-2, -1]]; },
        'mine': function () { return [[]]; },
        'reclaim': function () { return [[]]; }
    };

    if (typeof blockList[blockType] !== 'function') {
        console.log ("SHIT! SHIT!");                                // cool error messages dude
        throw new Error('Invalid action.');
    }

    return blockList[blockType]();
}

This was declared as a function local, and unless javascript has some insightful optimizations; he is allocating a dictionary, selecting one result, and then throwing the rest away :story:

Lazy initialization could be used here; just declare the dictionary as a static variable (or whatever java's equivalent is), then test to see if it's been initialized, and if not, initialize it.
 
I wish I knew why this code was so bad. I guess either way I'd still think it looks like shit.
This is absurd. Let me explain: He needs to look up a word and doesn't have a dictionary. So he creates a dictionary, looks up the word, then destroys the dictionary. Every time he needs to look up a new word, he recreates the entire dictionary from scratch and destroys it again. Needless to say, he should simply keep the dictionary.

The code works, but it's laughably bad. It's clear that Cosmo doesn't understand his own code.

It looks to me like an attempt to avoid having 40 consecutive if statements (which he does elsewhere in the code). He missed the mark slightly and made something exponentially less efficient instead.
 
I don't usually watch Narcissa's streams, but is it normal for her to completely stop playing a game to mug the camera? I briefly watched a tiny bit of her stream of Breath of the Wild today, and I swear, she put the controller down for several minutes just to pose and show off her new hair. I don't know what was stranger. The faces and poses she was making or her rabid viewers who were eating this shit up and applauding it like they were seals at a circus.
 
Cosmo got a boyfriend? Their chemistry is "awkward cute" or who's the person currently in Cosmo's stream

edit: those two videos, at least the beginning, are quite...something



At least he's not *that* delusional, unlike before

Edit: scratch that, he's still a fiend and wants dopamine because he can't function without drugs, yikes
 
Last edited:
She really has no clue does she? wow. Maybe one day she will figure out the answers to these questions. Dear lord.
 

Attachments

  • 2018-05-09 15_34_46-NarcissaWright - Twitch.png
    2018-05-09 15_34_46-NarcissaWright - Twitch.png
    7.2 KB · Views: 617
  • Thunk-Provoking
Reactions: Catetive
Seems like he's been only getting 120~ views tops on his Zelda speedruns. Compared to his glory days... yikes.

His runs are waaay too long (5-6 hours) who has time to watch all that in one sitting? He should do the most popular run, IMO.
 
Seems like he's been only getting 120~ views tops on his Zelda speedruns. Compared to his glory days... yikes.

His runs are waaay too long (5-6 hours) who has time to watch all that in one sitting? He should do the most popular run, IMO.
When you think about it, Wind Waker was a pretty long run, about 4-5 hours if I remember correctly. Still raked in views by the thousands. Seems like no run he does now can help.
 
Back