Link Bar

Home | Games | Programming | Tutorials | Donate | Legal (These are mostly empty right now. Placeholders!)

warning code

This website contains adult content.

Thursday, March 1, 2012

Day 14: Eureka!

I took my homework with me this morning when I went to look for work.  This was a good decision, because I only had like ten pages left to read in Phantoms in the Brain, and I needed something else to do besides all the paying work the temp agency didn't give me.  I had ten more chips to build:  DMux, Not16, And16, Or16, Mux16, Or8way, Mux4way16, Mux8way16, DMux4way, and Dmux8way.  I built the first six, and half-decided/half-succumbed to saving the last four for when I was able to make sure that the first six actually worked, despite the roll I was on.

Last night, I built a multiplexor by a rather circuitous and wasteful, albeit functionally intact, method.  But a two-way multiplexor, using one selector input to choose between two other inputs, only has an eight-value truth table when expressed propositionally.  Mux4way, on the other hand, has two selector inputs and four primary inputs (a-d), resulting in a 64-value truth table that still comes out only 1 or 0.  Don't even get me started on Mux8way!  I realized that yesterday's approach simply wasn't practical, but was stumped as for how to proceed.

Necessity is the mother of invention, and I invented an epiphany.  I honestly don't know how I missed this - it must have been decision fatigue - but I realized at some point when trying to draw up the 64 truth values for Mux4way that since it only comes out 1 or 0, I could just express the 1 values as ganged-up And functions, then disjoin them together into a giant Or function!  Now I am slightly embarrassed over yesterday's fiddle-fartin'; but that's what I get for doing my homework in public.  More importantly, I learned a valuable lesson, and I'm proud for having solved the problem in a more elegant fashion anyway, so it's all good.  Behold:  Mux2.0!
Meaner.  Leaner.  Also greener!
And here's the new and improved NAnd-Only HDL:
IN a, b, sel;
OUT out;
PARTS:
Nand (a=sel, b=sel, out=NotS);
Nand (a=a, b=NotS, out=r1);
Nand (a=sel, b=b, out=r2);
Nand (a=r1, b=r2, out=out);
Wham!  Bam!  Flim and flam!  That's over 75% fewer lines of functional code, for those of you playing along at home.  My inner quality consultant is serenely satisfied.  OK, moving on!

DMux, the demultiplexor which takes a single input and uses a switch between two outputs, gave me a little bit of trouble.  But that was only because I was thinking I still had one output, when actually I've got two output pins coming out of my own little black box space.  That realization cleared it up right quick!  The diagram seems almost absurdly simple in hindsight - even the NAnd-Only diagram!
Gallons easier once you paradigm shift out of truth-functional
propositions per se and just start black-boxing everything.
I'm not even going to bother with the code, here.  If you've been following, it's simple enough to work it out for yourself, and I'm starting to feel pangs of "give a man a fish" guilt about doing this all in public.  At this point, though, I think the only "damage" I've done is to help along somebody just getting started, like I am.  That said, my code works beautifully!  (Also, I found via typo that this HDL is case sensitive - good to know!)

Next up, Not16:  the first 16-bit gate.  This is the reason I wanted to try out a proof-of-concept at home before actually diagramming and coding Mux4way16 and the rest.  Turns out, I can't just put in the variable "i" for inputs 0-15, I have to code them line-by-line.  Or I could type it once in Word, and use Replace!  Not a big deal for Not16, but definitely going to appreciate it for Mux8way16!  I have never been so grateful for Ctrl+H in my life (true story!).  I can imagine a program that takes code with [i] as a variable, expands it n times, and replaces [i] in each iteration of the code with [n-1] (because you start with zero, duh)... but this would save me a fairly minor amount of time (even though it feels like a lot of tedium), and anyway if I knew how to do that, I wouldn't be doing this in the first place.  Heh.  Whatever, Ctrl+V x 16 and highlighting a few lines then pressing Ctrl+H, Tab, n-1, Alt-A, N, Esc over and over isn't exactly hard.  So that's And16, Or16, and Mux16 out of the way.

Or8way throws a bit of a curve, since it's not mapping multiple inputs to multiple outputs like the last three chips.  Instead, we're taking in eight inputs to the same giant Or function which maps to a single output.  What we're coding here is not to do one thing with many inputs and outputs, but rather to check for any of eight things (rather than Or's mere two).  Here I think it pays to point out that how we code this may have an appreciable effect on performance:  I could code 4+2+1 (or 8-1, ganging them serially rather than pairing them) Or gates, making the machine instantiate the Or chip (and its 3 component NAnd gates) seven times "inside" this chip; or I could directly code all 7*3 NAnd gates and have it be its own thing rather than making the machine look elsewhere first.  While the difference between configurations is infinitesimal for just this one Or8 gate, it adds up cumulatively in the processor load when turn on the "computer" and run the "chips."  Not of particular importance to the lesson at hand, but of tangential relevance and so I thought I'd point it out.

Also, I found out by experience that pins cannot be named beginning with numbers - who knew?  I named the outputs from some of my NAnd gates as "out=xvy" for clarity (where x and y were integer values corresponding to input pins), rather than the relatively nondescript r1/r2, etc.  I kept getting the error, "A pin name is expected," and jiggered around with it for over half an hour, giving myself a headache in the process.  I have a feeling I should be expecting a lot of these in the weeks and months to come...

Taking stock:  I seriously refined my multiplexor, which is a big deal to me, and wrote up the first six of my final ten gates.  Good progress for one day, I think; and my brain is feeling full now, to boot!  I also watched a great introductory video over at the Khan Academy, during which an idea for a text adventure began crystallizing. I'm not sure quite how to do the "window" stuff yet, but I've got a good handle on how to declare values like player health, experience, and level, and how to nest conditional dependencies inside them to link derived stats to their primaries (now I just need, oh, the rest of a game to house them!).  I've also got some good ideas for a weekend mini-project to overhaul the site with a custom image header and a few layout features, so there's quite a bit going on under the hood today, as well.  Plus Zach gave me another tip for making forward progress on Fetris, so I'll be looking into that right now.  Y'all have a great one!

Final Thought:  I just realized while proofreading that the program I pined after above - the one that would do my homework for me - would actually be pretty easy to code using the principles taught in Python by that video at the Khan Academy.  The only real "invention" would be to code the recursive function that iterates the steps n times.  Great, now I'm going to be thinking about that all night.  Anyway, I'm not writing the code here, since that would be providing a tool that actually does actual homework in an actual class, but the principle will be super-useful when generating content procedurally in future games.

No comments:

Post a Comment