Hacker News new | ask | show | jobs
by cs0 2773 days ago
Thank you to everyone who has replied to my rant.

I felt of low value for not being able to provide immediate help for most of the problems that she's being taught to work on.

Some of the examples (since some of you were asking for them): https://github.com/cs50/docs/blob/master/_pages/2018/x/psets...

https://github.com/cs50/docs/blob/master/_pages/2018/x/psets...

I realise that I may have written my original post a little hastily as I was feeling quite strong about having inadequate knowledge to solve these problems.

You've all been super nice to me, and I can understand where you are all coming from.

Again, thank you.

As an aside, the problem that I was stuck on earlier, I managed to solve through a bunch of trial and error, so I'm chalking that one up as a win for tonight.

17 comments

The examples you gave are very helpful in giving more context. I'm guessing that you're productive in your job, because you know the details of how to use language ABC, framework XYZ and the various patterns for solving common industry problems using ABC and XYZ. The part you seem to be weak in, is abstract problem solving. Ie, coming up with a pseudo-code algorithm that will accomplish some abstract goal that you've never come across before.

This requires a completely different skillset. You rarely have to come up with novel algorithms when building a CRUD app, hence why you've never gotten the chance to practice those skills. That said, it's definitely worth learning - if nothing else because it will help you in job interviews.

There's no shortcut to this. Go on leetcode or hackerrank or similar sites - or do all the homework assignments and projects along with your fiance. You're working out a brand new muscle, so it will definitely seem frustrating at first, but you'll get much better with practice.

Your first paragraph hits the nail on the head. This is exactly me.

Thank you for your reply. I do intend to work further on my skills in order to get better!

One (relatively) easy way to get better at it is combining a book and some real world uses with a project and a language suited for it.

For example, you could take python or java (or C#, pretty much any general OOP language), and make a simple crud application. Then add a "reporting" page where you can see different results on for example uses of trees, sorting algorithms or storage data structures (like linked lists, hash maps etc). The crud part can be your familiar part where you have a good feel of what's what, and the report/test/whatever page can be your sandbox to see how your experiments deal with your data.

One of the books I found helpful was Data Structures and Problem Solving Using Java by Mark A. Weiss.

A softer start can be found with http://interactivepython.org/runestone/static/pythonds/index...

If you want something using languages you already know, that's fine too. Say for example you wanted to simply know how to build a tree, or more generally a graph. Those concepts may sound big or complex, but they are only as big or as complex as you want them to be allowing you to build a simple version (i.e. a class that is a node in a linked list, and it holds just a number as a value and the next node for your list as a pointer or value or whatever you like). It's something you could do in 10 lines of code just to get yourself started. Building on top of that is a whole lot easier than jumping straight into AVL trees and A* path finding algorithms.

Starting light, say, making a few things yourself in a language of your choice will get you a good feel as to what you want to explore and how easy it is to grasp the concepts, for example:

- linked lists and doubly linked lists

- binary trees (binary doesn't mean binary data, don't worry)

- sorting (check quicksort, shellsort, bubblesort on wikipedia for starters to get an animation for an idea what it is)

- heap

- stack

- (priority-) queue

If you prefer watching videos/working through a MOOC for this stuff, I can highly recommend Robert Sedgewick's Algorithms I on Coursera: https://www.coursera.org/learn/algorithms-part1

If you don't know his name, you should - he's written some of the best books on these algorithms and his MOOC is similarly rich in visualizations and concrete examples that help you develop the intuition for the algorithms. Also incidentally his doctoral advisor was Donald Knuth, who he evidently learned a lot from.

Take a look at "How to design programs"[1]. It teaches a systematic way of attacking/solving problems.

[1] https://www.htdp.org/

I went through this too! I'd definitely recommend giving it a go if you're up for it. You may have those moments of utter confusion, but you'll definitely learn a lot!
Good job in putting it tactfully. I think you have it exactly right, there's a different skillset used in interviewing often, abstract problem solving - that really is different than the skills to write a crud app.
I'm sorry to say this - but given this examples I wouldn't hire you if you can't solve so simple stuff.

You have probably problems with text comprehension because I don't know how you can't solve it.

It's not coding that's needed - you should be able to do it on "paper".

What are you really struggling with?

1) understanding problem setup (reading)

2) coming with solution to problem (search)

3) implementing solution in programming language (coding)

I have to agree with you. Especially the ceasar cipher example is literally about following the steps, everything is outlined in an almost step-by-step fashion. The only part of the exercise that might be new to OP is programming in C - but the algorithm itself is stupidly well explained and the bullet points literally tell them what to do. It's as if they read the first paragraph and decided it's some arcane voodoo magic so it's not worth reading any further.
It might sound a little bit too harsh, but I totally agree with you. Furthermore, provided examples are missing search step – there's no need to come up with solution, because solution is explicitly specified in task description.
What exactly did you have trouble with? These really are simple problems, all you need are an understanding of loops, ASCII character codes, and basic arithmetic.

To be honest, I'm surprised a seasoned developer of 5+ years can't do these, or at least have a decent stab at them.

Why would you expect the modern application developer to even know what ASCII is?

There is a chance I wouldn’t know what ASCII encoding was if my exposure to programming didn’t start in the 8 bit era. C is foreign to a lot of self taught programmers.

A modern application developer should be at least vaguely familiar with Unicode, so character encodings should not be an entirely foreign concept.

You should be able to use a search engine to figure out what ASCII is, though. That's fair game to expect. The text document mentions ASCII, so it's not like a developer would be left without a clue.

In this modern time, no one needs to know what the ASCII code for @ is, but I think it is logical to expect people to know that some encoding exists and that letters can be mapped to numbers.

Also, all the ASCII you need to know to solve the problem is explained at length in the problem description.

I couldn't tell you offhand how to convert between an int and an ASCII character.

...But if you give me a second...

Now that I've typed "ascii character codes" into google, I can tell you how to convert between an int and a character.

You don't have to memorize everything. Well over half of our job is knowing how to find information quickly.

Remember the context, this is an introduction to computer science course. The slides for the lecture for that week most likely explained everything you need to know to solve the problem.

Even completely ignoring ASCII, it is trivial to create a dictionary mapping integers to characters.

ASCII does still map to the most commonly used parts of Unicode, so there is that. I would agree that I wouldn't have the foggiest idea what most of the ASCII character codes are if I hadn't cut my teeth on archaic stuff like QBasic; I remember a lot of silly little toy assignments doing rot13 or manually upper and lowercasing strings. But they do come up from time to time when you get into, for instance, JS keydown/keyup events. But any competently designed modern API ought to at least have named constants for this kind of crap
Don’t ask me why I remember that the lazy non performant way to put a character on the screen in assembly was to store the ASCII number in the A register and

JSR $FDED

The fast way was to copy the bytes directly to the $400-$7FF address space and figure out the non contiguous memory map -> screen yourself.

(After a "...I never used that in QBasic!", google explained that this is for the 6502)
I'm right now trying ti get around being made to learn ASCII for vocational school (some certification is useful to pass automated recruiters).

I base my Opinion on it being a bad idea to rely on manual translation, and untill then I'll have learned to write code that does the translation for me.

We probably underestimate how many people out there are just copy/pasters. No offence OP but I hope you dont work on anything that handles money/user data/requires security.
I do! I develop bespoke add-ons for the accounting software Sage 200. Fear not, my work is peer-reviewed by my boss who has 35+ years experience in the field.

If I get something wrong, my boss lets me know, I learn from my mistakes and ship out good quality software.

I just replied above, but I've never been amazing at being able to figure out how I should be using for loops to solve problems quickly and efficiently.

I do tend to make things harder for myself, as my boss and fianceè have told me before.

I usually end up with a very convoluted solution which I end up coming back to and refactoring the next day.

I was actually going to recommend exactly that - I find that, when I have a problem that I’m having trouble solving, just brute-forcing the damned thing helps me focus on the hard parts of the problem, and then I end up rewriting things in a “better” way that I’m actually not ashamed to put my name to.
Correct first, then simple and fast later. With more experience you'll be able to devise simpler, correct first solutions that you can then speed up later.
I'm curious, what sort of approaches do you take to your programming tasks at work? Is it more like e.g. writing SQL where you'd think more about relating sets of data rather than looping over individual items?
There's an old Kent Beck quote that fits here... "Make it work. Make it right. Make it fast." Your approach fits that.

http://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast

I've seen so many projects where the developers have taken this to heart way too much. The problem is they use it as an excuse to give up after stage 2 thinking stage 3 can come along when it actually becomes a problem.

The thing is that performance issues tend to creep up on you so slowly that you don't realise it until you have a very important client with tons of data screaming at you to fix it now. To fix it then you have a huge architecture issue because the whole system is so inefficient. So rather than rewrite the entire code base to actually be efficient you are forced to hack in some kind of caching solution. Then your problems multiply.

Make it fast from the start. Premature optimisation being the root of all evil is a lie!

I'm not sure you two actually disagree, but rather that you're thinking on different scales. Make it right, then make it fast is usually talking about specific snippets of code, rather than the whole program, so your whole program should be "made fast from the start" because you went through the process of making it right and then making it fast on the components themselves.
Yes, that's a great way of thinking about it!
If you do that you'll write great, fast code but it'll take you longer to do it. That's great if you have unlimited resources, but try doing it in a startup where failing to ship in a month means your whole business fails.

So... Maybe don't prematurely optimize?

What is your hypothesis on where that lie comes from?
Ok, it's a bit of an exaggeration and obviously depends a lot on what your definition of premature is. I guess the statement is actually a tautology, by definition premature means too soon. I just see people who think that any optimisation at all is bad, whereas in a lot of instances optimisation as you are writing the initial code is not premature. In my experience...
I mean the question also is whether OP has done any programming in C before. If the majority of your expierience is in VB.NET and web technologies I can see this being a major hurdle aside from the actual algorithmic problem.
I don't think C is the issue here but mental shift . I have suffered from same situation in the past. He should just spend time and interpret the question, internalize it , and then code it
You don't even need to understand ASCII. You can hard code an array of all the letters in the alphabet, search for a given letter and replace it with the letter 13 places ahead in the array. If you were really lazy and didn't want to worry about the logic for rolling over when going past Z, you could even rewrite the first 13 letters at the end.
I have no trouble believing that there are many developers out there with no understanding of character encodings. Because I have seen many applications where the handling of character encodings is nothing but kludges upon buggy ad hoc kludges.
I mean you had your share of tough love already in this thread. But: - The examples you posted are indeed very simple problems. Caesar is just about "can you scan two arrays at the same time" (and then do charString + charKey and some modulo). Luhn is just a step of non-obvious specification to follow.

- This is a different game than your day to day. Those two being easy stuff means nothing if you never played the game.

- Now you moved a "unknown unknown" to the category of "known unknowns". You know you have no competence in this category, and if you wish to improve in it you can do so. Or not, it's your choice. Before, you didn't have the choice. So that's good!

- It's not about the language. You can solve these in Java, C, Assembly, Haskell. Most training website for interview questions (like these) allow you to implement in any of the major languages. If you want to play the game and get better, I recommend Hackerrank (for structure) and TopcoderArena (for variety, since they give you a bit more fuzzy spec and you also need to identify the algo for the issue at hand). The latter is slow as balls though, and offers no solution (except the best submitted, which may be cryptic).

- This stuff takes time, and if you want to learn about things you'll have to book up. Cormen's "Intro to algorithms" or Skiena's Manual are the goto texts. They are thick. Take your time. Persevere.

Is there a particular part of these problems that is stumping you? Perhaps breaking them down into smaller sub-problems? Where is it something else?

Based on your original description I was expecting something more heavy on straight CS theory. “how do you sort an unordered binary tree in place“ kind of thing.

> heavy on straight CS theory. “how do you sort an unordered binary tree in place“ kind of thing.

I was having a related conversation earlier, and feel like I'm reprising the same argument for a new audience, but... I don't see what is either Computer Science or theoretical about that. It seems like an eminently practical task: Handling things in a tree structure, sorting items, and doing work in-place to conserve resources are all very concrete, real-world aspects of writing software. You might not need them in _every_ case, but they aren't really "theory" in any real sense.

If you’re a bog standard “dark matter developer” using high level languages or writing your typical SAAS app, you wouldn’t need it.

I turned down a job offer where the interviewer was more concerned about whether I could write a merge sort on the board (I did), than whether I could design a system. It told me a lot about the kind of people they hire.

I spent my first 12 years as a developer doing a lot of bit twiddling in C writing cross platform code with nothing but the standard library, but these days if someone asked me how to sort I would call a library function. Heck even C has a built in sort function.

But those issues are all totally orthogonal to my point.

You can argue that someone doesn't need something, that it's the wrong level of abstraction, or that it's not an appropriate interview question. I even agree to some degree. But that still doesn't make those "CS theory" subjects.

If you are writing a webapp in PHP you need none of these things.
I've never been so great with figuring out loops to iterate over things and the like.

And some of the questions being posed (which are all expected to be solved in C) are a little tricky for me to figure out on my own without some of the niceties which I have been exposed to in higher level languages.

Perhaps the hardest of these was the Credit Card Validation example.

I was stuck for such a long time on trying to figure out how to utilise an array with for loops to multiply every second number of the card backwards.

This is Introduction to Computer Science and all of this is from week 1, so I was pretty much falling at the first hurdle.

Can you solve these problems in your language of choice then? How can you write business logic at work without loops?
I tried looking up various solutions in languages which I knew a lot better, so, and example of one of these would be Go.

The logic was there, but I still couldn't understand most of what was going on, unfortunately.

Through trial and error, I eventually managed to get something working.

>How can you write business logic at work without loops? It's not that I don't use them, it's that I have a hard time figuring out how to use them in the context of solving the problem.

Personally, I would feel trying to find the solution by parsing other people's code would be way more complicated than just coming up with your own solution.

I would forget about C, though, and try to do it in a language you already know to begin with.

To be honest I also find it very difficult to relate, as especially the Cesar Chiffre seems like such an easy problem. I only have to read it and my brain already maps out the solution. (I guess you could call it a No-Brainer, except that it seems to be a "Brainer" :-)

I honestly can not imagine how you usually code.

However, I want to say I remember my first year of studying mathematics. Many of the exercises also seemed very hard back then, but looking back on them the following year, they actually seemed quite easy (well, most of them). So practice and experience really can work. No guarantees, though.

Personally I like "Project Euler" for programming problems: https://projecteuler.net/ I actually had questions pop up in interviews that I had previously solved on project Euler.

I would be very interested to hear about some examples of real-world contexts that have proven tricky. As much detail as possible is preferable.

Incidentally I describe my problems with math almost the exact same way - virtually nonexistent fundamental understanding, and so huge issues with abstracting out even the simplest real-world tasks. (My wake-up call was when I was basically just mashing buttons on my calculator one day when I realized I didn't know how to compute how much of X I could buy given that it was $Y per weight.)

Have you tried writing it out on paper as a flowchart? Sounds old school, but can help with visualising what's happening.

Loops become super simple when you see them as series of steps with a yes/no question of whether to stop or go through your steps again.

Draw up some boxes for every variable you think you're going to need, give them labels and add the labels to the flowchart.

This then allows you to run through the flowchart step by step changing the values in each box as you go.

> Figuring out loops

Maybe you're making it too complicated. The reason for loops is simply that you need to repeat an operation. Call it repetition if that helps.

- for x;y;z - repeat a specific number of times, or need an index #

- for x in y - iterate over container

- while x - repeat while a condition is true

- do while x - like while, but run at least once.

So, imagine we have a string and need to add 1 to each character. The second bullet above looks best, first if the language is lower level.

From this description it seems you have problems with implementation.

You probably lack in "coding"(maping solution to code) department - it's totally normal in language you don't work in day to day. You are probably less skilled in implementing simple, lower level abstractions - understandable given your background.

I have more exp than you - recently I was helping friend with python ML code - it took me 40 mins to code 20 lines. I don't feel bad at all, because even though I knew solution, to write it in python I had to google for each line and read docs to know range handling, dsl of libs, array comprehension syntax, lambdas etc.

Good news is that it's easy to get proficient fast by doing such exercises. I can recommend codewars.com

Thanks for the provided examples.

If you have been working as software engineer for five years, but can't solve that task, that indeed makes me doubt how were you hired in the first place. I'm sorry if that sounds harsh; I appreciate your honesty and I would want to support you in your self-doubt, but I consider honesty to be more valuable in such a situation than being nice.

Caesar's algorithm in particular looks like a high school assignment, to be honest.

Thanks for your reply.

To be honest, I'm only just able to write a program in C, which is the required language for these CS50 tasks.

I've never been asked to do this kind of work before, so I had no idea where to really start.

The walkthroughs provided in the course gave me a high level overview to the solution required, but being able to translate that pseudo-code, if you will, was the part which I was completely stuck on for a while.

I felt like I should have known at least how to start off solving this problem using prior knowledge I had gained through commercial experience, but I was wrong, and none of my experience thus far was able to guide me in the direction which ended up with an answer to the problem.

Have you reviewed the lectures and other course material or just jumped into the problem sets?

A thing that may help: Approach this CS50 material as if you have no knowledge of programming. Set aside your preconceptions about both your ability and the nature of programming itself (to the extent that this is possible). Review the materials and read/watch all of it, even the things that you know. You may know them, but exercise the discipline to persist through them and practice the material.

At the beginning of the course, this was one of my problems. My fianceè would give me the specification of the program and that's it.

I've since learned to also follow along using the walkthroughs provided, since they provide answers to the most basic of questions that I would have asked.

I'm glad to see this OP, as my post was initially going to be pointing you towards the support materials, eg.g Caesar: https://www.youtube.com/watch?v=ergRKv3DglI

I would suggest you have a golden opportunity here, tbh. You have identified an area of useful skills which you currently are lacking - and a source of info where to learn. That's good. More importantly than that, your fianceè is currently doing the course and is right at the start! If you sign up to CS50 now (it's free!), you have maybe 4-6 hours of lectures to catch up before you are at Ceasar yourself, and then you can work through this excellent course together!

You will learn lots, some of which may be very useful. As will your fianceè. And you'll both have a much easier and fun time having a partner to discuss the lectures and problem sets, helping each other out here and there, before having to reach out for assistance.

Just FYI, you may want to hang on to your LUHN algorithm implementation - I’ve had to do that for work several times. That’s actually pretty real-world relevant.
I would recommend not getting scared looking for the whole bunch of specifications at once, Try to say or write the solution's steps in plain English letting only the most fundamental, as you were explaining the steps to a kid or so, Try to imagine yourself explaining/teaching in simple words is a good way to reason better about the problem. I started learning programming as a hobby/long-term-dream at almost 40 y.o. and it felt so hard to understand the most basic thing in Ruby, like what an Array is, for example, that it gave me literally a big headache and devastating disappointment, even almost cried...now I laugh remembering that :D There is an interesting book I saw then that I recommend, it's name is "the nature of code" , talks about examples of algorithms that appear in Nature and natural phenomena.
I think you just need to brush up on data structures: https://www.geeksforgeeks.org/data-structures/ (There are probably better resources like HeadFirst or Khan Academy)

Most of the problems you've listed become easy the more familiar you are with data structures. This is a more common problem for anyone outside the SV/SF bubble and I wouldn't worry. Just start doing homework and you'll be fine.

Once you're done with data structures, I would start checking out design patterns: http://shop.oreilly.com/product/9780596007126.do

Hope it helps

These problems remind me of the ones on checkio.org. The difference being over there you get the benefit of using python--not that I already knew python but it's rather intuitive, plus you can run a million things through an interpreter to quickly understand how it works. These CS50 problems require C, which most mortals would have a much harder time working with.

In either case you constantly consult the language reference and standard libraries until you find something that works. The C reference at https://reference.cs50.net/ looks perfectly good.

To be honest I don't know how I would load a CC# into an array to compute Luhn's algorithm on it in C. In Python I know there are easy ways of doing that, because strings are automatically arrays in the first place (same as that Caesar cypher problem, Python makes it much easier to work with strings). I don't even know if that's the "right" way to do it, but that's what I would do in Python: Convert the number to a string, operate on it as an array, converting each character to an int as it goes, running the algorithm as given in the problem, back-converting to string and then back again to int as needed (like if I need to add the digits of a number together). Fine I suppose I could avoid doing that by taking modulos and if I didn't know what a modulo was I would divide by 10 for instance and then take a floor to get the first digit of a 2-digit number.

I have no idea if any of these methods are "correct", I would just hammer away at the code until the acceptance tests passed. It would take over an hour for each of these solutions, after getting into the zone, so let's say 2 hours. There you go, 4 hours of work to get through these two problems in C, let's add on a lunch break and we have a full work day. That will be $325 thank you. Oh I don't get paid to study computer science in my free time? Oh ok. I guess I will just bookmark CS50 and come back to it... some day.

Your wife is lucky she gets to study this stuff. Don't be so hard on yourself.

The solution is C is essentially same as the one you outlined in Python.
I mean, I notice that these assignments seem to assume that you are using C. Are you using C?

You said that you have used PHP, Javascript and VB.Net. C is much harder to use than any of these, and exposes you to many concepts that these languages have abstracted away.

Seems like the sibling comments have already doled out the tough love. All I can add is that I'm in a similar boat, having worked for a long time and now back at university to finally check out my degree... The material is much, much more challenging than I would have thought. Which is disheartening because I have so many years of experience and thought I knew most of what there is to know... So eh, don't give up! Working on those homework problems with your fiancee is a great opportunity to learn more.
Wtf? The second problem, listed after the Caesar cipher, is to reverse the hashing algorithm used for passwords on Linux.

What? How is that even remotely fair to ask as a challenge alongside something like the caesar cipher? One of these is a children's task while the other is a professional cryptographer's task. Am I missing something here? I'm sure it must not be terribly hard to do, but it's still so disproportionate to the previous task that I'm shocked.

You're not reversing anything first off, it looks like you're just call crypt(3) with every potential password since they put a five character cap on it. 600M or so combinations, so pretty trivial, but feels fun. I'm actually all for this assignment, it makes you feel all hacker typer.

Secondly, it's DES. DES hasn't been viable for almost two decades now.

There is very good advice and suggestions here, but IMO this thread is also distinctly "noisy" - lots of discussion and sharing, but very little in the way of a coherent go in this direction!.

So, I'd like to offer a couple of things that may be of immediately actionable, relevant assistance: SICP and NAND2Tetris.

--

SICP - the Structure and Interpretation of Computer Programs - was designed as an entry-level theory-first approach to programming. If you want to drown your brain in abstraction and get oriented quick, this will help you do that. It's very dense; expect to read it slowly, and also don't force yourself to block on one specific spot until you've understood it. If you can reach some sense of logic and order that lets you get through CS questions without breaking a sweat, who cares if you had to read the textbooks backwards or out of order.

I explicitly recommend SICP because you can find PDFs and EPUBs of it online (it's quite an old/classic book). I see a lot of book recommendations on here that I can't follow up on due to insufficient throwaway budget.

Plus, studying SICP with your fianceè will put her in a significantly better position to ace her CS courses.

I found this HTML rendering: http://sarabander.github.io/sicp/ (google will very readily find PDF and EPUB copies, but this version seems nice)

--

NAND2Tetris explains every step of a CPU from the electrons up (as opposed to the top-down orientation taken by eg JS, VB, etc), and has you build a toy CPU.

https://www.nand2tetris.org/

Unfortunately I've just discovered that this course, which used to be a little more open, seems to have closed down somewhat. Either that or I misunderstood and it was never an open course.

This being said, searching for "The Elements of Computing Systems" - the reference textbook for this series - is finding a PDF pretty quickly. The book itself is apparently listed on Amazon, so perhaps the PDF version could provide an idea of whether it would provide any value.

This course is taught in many CS classes IIUC, so studying this with your fianceè will also leave you both in a better position.

--

Also - I've been wanting to see how well I can explain pointers and so forth for a while now. Ping me if you like.

(I seem to be atrocious at email/IM-style communication, FWIW, so this may go horribly wrong)

There's also a Coursera MOOC on Nand2Tetris:

https://www.coursera.org/learn/build-a-computer

They sure make it sound more complicated than it really is... I'm a self taught developer too, so I get where you're coming from :-)

In javascript I would solve it like so: "HELLO".replace(/./g, character => String.fromCharCode(character.charCodeAt() + 1))

This would result in "IFMMP".

Basically it's just a matter of shifting charcodes.

Your solution would not work for all cases. For example, shifting "JAZZ" up by 1 should result in "KBAA" but your program would output "KB[[". You also need to handle wraparound at the ends of the alphabet.
Hi! Yeah, you're right! This was a 1-minute quick'n'dirty solution :-)
I'm pretty much in the same boat as you, so to speak.

I had a lot of fun playing with a few of these problems: https://adventofcode.com/

I'm not sure if they are classic CS though.

When I learned about the CAESAR cypher, I wrote a program called ENIGMA that changed the number of places shifted with each iteration.

Obviously I knew next to nothing about cryptography, and I did feel very smart about making a safer cypher.