Monday, December 3, 2018

All Possible Matched Sets of Parenthesis

Coding tests: That necessary part of the hiring process that can be the difference between being hired and not. For the All Matched Set of Parenthesis coding test, I was provided with the following information:
- Given a number n, print out all the possible syntactically valid n pairs of parenthesis.
- When n = 0, there are no answers.
- When n = 1, the one answer is: ()
- When n = 2, the two answers are: ()(), (())
- When n = 3, the five answers are: ()()(), (()()), ()(()), (())(), ((()))
- What is the N-time of your code?
- As a secondary exercise, make your code work for N in the millions if it does not to begin with.
- This should be completed on a whiteboard in 30 minutes.

Sounds simple enough. Generally, I like to avoid using recursive functions, as they tend to be hard to diagnose problems with. My original answer in java was:
HashSet results = new HashSet(1);
results.add("()");
for (int i = 1; i < pairs; ++i) {
    HashSet newResults = new HashSet(results.size() * 3);
    for (String s:results) {
        newResults.add("(" + s + ")");
        newResults.add("()" + s);
    }
    results = newResults;
}
for(String s:results) {
    System.out.println(s);
}

This answer is actually wrong. When I was given the n = 3 answers, I was only given 4 answers, without the (())() answer. I coded to that. I was not told this at the time and the interviewer even confirmed that I had the right answer as it matched the example answer given for n = 3.

The correct answer using that style in Java should have been:
HashSet results = new HashSet(1);
results.add("()");
for (int i = 1; i < pairs; ++i) {
    HashSet newResults = new HashSet(results.size() * 3);
    for (String s:results) {
        newResults.add("(" + s + ")");
        newResults.add("()" + s);
        newResults.add(s + "()");
    }
    results = newResults;
}
for(String s:results) {
    System.out.println(s);
}

But even this answer has issues, as it is going to be limited by memory due to storing the entire n results in memory as well as the n-1 results at the same time. When actually running real code (whiteboards as a rule do not run code) in a standard 64-bit Java environment, it runs out of memory with n = 17. Note that n = 4 should have fourteen answers.

The N-time for the correct code is between 2^(n-1) and 3^(n-1). During the interview, I incorrectly gave the N-time as n^2 for the incorrect code, without any acknowledgement that it was right or wrong. N-time for this problem is misleading.

Sometime after the interview, I search for the answer using Google and with some minor optimizations came up with this:
protected final byte[] base;
    
protected RecursivePairParenthesis(int pairs) {
    base = new byte[pairs * 2];
}

public void PrintPairs(int pos, int open, int close) {
    if (close == pairs) {
        System.out.println(new String(base));
    } else {
        if (open > close) {
            base[pos] = ')';
            PrintPairs(pos + 1, open, close + 1);
        }
        if (open < pairs) {
            base[pos] = '(';
            PrintPairs(pos + 1, open + 1, close);
        }
    }
}
    
public void PrintPairParenthesis() {
    for (int i = 0; i < pairs * 2; ++i) base[i] = ')';
    PrintPairs(0, 0, 0);
}
    
public static void main(String[] args) {
    new RecursivePairParenthesis(Integer.parseInt(args[0])).PrintPairParenthesis();
}

Unfortunately it uses recursion to operate, so that is still an issue. It also runs much slower for the same values of n than my original correct answer. It’s N-time is still between 2^(n-1) and 3^(n-1), but is less than my original answer. It also does not operate to millions effectively, as you would have to configure the stack to have millions of frames on it.

Next I tried to unwind the recursive nature of the recursive answer, but I ended up with very ugly code that operates without any noticeable performance increase. This took me a couple hours to do, so certainly would not have been something I would have been able to complete in the 30 minutes given for the original coding test.

Still not satisfied, I did end up spending a couple more days (yes, days) coming up with a better answer. This answer will at least theoretically handle n in the millions (more on than in a minute). This code looks like this:
int[] openPositions = new int[pairs];
final int pairs2 = pairs * 2;
byte[] sb = new byte[pairs2];
for (int i = 0; i < pairs; ++i) {
    sb[i] = '(';
    sb[i + pairs] = ')';
}
for (int i = 0; i < pairs; ++i) openPositions[i] = i;
int pos = pairs - 1;
while (pos >= 0) {
    System.out.println(new String(sb));
    pos = pairs - 1;
    sb[openPositions[pos]] = ')';
    if (++openPositions[pos] > pos * 2) {
        while (--pos >= 0) {
            sb[openPositions[pos]] = ')';
            if (++openPositions[pos] <= pos * 2) {
                sb[openPositions[pos]] = '(';
                for (int i = pos + 1, x = openPositions[pos] + 1; i < pairs; ++i, ++x) {
                    sb[x] = '(';
                    openPositions[i] = x;
                }
                break;
            }
        }
    } else {
        sb[openPositions[pos]] = '(';
    }
}

It only uses arrays with n or n * 2 elements, so memory usage is fixed. It does not use recursion, so has no stack overflow issues. It runs ever so slightly faster than the recursive or unwound answers, but still much slower than my first correct answer. It’s N-time should be slightly better than the recursive version, but still between 2^(n-1) and 3^(n-1).

The keys to this final method are realizing several things:
- There are exactly n opening parenthesis and n closing parenthesis.
- The first open parenthesis can only be in the first position and the last closing parenthesis can only be in the last position.
- The second open parenthesis can only be in the second or third position, with a corresponding pattern for the second to last closing parenthesis.
- Each answer will be exactly 2*n characters long.

With these in mind, this makes the pattern of open parenthesis look like a spring or wave:
((((....
(((.(...
(((..(..
(((...(.
((.((...
((.(.(..
((.(..(.
((..((..
((..(.(.
(.(((...
(.((.(..
(.((..(.
(.(.((..
(.(.(.(.

N in the millions is not good. At n = 64, there are more than 2^64 answers or more than 9 exa answers. With each answer at 128 bytes, that is more than 1 zettabytes of output. Given that some really big companies have exabytes of data, this one coding test problem is suppose to generate more data than these large companies currently have.

Did I pass the second time around? Maybe. But really the coding test is flawed:
1) The code has virtually no practical value: I can come up with two very obscure questionable uses for this output.
2) Giving the wrong answers as examples does not make for good code.
3) To give an answer that makes it beyond n = 17 and in the 30 minute time frame would have required knowing the question and correct code ahead of time. My first correct version takes ~3.5 seconds for n=15. My last spring version takes ~45 seconds for n=15. Both take about x3 longer for each successive n. In other words, if memory is not an issue, then use the memory version since it is 13 times faster.
4) To give the best correct code answer, one that theoretically could handle n in the millions would have taken way longer than 30 minutes unless you memorized the answer beforehand. I do not believe I could memorize it well enough to spit it back out correctly.
5) N-time is meaningless in comparing these versions. The worst N-time had the best performance by a significant margin. N-time can sometimes be a useful tool, but it has limits.
6) n in the millions is not practical for this problem with today’s computing technology, nor is it useful.
7) Writing code that you cannot run is bound to have errors.

Warning: This next part is beyond boring. The two very obscure use cases for this code that I can come up with are:
A) When populating an n-tree based database and you want to evaluate performance across all possible data organization, you could use this code as a basis for populating the data. You would do this to determine practical points at which the database tree should be rebalanced. For larger data sets, it becomes impractical to test every possible structure.
B) Used as a basis for generating formulas that have n variables and are properly formatted. You would further add coefficients, powers, and operators. It starts to break down if you want to include a variable more than once. Modern formula generation methodology uses genetics to find good formulas rather than trying every possible formula.

Friday, March 3, 2017

Phear Technology

I have been trying to get to write this blog entry for a while, but time just gets away at the moment. First where I am with game project. It is still on going, I have several rounds completed without having proper art work. I doubt it is going to be to a code finished state by the end of March. It will certainly need art work that I have no way to complete in a reasonable amount of time as well.

For a change of pace, I have been working a part time contract. From the second week of February thru the end of March for three days a week, I am indirectly, by a couple layers, working for Dekalb County Schools setting up iPads. Mostly I push buttons, take cases off and back on, and unplug and plug them back in. Each one is unique enough that it is not something you can do on autopilot. Originally, we were supposed to do just the elementary schools, but since we finished the last elementary school this past Wednesday, we are moving on to middle and high schools. We typically are in the library, which reminds me of my own high school time where I spent most of my time in the library. We did not get to do all the elementary schools, as some did not have enough iPads to justify having a contractor come in to do them and others were completed by internal IT teams. I did get to visit the three elementary schools that I attended. I was really young when I was at Cary Reynolds and lots of additions were done since I was there so it looks nothing like I remember. Woodward has a whole wing that was added to the entrance I remember. Fernbank changed the most, as it was completely rebuilt starting in 2012. The old building is now a parking lot and the playground is where the building is now. The Science Center looks the same from the outside at least.

Working in schools has reminded me of how desperate our schools systems are. Any help at all, even help that makes them go backwards at first is appreciated. The kids are still kids.

Several times over the past couple of months, I have been negatively impacted by different artificial intelligence (AI) systems. AI has started to show up more in popular media recently as well. Unfortunately, there is a slight misunderstanding of what constitutes an AI. Most people when they think of AI are actually thinking of Natural Learning (NL), whereby a system is taught somewhat like our children are taught to understand their world. AI encompasses anything that is artificially created that makes intelligent decisions. Your phone is AI. Your home thermostat is AI, even the old mercury based ones. AI and NL are not things to fear in themselves, but rather certain poor implementations of them.

An example of a negative impact that most of us with cell phones has experiences is Auto Correct. How many times have people said something inappropriate or humorous as a result of auto correct? It is nice that it fixes TEH to be THE, as that is one typo I consistently make. The problem is the NL part of this. At some level, we have to train the AI via NL or something akin to it for auto correct to work. So each of these humorous mistakes is actually reinforcing the NL to continue to make that mistake. As someone who is dyslexic, do as I intend for you to do which is not necessary what I say. AIs and the computers that run them tend to be literal.

Imagine existing in today's world without a cell phone or email or text messages or GPS navigation systems. Or worse, what if you got the wrong information from them? The failures over the past months have caused me everything from humor to embarrassment to inconvenience to potentially a fine. And in each case, I did not realize there was a problem until long after the problem started occurring. We have this expectation that technology just works. And when it does not, we want it to be fixed quickly. For me, having technology fail is normal. This is probably part of why I work in the field that I do: If something can fail, I will probably make it fail. I try to ignore the minor failures. As technology systems become more complicated, diagnosing failures and fixing those failures becomes increasing difficult. There are so many pieces to understand, it becomes difficult for even the most talented of us to follow.

As an example, I discovered about a week ago that some people or perhaps everyone was not receiving emails from me. I am not even sure at this point when it started since sometimes emails got through. Yesterday I spent the entire day diagnosing the problem. Until yesterday, I had 9 email addresses. They each have or had a specific purpose. It will be difficult for me to give up any of them as even finding what services use a particular email address will be difficult. As a part of figuring out the problem yesterday, I discovered one email address was totally non-functional and that I actually have a 10th email address that I need to monitor. I began the day by sending one email from each of my 9 accounts to all of the email addresses including the source email address. What I discovered is that things were very inconsistent except for the one email address that I was not even aware had a problem until doing this. The two email addresses I knew I was having a problem with did in fact have a problem. Or more correctly, there were multiple problems and sometimes the problems only sometimes caused a problem. I am still not sure that I have fixed all the problems. All I know at this point is that I can send emails from all my accounts to all the others, except for the 10th email address that has an unusual purpose and is not really an address I can send to.

So what did I learn? Some receiving email services silently reject emails for some unknown reasons. Some email services are more aggressive at marking mail as spam than others. Yahoo seems to mark more as spam than the others. In fact, until I added all my email addresses to the safe list, Yahoo marked all of my emails except the one from the Yahoo address as spam. Kind of funny to send yourself spam. I also learned that Google (gmail) is the only one that does not silently reject emails. The last thing I learned was that Apple sucks at automatically managing email settings. That is not exactly true. I knew this a couple months ago when I determined that Apple was not using the correct security settings for Yahoo Email addresses and filed a bug report to that effect. Trying to fix that problem may have in fact contributed to by current woes. The latest version of MacOS Sierra does have the correct settings for Yahoo, but you have to use an undocumented tool to prove that and you may have to delete and recreate the account on your Mac (and perhaps iOS device) to get the right settings.

So perhaps the biggest take away is that if an email, text, or voice mail might need a reply, you should probably reply just so the other person knows you got the message even if you are not yet ready to take action. And if you do not get a reply from me, hopefully that just means I did not think it needed a reply.

To be continued.

Friday, January 6, 2017

Assessment Time

Yes, it has been awhile again. Until the holidays, things were pretty much the same: Moving slowly. The past couple of weeks have been impacted by the normal holiday events. But that time has past. When I started this adventure almost a year ago, the plan was to assess where I was come the New Year. The New Year has arrived. This week I have spent assessing where I am financially and project status. Financially is fine. I could continue as I am for another year. But then the tanks would be completely dry. As for my current project, it is taking much longer than I had hoped. I am spending more time working on the art assets than actual code. I can do the art, but it takes me much longer than I want it to. It is tough when you can see it in your mind, but what comes out of your hands is not the same.

Finances were never such that I could afford to hire an artist, nor do I have enough volume to really need a full time artist. Spec art work tends to be expensive for those that talk about prices. Finding someone trustworthy to do spec work is a challenge as well. An artist has to eat just like the rest of us, so asking for free or cheap art seems wrong to me. And I tend to believe that you get what you pay for: If it is free or cheap, it may not be worth anything. Or even worse, it may be cost you more in the long run.

For my current project, I will be shifting to limiting my own art work to the bare minimum and spend more time focusing on functionality. The intent being that I get it to a point where involving an artist makes more sense. Or in a dreamy world, I magically become faster at art. I will continue to work on my current project until the end of March. Then I will assess where I am again with this project.

Farther out, I feel I can continue working as I am until the end of June. At that point, I will shift gears and start looking for outside work. Much like I did last time, I will be picky to begin with by looking for something with an organization that I believe in first. After a month or two of that, I will shift to looking for higher paying IT contracts. The higher paying contracts usually require travel. The intention then is to work long enough to save enough to go back to game development again.

Another reason to not write was the political world. I started to repeat myself. There was not a good choice. Trump was elected and now deserves your support. If you do not like that, then I suggest you figure out proper ways to change the political world. This was the year for an independent candidate to make a good showing, but none did. Rioting in the streets is not the answer. Whinnying about it does not help. So put your adult pants on and suck it up. I hear Ireland is a nice place to live and loves Americans. Canada might start shooting Americans. Mexico would kidnap you until they figure out you are worthless and then shoot you. California should secede. Nevada probably has to go with it to be viable.

In the mean time, perhaps fate will smile on me and the perfect opportunity will come knocking.

Wednesday, October 5, 2016

We Need More Math!

Recently I have been mired in utilizing rusty math skills. It is frustrating knowing that you can do something in math, but not remember how. Math is all about tricks. Everything derives from some simple rules. Multiplication is just adding repeatedly. As the tricks get more complicated, they come with their own restrictions. Remembering that there is a trick is better than taking the long route. Want to leave a 15% tip? Take the amount, move the decimal place once to the left, making the number smaller. Add half that smaller number to the smaller number. Presto, 15%. Need to know what angle a solo cup rests on a flat ground at? Arc-tangent to the rescue. Need an object to spin? Matrices to the rescue. Which is bigger: 3/4" or 7/16"? Common denominators help. Want a picture to be as big as possible in a window without it being stretched? Ratios are the answer, with a little Boolean logic to help. Math for some is hard. Learn the tricks, and it becomes much easier. Sometimes it just takes one trick to make it all easy. I keep saying this, but math is taught backwards. We should teach the why first, then work your way backwards through the hows.

Below is a screen show of what I am currently working on. It is a cross between a level and a mini-game. The final result will probably look much different than this. This is only one part among many planned. The players for this part are the round robots both in the light and the dark. It is amazing both that it is this for so quickly and take being this slow. Parts that I thought would have gone easily have been slow. Those that I expected to be harder took much less time. This lighting and sizing is being my current biggest challenge. Lighting is a known issue with Unity. Not quite time to put lipstick on the pig yet.

Tuesday, September 6, 2016

In Real Life

Another long break between posts, so there is a lot to cover. I have purchased a Unity license although it was more challenging than it should have been. I setup a similar test application using Unity that I was using with MonoGame. The process to do so was completed in a week or so: much less time than expected. I had spent a couple weeks about a year ago with Unity tutorials, so I already had a leg up on how things worked. It was still nice to get something that worked on all but one of my currently available platforms. Prior to last week, I have spent a couple weeks working on the first game. Of course I stumbled upon some of Unity's lackings, but so far nothing that I have not been able to work around. Last week was a trip to Ireland. Yesterday was a holiday. Today through the rest of the week will be in the mountains.

Ireland was amazing. We spent a couple days in the Killarney area followed by a couple in Dublin. Killarney reminds me a lot of the Highlands or Helen. Small town, lots of small restaurants and pubs. Temperature was mild, warm enough to not require a jacket and cold enough that jeans were comfortable all day. The people bring new meaning to the term friendly. Yes, it is a little touristy. Everyone was helpful and kind. There is a large park area that we drove through on one of our touring days that looked just like the mountains of the southern Appalachians. The park was filled with mountain laurel, rhododendron, and scrub trees. Had that same fall temperature feel as well. Mountains, sea, and plains all right there. I did walk a sea beach, but it was too cold to even think about going into the water.

Dublin, while still a small town in comparison to big cities I am used to, has an old city feel like Washington DC or New York. It is however much older. There are no mega tall buildings. There is plenty of history. The people are just as friendly as they were in Killarney. It was fun to watch Georgia Tech Football in another country, even if it was configured with a bias for Boston College. Irish Catholic school, go figure. At least we now know that 4th and 19 is possible. Go Jackets!

Facts I find interesting: Ireland's land area is slightly more than half that of Georgia. Ireland's total population, both Ireland and Northern Ireland, is about 60% of that of Georgia. The Republic of Ireland's population is less than the Atlanta metro area. If you turn Ireland just a bit, it almost entirely fits inside of Georgia.

A slightly strange thing is the English abbreviation for Ireland is IRL. To me, that stands for In Real Life, an old BBS/gamer term.

Now onto the north Georgia mountains and next week back to game development.

Wednesday, August 10, 2016

Mistakes of others

It is hard paying for mistakes of others. Usually there is some complacency on your part. Perhaps you were in the wrong place. Perhaps you believed someone who was not being truthful. Accepting responsibility for something you did not do is also difficult to swallow. To be a better person, sometimes you accept responsibility. You move forward.

I look at the decisions made four and eight years ago and wish we had those decisions today. Each four years gets to be worse and worse. There needs to be a Moore's Law for elections. It would be an ugly law.

Almost three months ago, I decided to pursue using MonoGame as my platform of choice. Would that I could change that decision now. But that would be taking the bad with the good. I still believe in the concept MonoGame promotes. Unfortunately it is not reality. Open source projects always have issues. MonoGame claimed to cover the platforms I wanted as options to target. Unfortunately, it is not in a state to actually support those claims. A benefit of having access to the source is that you can go fix problems yourself and contribute those back. It is hard to contribute when your primary platform is constantly being broken unintentionally by others. Another truthism with Open Source is that those participating may have different and conflicting agendas. What I have discovered is that the different platforms were each broken in different ways. Fixing them would require becoming an expert in all of them. That defeats the purpose I wanted MonoGame to provide.

In my last blog post, I alluded that a decision point was coming. It has arrived. While the time and book purchases will have gone to waste, it is not truly a waste. I spent that time trying to determine if MonoGame would work for my purposes. In that I was successful, I proved that it does not work for my purposes. I could not know that with out having gone through that effort and spending that time. Perhaps one day, MonoGame will be what it claims. I hope so. It would fill a void.

So where does that leave me now? My fear for this decision was that it might end up me abandoning doing game development. To my relief, I have decided to continue with game development. I will switch to using Unity. Unity has always been a choice. In fact, I spent some time with it more than a year ago evaluating it. It does not give me the source or the ability to fix problems myself. I did not really have that with MonoGame even with having access to the source. Moving to Unity removes one platform I had interest in utilizing but gives me one that MonoGame did not have. Fortunately, Unity recently changed their pricing model. So had I gone with Unity three months ago, I would have had to commit to paying six times what I will be paying today. Yes, it was a significant price change for me. Unity is missing one piece of functionality I want. I will just have to work around that missing functionality. It will require more work on my part to implement, but much less work than becoming an expert in all platforms.

It seems to me there are two sorts of successful people: Those that just succeed without making mistakes and those that succeed in spite of making mistakes. I am glad to be striving to be a member of the second group. Even if it is the mistakes of others are what I have to succeed through.

Meh. Back to moving forward.

Thursday, July 28, 2016

Thrown Games

Yes, the title is spelled correctly.

Recently, I have been quasi-binge watching Game of Thrones (GoT). I say quasi because I sit down to watch one episode and usually watch a second, or four. Yes, I am late to the game. The series started before I finished reading the first book. I wanted to read first and watch second. You may think I am about to launch into how great GoT is. Well, I am not. Do not bother sending hate mail, I already know I am in the minority.

I am enjoying watching GoT: It is entertaining. However, it is not great. It is at best a C+. Yep, I can hear you movie first people saying "here it comes, another one to blast a movie/series because it does not follow the books." If there are people who watch GoT without having read the books first, I think they might be confused. I am well into season 3, so almost halfway through what is available. There is so much in the books that is not sufficiently covered in the series thus far. Entertaining. I look forward to certain points, dread others, and scratch my head over what is excluded. And that would not be the end of it, but it feels "off" or not quite right. It could be the directing, writing, or acting. It is hard for me to tell. There are certainly points of brilliance in each of those areas. But overall, I am not sure where all the hype comes from. It will also not be a series for everyone. Meh. I will still watch till the end or until I catch up to where I have read up to.

Facebook as broken something again for Sudoku Pseudo and has sent a breaking change notice.  Time to spend a few hours figuring out if it is a simple fix and what impact the breaking change has. Since I think I am the only person that plays it, it may just be time to write it off as a failed experiment. It was better when it was first written, before Facebook changed what apps are allowed to do.

On the proper game development front, I continue to run into problems with MonoGame. Well, more of the same problem really. I have bugs with the current "stable" version. Some of those bugs are  fixed in the development version or were supposed to be fixed in the stable version. I cannot seem to get building from source to work at all on my Mac nor can I get the developer built binaries to work. I cannot update to the latest version of the upstream tool either. Being a volunteer supported open source project, I am not getting much help solving my issues. I would gladly give time back to support it. It makes it hard to give back if I cannot get my primary development environment to work. This means I cannot support Apple TV. My fear is that when the next version of MonoGame gets released which is already two months late, it will no longer work at all on my Mac and may still not support Apple TV.

So where does this leave me? I am coming to a decision point: Should I abandon MonoGame as a platform. The problem then is what does it get replaced with. I have not found any other totally workable solutions. Each of the other platforms I have looked at have issues: Unreal does not work with my mac and is unbelievably bloated and slow on all the platforms I have tested it on. Unity has a monthly subscription and does not provide all the functionality I was looking to use. Lumberyard does not work on the Mac. Those are most of the big guys that have platforms available. I have a spreadsheet of 46 platforms that I have did initial evaluations for. Thrown for a loop.