Trial by fire in my opinion is the best way to be exposed to a new skill. I don't mean that you will suddenly become the best at something by diving into an abyss recklessly, but you will at least force your head into an uncomfortable position and adapt to new concepts.
Every minute I had free at my electrician job, I was studying docs, writing code that was akin to a Frankenstein monster of stack overflow answers and just submerging myself in this world that I felt ever behind and lost in. But I kept at it.
So I forced myself to uphold a promise while starting to work on my latest project Coloursel.io. I would not use any of these francy frameworks or libraries that I didn't absolutely need.
Then came the day I wanted to build upon my application, I wanted to flesh out Coloursel.io into a wide variety of tools and modules that showcased p5.js in all its glory. The minute I wrote the next line of code, I knew I had a problem.
I looked down at the plethora of logic I used to write one single component and it dawned on me that writing the state managing logic for these two components was going to be nightmareish. And what happens when I want three components? Or four?
I was stuck, I was not about to mix the component logic into an inseperable mass of ugliness, there has to be a better way. It was time to employ React.
It made sense, this is what React is used for. It would be incredibly unreasonable to not utilize this amazing opportunity to make my app better!
Before I knew it, I was using all my tools again that I swore I wouldn't touch. Violating my purist oath.
The takeaway is this, learning in reverse didn't hinder my ability to use basic tools like I thought it would, but not allowing myself to use these tools when I need them would end up making my app not as great. Learning in reverse gave me the opportunity to see what problems these tools are made to solve.
I would admittedly be the first to buy into the hype of react native since its release in 2015. React is a solid tool for building user interfaces and I use it with nearly all my projects.
Here are 3 things I've learned during my first experience with React Native
In order for reusability between platforms, React Native uses components that translate into their native equivalent.
For example, there is a "View" component that must be used any time you wish to render anything on the screen, and "Image" components for displaying images and so on.
This will take a bit of studying the docs to understand the quirks and implementations of each type of component, and don't even get me started on the ListView component
If you want certain features such as camera access, you better pray that someone has taken the liberty to write a package for your respective React Native platform target.
Some features require split component implementations from React Native, like the ProgressBarAndroid and ProgressViewIOS. Meaning that you will still have to develop for each platform individually to some extent which is a ding to React Native's "write once use anywhere" pitch.
As mentioned in the 2nd item, some kind people take it upon themselves to write third-party packages to access hard-coded native features that React Native doesn't support out of the box.
However, you cannot count on 3rd party packages being available to both target platforms, as of writing this article 3rd party package support is unfairly skewed in favor of iOS for desired packages like fs attachment support.
In conclusion, React Native is still very early in development and its premise is very ambitious, but nothing about it at this very moment suggests that it is a viable platform for developing anything more than simple prototypes or fleshing out a side-project.
Node gets input via a readline library, this is native to Node and only requires importing to use.
readline takes a configuration object that we specify to use standard in and out for our interface (keyboard and screen).
We initialize a constant to every lowercase letter in the alphabet. For filling in the grid at the very end.
Initialize a grid variable to a list, declare a gridSize variable, initialize an array of words and an array representing possible word configurations.
We call a function getInput() which will execute our readline interface
This function loops and gives readline a question which prompts the user for a word. Upon entering a word and hitting enter. We add the word to our list we declared earlier.
If the word is a blank string, we quit the loop. We then sort the list by longest word first, make that our gridSize and execute our next function makeGrid()
The reason we sorted the list by longest first is so we have a good base size for our grid. The grid must be able to contain the longest word in width, height, and diagonal configurations.
Now we make the grid. We simply call a nested loop according to our gridSize, this will give us a row | column layout where the row contains an array of blank strings. Each blank string represents a column.
Now we will call a function mapConfigs().
Now it gets involved. We have to find the places a word can fit into the grid.
There are more efficient ways to determine available spaces (like keeping a copy of free spaces in another variable and only using that) but for this purpose we will just choose a random row and column to check.
For every word the user entered, we make an empty row, column, configuration, incrementor, and options variable.
The options variable is an array of configurations or 'choices' we have for the current word. Our loop will keep executing as long as we have no options.
The row and column are chose randomly (thats what the getRandomIntInclusive() function is doing, nothing magic).
logging the word, config, row, and column with give you the 'solution set' to your word-search at the very end.
Then the row, column, and the configuration string are passed into a function called getAvailConfigs(). This function will return an array of booleans that we assign to our options array.
If a loop fails at getting a true option, the loop executes again, trying a new one and incrementing the i variable. If i gets bigger than gridSize*gridSize, we assume we have tried every possible option for our current gridSize and we make the grid bigger by 1 and restart the list of words.
When we get a true option, we go to our if statements. Each index in the options array is a boolean with a corresponding configuration that returned 'true' (the word can go there).
We simply change our configuration string to represent what was in the options array in a more readable form.
This list of options is what is returned from the getAvailConfigs() function, lets see what it actually does.
getAvailConfigs() simply acts as an abstraction to two criteria. A word must match these rules to be considered eligible to fit into a space in a configuration. If one fails, the position doesn't work and false is returned for that configuration back to our options array.
Lets look at what fits() is checking for.
fits() checks the configuration string and does a simple calculation to see if the length of the word can comfortably occupy the space in the given row and column.
If a configuration passes its assigned rule, then it will return true, and half of our corresponding options boolean will be true.
But remember both criteria have to pass and fits() is only the first, lets look at the next which is handled by availSpaces().
7th inning stretch everyone, take a minute and pop your backs and walk around a bit, you deserve it!
You good? Okay lets continue.
We're first checking if the config string starts with 'r' because that means it is a reversed configuration, so we need to reverse the word.
Next we need to loop over the letters of our word and check every row and column that the letter is expected to occupy. Remember we're not only affecting a single row x column intersection, we're checking everything the word is going to touch once it's spelled out.
If a configuration passes its assigned rule, then it will return true, and the final half of our corresponding options boolean will be true.
This means that both tests passed, the word fit and had available spaces in the given configuration.
This info is relayed back to getAvailConfigs() who sees fits() === true && availSpaces() === true and that index in the options array now equals true.
Lets look back at our mapConfigs() who started this goose chase.
Now that one of our indexes in our options array is true, we simply choose the first true one (for randomization sake probably not the best method but when word lists are longer it's unnoticable).
Then we call a function insert() and enter the home stretch.
We pass insert() the word we want, a config string that passed our tests and the appropriate row and column.
Again we check if the config starts with an 'r' that we reverse it.
We are essentially implementing the same logic as our availSpaces() check, but this time we are actually inserting the letters at their appropriate space in the grid.
At the very beginning we made a constant called 'possible' with every letter in the alphabet. We are going to use this to fill in the blank spaces in our grid.
Using good ole' functional programming we have the grid mapped with every character that is a space filled by a random choice from our possible string.
Just for debugging sake I also kept in the gridSize and the length of the longest word just to see how many times the grid needed to be resized before finding a home for every word on the list.
Simple countdown event web application, uses serviceWorkers and other PWA technologies to provide a native app-like experience. Syncable with Google Calendar and Facebook Events. First experience with create-react-app bootstrapper....must say, amazing environment not having to setup babel and webpack and other build tools manually.
Exploring the relationships of colors through interactive modules. Emphasizes the visual aspects of coding and user input. Multiplayer games constructed with socket.io and Node.js running over AWS EC2 which was great fun to use