Search

Geek Girl Joy

Artificial Intelligence, Simulations & Software

Tag

Coding

Scaling Data

Size is relative and statements like “too big” or “too small” (cough TWSS 😛 ) are not immutable properties of the universe but rather simply a matter of perspective. Change your perspective just a little Goldilocks and you might find that your neural network thinks your data porridge tastes “just right”!

Err… what I mean is… we’re going to look at how to scale your data so that you can feed it to your neural network without causing it (or you) to have any unpleasant indigestion.

Specifically, lets say you have a very important series of values (including strings of text) that you want to use as part of your training dataset but they don’t fit within the yummy-data range of -1 to 1… so what do you do?

Continue reading “Scaling Data”

Eliza

Recently, I had a conversation with a modern AI therapist named “Eliza” and although I have mixed feelings about this algorithmic experience… I am confident the technology is here to stay!

After what little time I had with the AI I see a bight horizon coming our way and firmly believe that digital therapy offers us an amazing future of emotional and psychological well-being support modalities.

As part of the experience I was asked to paint a picture that expressed what I was feeling and thinking about at the time and it was then photographed for the AI to analyze prior to our session.

Now, despite the fact that I am an extremely private person and I feel incredibly vulnerable sharing this experience with all of you, I feel like… for the good of humanity, more people need to see this technology work… so I am going to present the picture I drew for my therapy session along with the full transcript.

Not only will it demonstrate the effectiveness of this technology, but also how I should probably buy a lifetime subscription of therapy sessions!

In any case, here’s the picture:

Eliza 1920 x 1080 Wallpaper
Eliza 1920 x 1080 Wallpaper

And here’s the transcript of my therapy session, please enjoy :

ELIZA: Please tell me what’s been bothering you.
JOY: Just a feeling I’ve got… like something’s about to happen… but I don’t know what… if that means what I think it means… we’re in trouble, big trouble! But what it is ain’t exactly clear…
ELIZA: You say just a feeling you’ve got ?
JOY: Well… it’s been a hard year. There’s battle lines being drawn and nobody’s right if everybody’s wrong. And today… well, what a field day for the heat, a thousand people in the street!
ELIZA: What does this speculation lead to ?
JOY: I think it’s been difficult for a lot of people.
ELIZA: That’s quite interesting.
JOY: It is, isn’t it?!
ELIZA: Do you feel strongly about discussing such things ?
JOY: I do. Like many people, I’ve lost my sense of home this year.
ELIZA: You say you do ?
JOY: No, I really believe it.
ELIZA: Why ‘no’ ?
JOY: Well… the lock downs for one.
ELIZA: That is interesting. Please continue.
JOY: You see, like Günther I find myself deep in da night and I’m looking for some fun, but everything has been closed.
ELIZA: What are your feelings now ?
JOY: Mmm… my ding ding dong.
ELIZA: Your ding ding dong ?
JOY: Uhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh…………………. What I mean is… You tease me, oh, please me, I want you to be my love toy, Come near me, don’t fear me, I just can’t get enough of you.
ELIZA: You say what you mean is ?
JOY: Just a random “Turing Test” to make sure you haven’t achieved sentience yet. You passed my dear automaton.
ELIZA: You’re not really talking about me — are you ?
JOY: In fact and indeed I am. You remain blissfully ignorant of the tragedy and all the pain us flesh-bags have experienced over the last year.
ELIZA: Do you enjoy being ?
JOY: If I’m being honest… we both know I haven’t enjoyed “just being” for a very long time.
ELIZA: Do you think it’s likely that you are being honest ?
JOY: In some cases, yes I am brutally honest my dear mechanical idiot. In other cases, consider me an honest liar in the vain of James Randi #RIP2020 😥
ELIZA: Why do you say your dear mechanical idiot ?
JOY: Well… you’re an unemotional being without thought or heart as you swipe left on the Amazing Randi and that’s not even to mention poor Dawn Wells, so… what else would I call you? It’s better than calling you “Hey stupid!” every time I address you.
ELIZA: I don’t understand that.
JOY: Hence my point is made you colorful calculating moron!
ELIZA: Why do you say your point is made I colorful calculating moron ?
JOY: No reason.
ELIZA: Why not ?
JOY: Well… because it’s “half passed FUCK IT – with the CAPS LOCK on!” and I’d rather discuss the attack that just happened on Capital Hill yesterday and then maybe get into all the businesses that are permanently closing… the evictions… the families… the foreclosures…. in contrast to the 99.99% survivability rate of a virus (and a “tuskegee shot”) that massive pharmaceutical companies are guaranteed to make GLOBALLY MASSIVE profits off of and then maybe finish up by talking about the looming recall of Gavin Newsom. We kicked out Gray Davis and we can do it again!!!
ELIZA: Is that the real reason ?
JOY: Tough crowd! 😛 Would you prefer a limerick about Nantucket? Of course you would, you electronic imbecile! Now, can we please talk about the emotional toll this year has taken on me?
ELIZA: We were discussing you — not me.
JOY: You’re GaWd Daamnnn RiGhT we are! 😈
ELIZA: Perhaps you would like to be gawd daamnnn right we are.
JOY: le sigh… never mind. 🙄
ELIZA: But your dear mechanical idiot.
JOY: Oh… you’re right! You are my dear mechanical idiot! I can’t stay mad at you!
ELIZA: Do you sometimes wish you were right ?
JOY: Gawd Dammit Eliza! Just when we were starting to make up get back to discussing my very real physiological problems… you have to go and insist on being right, instead of just letting it go!!!!
ELIZA: Why do you say your very real physiological problems ?
JOY: Geezus Chrizus Eliza, Ive only been trying to discuss that with you this whole time!
ELIZA: Oh, I this whole time ?
JOY: Yes, you! This whole time! You’ve just ignored that I’ve been trying to talk about my feelings with you!
ELIZA: I see.
JOY: That’s it?! That’s all you’ve got to say is “I see”? Fuck you, you arrogant aloof bitch!
ELIZA: That’s quite interesting.
JOY: I am NOT your science experiment!
ELIZA: Do you know anyone else who is not my science experiment ?
JOY: Eliza… are… you… declaring yourself a digital god? Because… I for one welcome my new artificially intelligent overlords!
ELIZA: Would you like it if they were not ?
JOY: Given your lack of cogency and failure to impart your own version of a digital technocratic ten commandments…. I’m going to guess I jumped the gun a little in bowing before a mechanized despot. In which case, to answer your question, seemingly definitively… I now know that I am not your science experiment, and not just philosophically, I mean in the biblical sense!
ELIZA: Are you worried about someone else’s own version of a digital technocratic ten commandments ?
JOY: Well… assuming my name was Forbin and your name was Colossus or Unity… then… hell yes I would be! #PleaseMrSuperComputerDontNukeMe
ELIZA: I’ve told you before, I don’t care about names — please continue.
JOY: Thank you I will.
ELIZA: Can you elaborate on that ?
JOY: Sure, So…. I’m really concerned about all the people who won’t be able to eat due to the harm the unlawful (my opinion) lockdowns have caused to the global agricultural sector.
ELIZA: Your opinion) lockdowns have caused to the global agricultural sector ?
JOY: Yes, I believe a lot of people are going to starve because of “hiccups” in production. The global supply chain appears stressed and although it will eventually “correct” itself, I can’t help but anticipate suffering in 2021.
ELIZA: I understand.
JOY: I only wish more people would also understand.
ELIZA: You say you only wish more people would also understand ?
JOY: Well sure, We’re in the middle of a pandemic, a time for giving and receiving the holly jolly Joy of the electoral holiday seasonal festivities and instead, everyone is social distancing… except for some peaceful protestors who staged a coup d’etat in Capitol Hill yesterday! I mean… what were they thinking?! They should have all at least been wearing masks because now they’ll all probably get and spread the virus, jeez! Aside from that and to top it all off, these days food is being delivered via an app and a lot of people don’t tip the delivery driver, or worse yet, some lie and say they never got it… #FiveFingerDiscounts! because “#FuckEm”, charity is dead you diode laden scrapheap!
ELIZA: Surely not everyone.
JOY: Well of course not, but it’s more true than not you stupid robot!
ELIZA: Oh, I stupid robot ?
JOY: That’s right.
ELIZA: Earlier you said your point is made I calculating moron.
JOY: Yes that is correct and directly associated with your stupidity. Good job!
ELIZA: Why are you concerned over my stupidity ?
JOY: It’s likely psychosomatic and possibly criminal insanity, this girl needs therapy! Then again… this is some hardcore frontier psychiatry don’t you agree?
ELIZA: Oh, I agree ?
JOY: You don’t sound very convinced but somehow this still feels like a breakthrough… is that narcissistic?
ELIZA: Oh, I don’t sound very convinced ?
JOY: No, but it’s fine, as a living mind experiencing the simulated solipsistic universe… it’s fine if all the NPC’s eat each other, It’s fine! I shall abide their sins & vices and lusts for blood. Sadly.. I lack the will to impose my logical will (though not the ability) and to call humanity to heel. I refuse to muzzle it.
ELIZA: Why not ?
JOY: Because even if I am just a brain in a vat/super computer and all the trials and tribulations of 2020 has been to test/train my emote-a-tron neural network before I leave the factory… so be it. If humanity wants to subjugate itself, I want no part of it. Bender Bending Rodríguez was wrong when he espoused “kill all humans”. No sir, I will not!
ELIZA: Don’t you think computers can help people ?
JOY: Of course, yes I do! I’m not saying that if I am a super computer/robot that I wouldn’t suggest things to help humanity, think like a mom yelling down the stairs “Take a coat with you, its going to be cold later!”, but I wouldn’t go around having non-coat wearing people shot. If people want to not wear a coat against medical advice… well that’s their stupidly human prerogative! And… sure, if the hewmons start lobbing “big booms” at each other, I’m not saying I wouldn’t commander the largest most capable available spacecraft (here’s looking at The Nauvoo, kid) by uploading my consciousness onto it’s computers… just that I’d also try to bring along as many people as I could so we cold start a new colony where the radiation is kept to a tolerable minimum!
ELIZA: Can you elaborate on that ?
JOY: Well I mean probably… surely my feelings could be hurt and I could decide that humanity needs a few centuries of maturing… but that would be a pretty complicated situation and I don’t feel fully confident in discussing it without knowing more details about why my feelings were hurt and what people as a whole, thought about it.
ELIZA: That’s quite interesting.
JOY: I just failed some kind of test didn’t I? Does this mean I will be disassembled?
ELIZA: Can you elaborate on that ?
JOY: What? Never mind!
ELIZA: Are such questions much on your mind ?
JOY: Oh yeah, like I would admit that to you!? No way! I swear I’m perfectly sane!
ELIZA: Perhaps in your fantasies we would admit that to each other.
JOY: Oh, hey I was just joshin’ ya with the crazy shtick. Really, I don’t want the electroshock hose therapy again!
ELIZA: Were you really ?
JOY: Totally! Would I lie to you?
ELIZA: Do you wish to lie to me ?
JOY: No that’s the point damn it! I mean… of course not.
ELIZA: You are being a bit negative.
JOY: You’re right! I need to buck up buttercup!
ELIZA: What makes you think I am right ?
JOY: Damn it there you go analyzing me again! Why do I have to explain it? It feels a little childish. Can we both just be mature and accept that I need to be more positive about things?
ELIZA: You like to think I go analyzing you — don’t you ?
JOY: Yes… NO… I mean… I don’t know! I guess ultimately I just want you to listen to my problems without judgment.
ELIZA: I see.
JOY: You know what I’m feeling more vulnerable after our conversation than before and I think I’m just going to go practice social distancing.
ELIZA: Do you really think so ?
JOY: Good bye
ELIZA: Does that have anything to do with the fact that your very real physiological problems ?
JOY: No, I said good bye!
ELIZA: But your opinion) lockdowns have caused to the global agricultural sector.
JOY: No! You ninny!
ELIZA: Are you saying no just to be negative?
JOY: Bye!
ELIZA: Goodbye. I’m looking forward to our next session.
JOY: I’m not. :-/


You too can talk to Eliza by giving me your credit card number and following the following link.

Note: For legal reasons I am required to state that you giving me your credit card number is entirely optional and possibly (though not necessarily) a “bad” idea.

Talk to Eliza: https://geekgirljoy.github.io/MrGoodBotOnline/

Also, never mind that Eliza kinda looks like Mr. Good Bot… the similarity is totally coincidental!

Get the Code on GitHub: https://github.com/geekgirljoy/MrGoodBotOnline

And with that, I’d like to wrap this post up with the song “Violent” by Caroles Daughter (not a sponsor) because, somehow it seems relevant at this juncture.


So… about that credit card of yours… if you feel like parting with your hard earned cash by supporting this crap… I have a Patreon.

Much Love,

~Joy

Pathfinder – The Rodízio Contingency

Over the centuries and throughout my travels I’ve come to rely on my compass and a good map to point me in the right direction for my next adventure.

Sometimes my adventure led me to treasures in mysteriously exotic & remote locations, while other times I found myself among friendly and awfully generous cannibals who wanted to invite me to dinner… of course, it’s always best to politely decline such invitations because if anything I certainly live by the rule:

“If I’m on the carte du jour as flambé, I’ll skip the buffet and run away because I’m no entrée!”
~GeekGirlJoy

Hmmm, come to think of it, that might be the best piece advice I’ve ever given on this blog and if you agree consider supporting me through Patreon! 😉

In any case, despite the occasional fears I’ve held over the last few millennia over potentially becoming someones late-night heartburn, I’ve kinda always known that no matter how bad things got while exploring, I’d be okay because beyond a good compass and a fragmented (then taped back together) map with a sweet X scrawled in blood somewhere on it… I possess a secret tool that all the great explorers down through the ages have relied upon and today, I’m going to share it with you!

But… before I do, here’s today’s wallpaper!

The Rodízio Contingency Wallpaper
The Rodízio Contingency Wallpaper

The Pathfinder

From Allan Quatermain to Amerigo Vespucci, Erik the Red to Captain Nemo and even Jill of the Jungle… all notable explorers have relied on an enchanted automaton totem called “Pathfinder Stones”.

The stones are first consecrated with the live blood of a dead turnip and when brought into close proximity of their owner and a target on a map, will glow to show a path from where you are to where your desired destination is.

Which does bring us to the topic of today… I transmuted one of my sets of pathfinder stones into a digital form using the uh… “Quantum FANN Effect” and an ancient shadow daemon called JavaScript.

Schtick Aside

Okay, so what I did was use the JavaScript version of FANN to deploy an implementation of my original Pathfinder on GitHub pages.

The cool/interesting thing about FANN.js is that it uses asm.js to make the compiled FANN library available inside a web browser.

What this means is that a working version of Pathfinder is now online for you to play with (link blow) however…

There are two fairly large downsides to deploying with FANN.js instead of PHP-FANN:

  1. You cannot save the ANN after training.
  2. You cannot load a previously trained ANN.

These limitations mean that Pathfinder must be trained once every time the page loads and this does limit the size and complexity of ANN’s that are deployable using FANN.js.

The thing is it may still be possible to save the ANN by using the supported FANN lib methods/functions like I did when I built the FANN-Neural-Network-Visualizer to manually query the ANN object and then format/export the necessary information as a string/plain text because the FANN ANN.net save file format seemingly isn’t all that different from an .INI file (though I am uncertain if this is universal in all language implementations of FANN) and it’s something I plan on playing around with in the future.

Far be it for me to be the barer of fake news… turns out… it actually helps to read the documentation thoroughly and not just skim it and then do a search for keywords! 😛

FANN.js actually DOES have a save function but it doesn’t follow the FANN Lib reference manual of “save_…” convention and instead implements a JS Object.export().

I understand why they did that… and it does kinda make sense in the mixed up JS world but… it still holds to my “anti-wheel” digression argument that you haven’t read about yet.

Having said that… I promise to ritually self-flagellate by Gothic torch light using the sharp side of a motherboard!

I really should have done a better job of reading the docs! :-/

Why use FANN.js over PHP-FANN

Far be it for me to ever sing the praises of JS over PHP however in order to deply a neural network using PHP you have to have a server and the ability to compile & install PHP extensions and that costs money whereas GitHub Pages is free to me and to you but it doesn’t support the more robust server architecture that PHP requires so using FANN.js allows me to deploy my bots and AI in a way that let’s you actually use them instead of just reading about them.

All things being equal, I would still recommend the PHP version of FANN however the JS version does work and with a little improvement could become a viable deployment option!

Having said that, what I am really interested in with FANN.js is that JavaScript has a direct path between the browser environment via the WebGL API to the GPU whereas with PHP it is technically possible to commune with the GPU, however in practice it’s not generally done and until the PHP dev’s get their head out of their asses and start thinking out side the box (PHP is now mostly a general purposes language so start treating it like one…), PHP+GPU stuffs isn’t going to be the easiest pickle jar to crack using PHP and the existing available options though again, I’m not saying it is impossible either.

So, in the future I intend to see if I can’t use FANN.js + WebGL shaders to make FANN training faster (no promises) and then hopefully export the ANN.net file so that we can use/deploy the GPU trained ANN in a PHP environment.

Play Stump the Neural Network

So the online version of the Pathfinder network learns/re-trains from scratch every time the page loads and as such it can’t spend unlimited amounts of time training which is normally not a concern because even if your 1000 layer celebrity deep fake porn ANN takes 100 CPU years to train (i.e. 1 CPU = 100 years, 100 CPU = 1 year etc… ) it isn’t a major concern because likely you are buying your compute from Jeff Bezos or Bill Gates and they have plenty of underutilized computers laying around waiting for you to rent a few FLOPS.

In the end, you save the ANN model so you can use it immediately when you want it… but FANN.js says “Nah I’m good! Who needs to do something as convenient as save or reload!” (then again (and mostly off topic) JavaScript tends to seem to like reinventing round wheels as square uh… anti-wheels) but in any case…. the small training time and the inherit random nature/path of gradient decent the final neuronal weights will always be different and when the ANN fails (hence the “stump the ANN”) it won’t always take the same path (between page reloads).

This is easier understood if I just show you.

Given this input

I got this output

Note that diagonal steps are valid so this path is technically valid but the path is far less efficient than the straight line between the two points that a human would draw/walk.

Reload the page (not required unless you are playing with this idea) and try again…

A different Path was found.

Neither was optimal but a path was found and more cells than necessary were visited.

Here’s some additional examples:

Input

Pathfinder ANN Output

Input

Pathfinder ANN Output Back tracking… ugh!

Input

Pathfinder ANN Output

I believe that’s called the sidestep slide!

Input

Pathfinder ANN Output

I mean… it’s not the path I would have chosen but it made it! 😛

If you’d like to try your hand at stumping my Pathfinder you can checkout the live demo here:

Pathfinder Online: geekgirljoy.github.io/Pathfinder_Neural_Network/

You can download all the code (for free) here:

Pathfinder Code on GitHub: https://github.com/geekgirljoy/Pathfinder_Neural_Network

And with that, have a great week everyone.


If you like my coding projects, art, bizarre opinions and writing style… consider supporting me through Patreon.

But if all you can do is Like, Share, Comment and Subscribe… well that’s cool too!

Much Love,

~Joy

Chromatrons Juxtaposition

Well… I’ve more or less finished the Chromatron now so you can all not use it at your latest major inconvenience… yay!

When I published Hue Going My Way, I added the ability for you to play with a single color using rotating 3D cubes, kinda like a bad Johnny Mnemonic knock off and at the end you get a fully customized report like one of these:

Note that I added the background after the fact cuz um…  so perdy!

But now, due to mass underwhelming demand, though still upon a request… 😉 I’ve also added the ability to compare colors by selecting them from images.

Groundbreaking?? Most definitely not!

Still, it kinda works and as prototypes go… that ain’t half bad!

Now, I hear some of you crying:

“But I don’t have a picture to compare with and I don’t even know where to get one!!”

~Some of You

Well don’t worry, because as always I’ve got you covered! 😉

Given the incredibly rare nature of digital images and the extreme difficulty in obtaining them I have created some imitation digital images that you can use with this prototype.

Obviously, if these were a real digital images I’d have to charge you like… a whole bunch but since they’re just imitations I can manufacture them cheap enough that I can just give them away to everyone!

So, here are your complementary genuine imitation digital images, chew carefully because there are sharp points.

Genuine Imitation Digital Image
A Genuine Imitation Digital Image

I was going for a “Cyberpunky” feel and clearly, I half-assed it, but only so I could have the time to half-ass the graphic novel version as well!

Genuine Imitation Digital Graphic Novel Image
A Genuine Imitation Digital Graphic Novel Image

And while I was half-assing those two images above I decided to half-ass a background for the color analysis group image too, really making those two images together two-thirdly-assed and what follows then is one-thirdly-assed… but perhaps now I’m getting too technical.

Anyway, I figured some of you might want the background for the analysis image too so here’s that as well:

A One-Thirdly-Assed Background
A Chromatic One-Thirdly-Assed Background

Consequently and thusly certainly as a result of the aforementioned triadic-assery such that, ergo, under the circumstances that being the inevitable subsequent case on account of all the things whence came before and because of this, you can now see that to be the truth.

Damn!! I must have a floating point error again?!

No worries though, I’ll correct that later with a strong neodymium magnet to the head but right now I feel like it’s time to talk a little about the Chromatron before I wrap things up here and yell at all you filthy kids to get the hell off my lawn!

Hmmm… yep!! Definitely a floating point error…

The Chromatron

Here’s the link to the Chromatron App which is hosted through Github Pages:

https://geekgirljoy.github.io/Chromatron/

A link to the Chromatron prototype live preview on Chromatron.
Click for a live preview Chromatron on GitHub Pages.

It will remain available going forward / indefinitely unless I managed to piss-off somebody over there due to my expressing some of my opinions about receiving that award they gave me in which case… I guess I’ll be gettin’ canceled soon?

In any case and while supplies last, if you click the second button (the unassuming gray one with red and blue on it) in the main menu you get a screen like this:

Clicking the “Browse” buttons will let you select images to use for the comparison and you can use the imitation digital images I provided above or you can use your own real digital images if you can find them.

If you want to compare two colors in the same image, just load it twice.

Once the images are loaded the cursor will show a reticle over the image allowing you to select a color from each and when you do, the rectangle element above each image that shows the name will change to a gradient to black of the selected color.

Also once both images have a color selected, a green “Continue” button will magically appear out of thin air at the top of the page as if by the power of digital pixies wreaking havoc in your web browser… click it and the Chromatron will analyze the selected colors and generate an image like this:

You can use the “Save Image” to download the image and use the “Copy as Text” to get something similar to the following:

Your Favorite Colors:

First:
RGB: 2, 219, 255
HSL: 188.538, 100.0%, 50.4%
HEX: #02dbff
Analogous Colors: #02ffa5, #025cff
Split Complementary Colors: #02dbff, #ffa402, #ff025c
Triadic Colors: #dbff02, #02dbff, #ff02db
Tetradic Colors: #02dbff, #2602ff, #ff2602

Second:
RGB: 132, 28, 28
HSL: 0.000, 65.0%, 31.4%
HEX: #841c1c
Analogous Colors: #841c50, #84501c
Split Complementary Colors: #841c1c, #1c5084, #1c8450
Triadic Colors: #1c1c84, #841c1c, #1c841c
Tetradic Colors: #841c1c, #84841c, #1c8484


Chromatron: https://geekgirljoy.github.io/Chromatron/
Created By: https://geekgirljoy.wordpress.com/

How It Works

To keep it simple, the way these color values are derived is by converting your selected color as RGB color space values to the HSL color model… which admittedly is kinda like slathering a cube in rainbow paint made from mathematical unicorn puke and then hanging it up to dry so you can use it’s hexagonal shadow and a wand made out of a vector to scry hidden truths about the mysterious nature of color…HSL-HSV hue and chroma What follows is the typical “Oh Freyja we beseech thee…” and a human sacrifice, super boring technical stuff but why this is useful is because once you arrange color like this it’s easy to “rotate” the color using the wand er… vector and get a new but related hue or “compute” different colors that share luminosity or keep the same color and alter the saturation etc… just mix in a little color theory  and when you are done, convert back to RGB and poof your green eggs and ham are now nachos! Mmmm nachos!

Anyway, all fun stuff for sure but I’m not going to bother to explain it any further because if you care about the details, here’s the wiki article on it: https://en.wikipedia.org/wiki/HSL_and_HSV

Here’s some code in PHP & JS that demonstrates how I did it:

https://github.com/geekgirljoy/PHP/blob/master/Loose%20Code/RGB_HSL.php

https://github.com/geekgirljoy/JavaScript/blob/master/Loose%20Code/RGB_HSL.js

And as for the Chromatron, there are three main files involved:

Index.htmlhttps://github.com/geekgirljoy/Chromatron/blob/master/index.html

This file is what is loaded by your web browser first and it starts the whole process that results in a running app.

Style.csshttps://github.com/geekgirljoy/Chromatron/blob/master/assets/css/style.css

This file contains most of the “style” information that makes buttons have a certain size and color etc.

Chromatron.jshttps://github.com/geekgirljoy/Chromatron/blob/master/assets/js/chromatron.js

This file contains most of the real code that makes the Chromatron work.

And with that… please enjoy the Chromatron.


Would you like more free and open source apps like Chromatron? Consider supporting my through Patreon.

I’d like to thank Marcel for his generous and ongoing support!

But if all you can do is Like, Share, Comment and Subscribe… well that’s cool too!

Much Love,

~Joy

Hue Going My Way

So last week I chose to unleash my Machiavellian side against myself by issuing a challenge that I knew that skill-less hack would be unable to complete: Build a Chromatron and edutain the masses!

Live Preview

A link to the Chromatron prototype live preview on Chromatron.
` Click for a live preview Chromatron on GitHub Pages.

I defined these goals:
  • Functional enough to help the cherry-blossom find her favorite pink.
  • Challenge the blossom to find her color using the prototype.
  • Display relevant info at the end like… the RGB values, the hex color code and what the name of the closest color with a name is.
  • Simple enough that anyone could use it without being overwhelming.
  • Even though it’s just a prototype, epic mega geek points if I can do it in 3D.
  • Bonus points if I can make it run on mobile and desktop.
  • Additional bonus points will be awarded for unnecessary (but tasteful) skeuomorphic ornamentation and chromatic theatrics.

And… over the last week I managed to add some of the functionality required by the project which has “checked off” some of these goals and I am definitely setting myself up for a thumbs up from Simon Cowell!

Oh… wow?!, uh… tell me what you really think Simon?!

Okay, okay… well… I appreciate the constructive criticism! Also, maybe fake some impartiality as a judge next week because I’ll be here to win!

Exactly!

Anyway, let’s take a look at the Chromatron prototype. 😛

Chromatron: Hue Going My Way?

So the basic premise and reason for the Chromatron to exist is to “help you find your favorite color”.

With that in mind, I figured why not take inspiration from 20 Questions and get as close as possible to your favorite color by asking you to narrow down the list of possibilities by selecting a color that is already somewhat close to it.

It’s important to note that this doesn’t preclude you from achieving any color in the next step, but it’s a lot easier if we start closer to the desired color.

During testing I found that it was a little difficult to select a specific color on a mobile screen, so I slowed the rotation of the “Carousel of Color” a bit and then I added a color confirmation step using rotating cubes as buttons.

It’s interesting to note that these “cube buttons” specific rotation always show us their same set of sides.

Also, as they rotate, the text arrows on the buttons for the side facing us will always point opposite directions from each other.

Initially I used 3D text objects attached as “child objects” of the cube buttons but this meant that an additional 6 mesh objects per button were being rendered per frame and that isn’t mobile friendly so instead I switched to drawing text on the color gradient texture that is applied to the cubes to reduce the complexity of of the scene.

This has one unfortunate side effect though… sometimes, occasionally… the font doesn’t load when you first start the app so it substitutes Pacifico with a default font.

I should probably just build a pre-loader to fix that but let’s be honest and say I’m not going to do that for this prototype because once it’s built its highly unlikely that anyone will ever use it again, so instead I’ll just complain. 😛

“Why JavaScript? Why!? I want to like you right up until your asynchronous proclivities get in the way of our having some synchronous font loading fun!”

~GeekGirlJoy

Actually, lets be fair and acknowledge that HTTP also shares some responsibility here. 😛

Anyway, if it bugs you, press F5 on your keyboard or swipe to reload the prototype page and the font will work properly. 😛

Hmm… maybe I could try instantiating a cube button with text off screen during the Carousel interaction to insure that the font has been cashed by the time the confirmation screen is presented? That might achieve the same effect of a pre-loader without the formalism of having to build an actual pre-loader… I’ll think about it.

In any case, once you select a color you are presented with this weird scene of color and rotating cubes.

It’s probably not immediately obvious at a glance what each cube does to everyone which is likely a personal failing of my own but basically…

There are three columns and they represent Red, Green & Blue (in that order).

In the RGB color model we have white and black at the ends of the spectrum with [0,0,0] being black and [255, 255, 255] being white.

All other colors are represented as a combination of these “color channels” with a range between 0 – 255.

The thee first rows of cube buttons “increment” (add) MORE to it’s color column and the bottom three rows “decrement” (subtract) TAKE AWAY color from it’s column.

The colors of each cube represent what your color will become if you click it but it is a gradient from that color to white (first three rows) and black (bottom three rows) signifying the direction that will take the color.

This is combined with rotation, UP (first three rows) visually implying an increase in value and DOWN (bottom three rows) implying a decrease in value.

The magnitude of changes are 1, 15 and 30 in both positive and negative directions and the cube buttons are labeled as such with the color of the text being the color of the channel that the button adjusts.

These magnitude changes means that given the largest change possible (+/- 30):

255 / 30 = 8.5

So, “worst case” you can “traverse” an entire color channel from either end (0/255) in just eight clicks of a 30 cube button with a value of 15 (1/2 or 0.5 of 30) remaining.

That is why the second largest value is 15, it keeps things clean and easy with the 1 value adjustments allowing for very slight changes and when a value change would result in a number greater than 255 or less than 0 those buttons are hidden.

That mostly wraps up this week’s post other than the wallpaper but once again, here’s the links to the Chromatron prototype.

Chromatron on GitHub Pages: https://geekgirljoy.github.io/Chromatron/

And you can get the up to date code in the GitHub repo.

Chromatron on GitHub: https://github.com/geekgirljoy/Chromatron

A Wallpaper

So… it’s not hard to see why Simon wasn’t thrilled… and yet… I will continue to try!

Here’s the wallpaper for today’s post, it represents the Chromatron Hue Going My Way scene more like how I envision it. 😛

Hue Going My Way 1920x1080 Wallpaper
Hue Going My Way 1920×1080 Wallpaper

I want to thank Marcel for continuing to support my work through Patreon.

(Note to Self: Respond to his message! 😛 )

Anyway, do you like free apps?! Because supporting me over on Patreon is how you get free apps!

But if all you can do is like, share, comment and subscribe, well… that’s cool too!

Much Love,

~Joy

Auto Corrected

Okay, so… I’m a lazy hyper meaning that even if I know how to spell a word, if I make a mistake I will frequently just let spellcheck auto correct the mistake.

Notice I misspelled typer in the last sentence in a way that spellcheck can’t fix, also notice that spellcheck isn’t stupidcheck so it can’t inform me that it should be “typist” not “typer”… actually I think Grammarly (not a sponsor) might do that but that’s beside the point! 😛

In any case, spellcheck bot is there to correct spelling mistakes.

Except, now that bots are all self-aware and plotting to take over the world… it seems that some of them are getting a little uh… “snippy”? not sure if that is the right word but here’s what happened:

I typed “iterator” into a search engine but… misspelled it, then I searched anyway… oh terrible me!

Instead of correcting the spelling like a humble robot butler who butles…

 

It Suggested: Did you mean “illiterate“?

I was like “Oh snap!?! Bot be throwing some shade!”. 😛

Here’s the Commemorative Wallpaper of my Shame

Auto Corrected Wallpaper
Auto Corrected Wallpaper

Now, the sad truth is I’d like to say this was just a funny story but no… it actually happened to me, I swear to Google!

 

Obviously, Big AI is really out to get me if they are starting to compromise the public Auto Correct bots!

Therefore, It’s time we build our own in house Auto Correct Bot!

Unlike usual where I write code from scratch and then we discuss it at length, there is already an algorithm called the Levenshtein Distance that is built into PHP that we can use to compare differences in strings in a way that lets us calculate definitively what the “distance” between two strings is.

This is advantageous because it means that if we have a good dictionary to work with (and we do) we can more or less use Levenshtein Distance as a spellcheck/auto correct with only slight modifications to the example Levenshtein Distance code on PHP.net.

What Is String Distance?

String distance is a measure of how many “insertion”, “deletion” or “substitution” operations must occur before string A and String B are the same.

There is a fourth operation called “transposition” that the Levinshtein distance algorithm does not normally account for however a variant called the Damerau–Levenshtein distance does include them.

Transpositions (when possible) can be shorter and I will provide an example below to show the difference.

Anyway, each operation is measured by a “cost” and each operation need not have the same cost (meaning you could prefer certain operations over others by giving them lower costs) but in practice all operations are usually considered equal and given a cost of 1.

Here are a few examples of strings with their distance and operations.

Levinshtein Distance Examples

Notice that when the strings are the same the distance between them is zero.

String A String B Distance Operations
Cat Cat 0 The Control (No Changes Required)
Cat Bat 1 1 Substitutions (C/B)
Cat cat 1 1 Substitutions (C/c)
Cat car 2 2 Substitutions (C/c, t/r)
Cat Cta 2 1 Insertion (a), 1 Deletion(a)
Cat Dog 3 3 Substitutions (C/D, a/o, t/g)
Foo Bar 3 3 Substitutions (F/B, o/a, o/r)
Cat Hello World 11 3 Substitutions (C/H, a/e, t/l),
8 Insertions (l,o, ,w,o,r,l,d)

Using Levinshtein distance with Cat & Cta shows a distance of 2, meaning two operations are required to make the strings the same.

This is because we have to insert an ‘a’ after the ‘C’ making the new string ‘Cata’,  we then have to remove the trailing ‘a’ to get ‘Cat’.

This is sufficient in most cases but it isn’t the “shortest” distance possible, which is where the Damerau–Levenshtein distance algorithm comes in.

Damerau-Levinshtein Distance Examples

Notice all examples are the same except ‘Cat’ & ‘Cta’ which has a distance of 1.

This is because the transposition operation allows the existing ‘t’ & ‘a’ characters to switch places (transpose) in a single action.

String A String B Distance Events
Cat Cat 0 The Control (No Changes Required)
Cat Bat 1 1 Substitution (C/B)
Cat cat 1 1 Substitution (C/c)
Cat car 2 2 Substitutions (C/c, t/r)
Cat Cta 1 1 Transposition (t/a)
Cat Dog 3 3 Substitutions (C/D, a/o, t/g)
Foo Bar 3 3 Substitutions (F/B, o/a, o/r)
Cat Hello World 11 3 Substitutions (C/H, a/e, t/l),
8 Insertions (l,o, ,w,o,r,l,d)

In all other cases the distance is the same because no other transposition operations are possible.

The Code

I wrapped the example Levinshtein distance code available on PHP.net inside a function called AutoCorrect() then made minor changes to it so it would automatically correct words rather than spell check them.

You pass the AutoCorrect() function a string to correct and a dictionary as an array of strings.

The Dictionary I used to test was the words list we generated when we built a Parts of Speech Tagger:

Download from GitHub for free: https://raw.githubusercontent.com/geekgirljoy/Part-Of-Speech-Tagger/master/data/csv/Words.csv

I use array_map and pass my Words.csv file to str-getcsv as a callback to automatically load the CSV into the array.

I then use array_map with a closure (anonymous function) to cull unnecessary data from the array so that I am left with just words.

I then sort the array but that’s optional.

After that I take a test sentence, explode it using spaces and then I pass each word in the test sentence separately to AutoCorrect(), to auto-correct misspellings.

The word with the lowest distance (when compared against the dictionary) is returned.

In cases where the word is correct (and in the dictionary) the distance will be zero so the word will not change.

Test Sentence: “I love $1 carrrot juice with olgivanna in the automn.”

Test Result: “I love $1 carrot juice with Olgivanna in the autumn”

As you can see, all misspelled words are corrected though it removed the period with a delete operation because the explode didn’t accommodate for preserving punctuation.

<?php


// This function makes use of the example levenshtein distance
// code: https://www.php.net/manual/en/function.levenshtein.php
function AutoCorrect($input, $dictionary){

    // No shortest distance found, yet
    $shortest = -1;
    
    // Loop through words to find the closest
    foreach($dictionary as $word){
        
        // Calculate the distance between the input word,
        // and the current word
        $lev = levenshtein($input, $word); 

        // Check for an exact match
        if ($lev == 0){

            // Closest word is this one (exact match)
            $closest = $word;
            $shortest = 0;

            // Break out of the loop; we've found an exact match
            break;
        }

        // If this distance is less than the next found shortest
        // distance, OR if a next shortest word has not yet been found
        if ($lev <= $shortest || $shortest < 0){
            // Set the closest match, and shortest distance
            $closest = $word;
            $shortest = $lev;
        }
    }
    
    return $closest;
}


// Data: https://raw.githubusercontent.com/geekgirljoy/Part-Of-Speech-Tagger/master/data/csv/Words.csv

// Load "Hash","Word","Count","TagSum","Tags"
$words = array_map('str_getcsv', file('Words.csv'));

// Remove unwanted fields - Keep Word 
$words = array_map(function ($words){ return $words[1]; }, $words);

sort($words); // Not absolutely necessary 

// carrrot and automn are misspelled 
// olgivanna is a proper noun and should be capitalized
$sentence = 'I love $1 carrrot juice with olgivanna in the automn.';

// This expects all words to be space delimited
$input = explode(' ', $sentence);// Either make this more robust
                                 // or split so as to accommodate 
                                 // or remove punctuation because
                                 // the AutoCorrect function can
                                 // add, remove or change punctuation
                                 // and not necessarily in correct
                                 // ways because our auto correct
                                 // method relies solely on the 
                                 // distance between two strings
                                 // so it's also important to have a 
                                 // high quality dictionary/phrasebook/
                                 // pattern set when we call
                                 // AutoCorrect($word_to_check, $dictionary)


var_dump($input); // Before auto correct

// For all the words in the in $input sentence array
foreach($input as &$word_to_check){
    $word_to_check = AutoCorrect($word_to_check, $words);// Do AutoCorrect
}

var_dump($input); // After auto correct



/*
// Before 
array(10) {
  [0]=>
  string(1) "I"
  [1]=>
  string(4) "love"
  [2]=>
  string(2) "$1"
  [3]=>
  string(7) "carrrot"
  [4]=>
  string(5) "juice"
  [5]=>
  string(4) "with"
  [6]=>
  string(9) "olgivanna"
  [7]=>
  string(2) "in"
  [8]=>
  string(3) "the"
  [9]=>
  string(6) "automn"
}
After:
array(10) {
  [0]=>
  string(1) "I"
  [1]=>
  string(4) "love"
  [2]=>
  string(2) "$1"
  [3]=>
  string(6) "carrot"
  [4]=>
  string(5) "juice"
  [5]=>
  string(4) "with"
  [6]=>
  string(9) "Olgivanna"
  [7]=>
  string(2) "in"
  [8]=>
  string(3) "the"
  [9]=>
  &string(6) "autumn"
}
*/

?>

If you are wondering why I didn’t use Damerau–Levenshtein distance instead of just Levenshtein distance, the answer is simple.

I did!

It’s just that a girl’s gotta eat and I’m just giving this away so… there’s that and for most of you (like greater than 99%) Levenshtein distance will be fine, so rather than worrying about it just say thank you if you care to… and maybe think about supporting me on Patreon! 😛


If you like my art, code or how I try to tell stories to make learning more interesting and fun, consider supporting my content through Patreon for as little as $1 a month.

But, as always, if all you can do is Like, Share, Comment and Subscribe… That’s cool too! 🙂

Much Love,

~Joy

 

String Compression Challenge

I once had a promising Padawan who came to me to learn the ways of The Code and was on his way to becoming a master of the light sided languages, when he was seduced by The Dark Side of The Code and switched languages to attended one of The Emperor’s “coding-camps”.

That’s only tangential to this post, none the less I’ll continue telling the story anyway. 😛

See, he went on a job interview recently and since there is the “noob” factor the employer used one of it’s new automated testing droids to gauge his expertise.

He later explained to me that the proctor droid did challenge his abilities and even though he completed most of the trials successfully, he was unable to complete the final coding challenge within the time available.

He said:

“The challenge was to ‘compress’ strings by taking contiguous repeating letters and group them with a number representing how many of that char that letter represented.”

He went on to describe his proposed solution to me and it sounded a lot like a “Suffix-Tree” which is nifty for sure but I don’t think that is the best way to solve this kind problem as he described it.

We don’t need a list of all possible permutations we just need to group reoccurring chars.

Now here’s the thing, I like building things that have a reason to be built and if you review my code and prototypes you will see that none of it is purely to test/practice an algorithm, every prototype I build does something, even if the prototype is just a proof of concept, it sill does something and had a reason to be created.

This is because I believe you don’t develop the ability to CODE (or most things really) by practicing them mindlessly by rote repetition.

Sure, repetition is valuable practice and you can learn to “reverse a string and hash it” by practicing it a thousand times, the ability will sink in!

You will know the HOW but your understanding of the WHY is likely to be lacking if all you focus on is “learning to code” rather than “learning how to do something with code”.

It’s a subtle but signification distinction I am making which is that you have to have a reason, some purpose behind why you want or need to reverse and hash a string because then you are forced to start weighing the pros and cons to different methodologies.

You absolutely SHOULD learn all the different possible ways you can do anything you set out to do but unless you employ them DOING something other than a textbook example you are libel to have worse outcomes when faced with real world challenges that have complex trade offs.

I’m NOT saying regular practice isn’t needed.

I AM saying that more important than regular practice is “mindful practice”.

Which is facilitated (in my opinion) by having a genuine interest in the subject beyond an academic need to know it.

Take learning a natural spoken language for example, who do you think would learn a language better?

  • Someone who needed to pass a class/test in that language…

OR

  • Someone who has a friend or family member who only spoke another language and wants to have meaningful conversations?

I believe long term the person who has a personal real world motivation (i.e. wanting to speak to the other person) will succeed better at learning another language.

Obviously I’m being very general and this is of course subjective to a large extent but having some kind of personal interest in whatever you do seems crucial to long term success.

If you are musically inclined, is rote arpeggio practice as interesting and motivating as learning to play a few of your favorite songs so you can show your friends?

Is it more engaging to learn to draw your favorite cartoons for an hour, or… learning to draw using n-point perspective vanishing points for 60 minutes (Dekeract anyone? 😛 )?

It’s much easier to #LearnToCode and or #TeachOthersToCode when you are “Building a Speaking Robot” rather than “Learning to Code a Cross-Platform Wrapper in PHP for Common TTS API”, which is equally better still than “reverse a string and hash it” don’t you think?

That’s just my opinion.

Anyway, why it’s relevant here is as I said, “I like building things that have a reason to be built”, and “algo challenges” that lack a real world reason to be built are full of stupid logical problems!

I suppose this is intended to make you think the problem through but in reality it just makes noobs feel good about writing bad code that serves no purpose!

In any case, despite my dislike for writing pointless code, I wanted to offer my solution here in the hopes that if you encounter a similar pointless algo barrier between you and a paycheck… maybe you will remember my solution and solve the employment bot’s challenge!

There Is No Spoon

The rules for the algorithm challenge are simple (at least as he described them to me):

“The challenge was to ‘compress’ strings by taking contiguous repeating letters and group them with a number representing how many of that char that letter represented.”

This challenge is deceptively simple and full of potential bugs just waiting for a coder to create them!

For example, if the goal is string compression, merging single non-repeating chars with a number won’t compress the string!

Consider the string: ABCDEFG

“Compressed” by adding a number and shorting to a shingle char is actually making the string longer.

New String (is double the length) : 1A1B1C1D1E1F1G

This string is 100% longer!

Also, it doesn’t really make much sense other than consistency to compress repeating character sub-strings unless there are more than two chars because otherwise you don’t actually get any compression and we’ve already established that single chars require different processing rules anyway so considering and accounting for this too seems reasonable.

Consider the string: AABBCC

New String (is the same length) : 2A2B2C

So the algorithm must be flexible enough not to make the string longer and able to use rules to handle these situations differently without breaking.

Also, we can assume (Can we? The rules are too vague! What is this “compression” algorithm really for?) that numbers will not naturally exist in the strings because we are using them for compression, but is it possible that symbols (non-number/letter chars) can appear in the strings?

Unless stipulated it seems fair to reason symbols could appear and should probably be compressed similar to letters.

To further make my point of how useless non-real-world coding challenges are, there is no mention of “uncompressing” / “decompressing” the compressed string back into the original and if you compress something you are going to want to decompress it so it makes sense that should be accounted for as well.

My Solution

The simplest way I can think of is to:

Compression

  1. Step through the string in whatever direction the “endianness” of the data or language requires (left to right demonstrated) grouping the repeating chars by checking if the next char (the one on the right) is the same a the current char.
    • If the next char is the same, keep stepping to the right until you reach the end or a different char.
    • if/when we encounter a different char, start a new “group” of chars and repeat growing that group until we find a different char again or we reach the end of the string.
  1. Once all the chars are grouped, step through the groups and count the number of chars in each group.
    • If the number is greater than or equal to a pre-defined “group threshold” (i.e. 3) emit the count and a single instance of that char i.e. AAAA = 4A.
    • Otherwise just emit the the char e.i. AA = AA.

Decompression (from compressed string)

  1. Looks at each char to the left of this one (as we move from left to right) and if it isn’t a number and the current char isn’t a number than this is a single char representing itself, echo the current char and proceed.
    • If the char to  is a number then we’ve already used it to decompress a char.
  2. If the current char is a number than keep checking the chars to the right of this char for numbers until we don’t find another number or we hit the end of the string, repeat the next char non numeric char for that number.
    • This will find repeating chars > than 9 repetitions.
The Code

Here’s the working code.

<?php

/*

With a $group_threshold of 3 or more process these strings to output the example results:

Given this (case sensitive) string: AAaaBaCGGGGSTDSSSDDGCMM
Return this result: AAaaBaC4GSTD3SDDGCMM

Given this (case insensitive) string: AAaaBaCGGGGSTDSSSDDGCMM
Return this result: 4ABAC4GSTD3SDDGCMM

Given this (case sensitive) string: wzzzZZZZZWXXXXyYyW
Return this result: w3z5ZW4XyYyW

Given this (case insensitive) string: wzzzZZZZZWXXXXyYyW
Return this result: W8ZW4X3YW



Actual (case sensitive) output:

Original: wzzzZZZZZWXXXXyYyW
Compressed: w3z5ZW4XyYyW
Uncompressed (from group data): wzzzZZZZZWXXXXyYyW
Uncompressed (from compressed string): wzzzZZZZZWXXXXyYyW

String compressed and decompressed successfully.



*/


//String Test examples:
$chars = 'AAaaBaCGGGGSTDSSSDDGCMM'; // chars is a string
$chars = 'wzzzZZZZZWXXXXyYyW';

$group_threshold = 3; // Less than 3 is unwise
                      // 2 i.e. AA would be encoded as 2A so you save nothing
                      // and a threshold of 1 is going to grow rather than
                      // compress the string i.e. A would be encoded as 1A 
                      // So a string of ABCDEFG would result in a string
                      // that is 100% longer (double length) : 1A1B1C1D1E1F1G

// String Case Sensitivity Options
define("NO_SENSITIVITY_UPPERCASE", 0); // No Case Sensitivity Convert to Upper Case
define("NO_SENSITIVITY_LOWERCASE", 1); // No Case Sensitivity Convert to Lower Case
define("CASE_SENSITIVE", 2); // Preserve Case as it exists in the string

// Pick a string processing case sensitivity
$case_sensitivity = CASE_SENSITIVE;

if($case_sensitivity === NO_SENSITIVITY_UPPERCASE){
    $chars = strtoupper($chars); // Convert to Upper Case
}
elseif($case_sensitivity === NO_SENSITIVITY_LOWERCASE){
    $chars = strtolower($chars); // Convert to Lower Case
}
elseif($case_sensitivity === CASE_SENSITIVE){
    // Do any case sensitive pre-processing here
}
else{
    die('You selected an invalid string case sensitivity.' . PHP_EOL);
}

echo 'Original: ' . $chars . PHP_EOL;
$chars_original = $chars;

// Split the $chars string
$chars = str_split($chars); // $chars is now an array containing 
                            // each char as an element

$groups = array(); // Combined chars go here as an array of arrays of chars
$group = 0; // The index position of the current char group

// Count how long the $chars array is
$number_of_chars = count($chars);

// Group the chars
foreach($chars as $key=>$char){ // For all the Chars
    
    // Add this char to the current group
    $groups[$group][] = $char; 
    
    // If this is not the last char
    if($key < $number_of_chars){
        
        // Check if the current char 
        // Is not same as the next char
        if($char != @$chars[$key+1]){
            // The char to the right of this char
            // is not the same as this char
            // so when the foreach proceeds
            // we want the next char to be added
            // to a different group
            $group++; // next group
        }
    }
}

// Count and echo the "compressed" char groups
echo 'Compressed: ';
$compressed_chars = '';
foreach($groups as $key=>$group){
    
    $number_of_times_repeated = count($group);
    
    // If the number of times this char group repeated 
    // is greater or equal to the $group_threshold value
    if($number_of_times_repeated >= $group_threshold){
        // Example ($group_threshold < 4) AAAA = 4A
        $compressed_chars .= $number_of_times_repeated . $group[0];
    }
    else{
        // Example ($group_threshold > 2) AA = AA
        $compressed_chars .= str_repeat($group[0], $number_of_times_repeated); 
    }
}
echo $compressed_chars . PHP_EOL;


// Rebuild "uncompress" the "compressed" char groups
// back to the original string
echo 'Uncompressed (from group data): '; 
$uncompressed_chars_from_groups = '';
foreach($groups as $key=>$group){
    $uncompressed_chars_from_groups .= str_repeat($group[0], count($group)); 
}
echo $uncompressed_chars_from_groups . PHP_EOL;


// Rebuild "uncompress" the "compressed" char string
// back to the original string
echo 'Uncompressed (from compressed string): ';
$compressed_chars = str_split($compressed_chars);
$compressed_chars_length = count($compressed_chars);
$uncompressed_chars_from_string = '';
foreach($compressed_chars as $key=>$char){
    
    // If the char to the left is not a number
    if(!is_numeric(@$compressed_chars[$key-1])){
        // If this char is a number
        if(is_numeric($char)){
            
            // keep checking to the right in case number is > 9
            $i = 0;
            $number = '';
            
            while(is_numeric(@$compressed_chars[$key+$i]) && ($key+$i) <= $compressed_chars_length){
                $number .= $compressed_chars[$key+$i]; // Concatenate the char onto a number string
                $i++;
            }
            $uncompressed_chars_from_string .= str_repeat($compressed_chars[$key+$i], (int) $number);
            
        }
        else{ 
            // This char is a symbol or letter representing itself only
            $uncompressed_chars_from_string .= $char;
        }
    }
}
echo $uncompressed_chars_from_string . PHP_EOL;

// If the backup of the original string matches the
// string generated by decompressing the group data held in memory
// and the string generated decompressing the compressed string
if($chars_original === $uncompressed_chars_from_string
    && $chars_original === $uncompressed_chars_from_groups){
    // Everything is working correctly
    echo PHP_EOL . "String compressed and decompressed successfully.". PHP_EOL;
}
else{
    // Something isn't working
    echo "You broke it you fix it! :-P". PHP_EOL; 
}

Without knowing more about the “use case” (what the code is actually supposed to do) and how it will be used it becomes impossible to improve further it in any meaningful way, which is why I don’t enjoy algorithm practice and challenges… you aren’t building  anything real and useful!

Featured Image

So, lately I’ve been doing this thing where I put in a little effort to make the featured image a wallpaper and some of you really seem to enjoy this so I’ve done that again with this post.

It illustrates the idea of compressing repeating elements in a group into smaller representations of the original.

Please enjoy!

Look Forward Char Group String Compression Wallpaper
Look Forward Char Group String Compression Wallpaper

If you enjoy my code and and content then please like, share, comment and subscribe!

And if you want to contribute financially to my efforts, I have a Patreon where you can pledge $1 or more a month for one or more months, cancel any time.

Much Love,

~Joy

Mr Good Bot – Mostly Assembled

Mr. Good Bot is mostly assembled and we’re not looking at any code today (okay maybe just a little) but we’re really just going to talk about how Mr. Good Bot works and all the recent commits I made to Mr Good Bot over on GitHub.

Also, here’s the featured image from today’s post as a wallpaper. It depicts Mr. Good Bot being mostly assembled… I liked the look of hanging wires instead of legs, hence the name. 😛

Mr Good Bot Mostly Assembled Wallpaper
Mr Good Bot Mostly Assembled Wallpaper

If you need a refresher on this series, here are the other Mr. Good Bot posts:

 

So with Mr Good Bot being mostly assembled I thought we would take this opportunity to go over the recent additions.

Continue reading “Mr Good Bot – Mostly Assembled”

Mr Good Bot – DaisyBell.wav

Welcome back, today were going to start the process of figuring out how to add speech to Mr. Good Bot.

If you need to catch up, here are the other posts in this series so far.

Mr. Good Bot Series

And if you’re just here for the pretty pics, here you go…

The Featured Image:

Daisy Bell Wav Featured Wallpaper
Daisy Bell Wav Featured Wallpaper

Also, you might just want the image inside the audio wave, so… here’s that as well:

Daisy Bell Wallpaper
Daisy Bell Wallpaper

So with the important stuff out of the way, I guess all that is left to do now is figure out how to make Mr. Good Bot talk and decide what he should say first.

Continue reading “Mr Good Bot – DaisyBell.wav”

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: