Lost Keystore password

A few years back I uploaded my first mobile game to the app stores. Now that I have completed my master's degree and have worked on several other projects, I wanted to revisit it and give it a few updates.

One of the first things I noticed was how messy my code was compared to how I write now. I did not follow any naming conventions, not nearly enough comments. 

However, the problem I ran into was that I could not recall or find where I stored the publishing keystore password. This is an issue because, if I wanted to easily update the existing app on the Google play store I had to use the same keystore. There is a process of contacting support and being about to use a new keystore, or use a new build identifier and create a new store listing. Luckily I was able to find a tool to help recover the password I needed.

http://maxcamillo.github.io/android- keystore-password-recover/howto.html

I created a word list file of possible passwords I may have used and it was able to find the password I needed very fast. 

Also goes to show how effective password cracking can be.

Custom Function in Google Sheets and XML

Sometimes you don't have a full understanding of somethings functionality or capacity, but you still think 'I can do this'. Eventually you wind up down a rabbit hole and come out learning something new.

This time it is thanks to Google Sheets, XML, and wanting easy access to a bunch of boardgame's details. 

So I'm getting ready to head to a small boardgaming convention for the second time. There will be a game library you play games from, a great way to try out different games. Last year we tried some games based on recommendations, which is great, but other times we were basically selecting games cause the title sounded interesting. 

The problem: I'd like easy access to all the board games information, on a spreadsheet I can have saved to my phone.

Original thought: Googles sheets allows me to save a spreadsheet to my phone for on and  offline use, it has a built in importxml function, and boardgamegeek.com has an API that export XML data. Plus the conventions website has a list of their games, a few even with the boardgamegeek links.

So this should be simple right? ... Yes, for a very small sample.

I need the ID number for the game on boardgamegeek. These numbers are in the links so it is easy to split them out.
So put this is cell A1:
Then use this formula to get just the number:
=SPLIT(A1, "abcdefghijklmnopqrstuvwxyz:/.-")

The other way is if I just have the exact name of the game I could use importxml to get the ID#:
=IMPORTXML(CONCATENATE("https://www.boardgamegeek.com/xmlapi/search?search=",A1,"&exact=1"), "//boardgame/@objectid")

Great now I got the ID number and can get XML stats from:
Using this formula if my ID # is in A2 and I want to get the playing time:

I can adjust that to get anything I can from min and max players to average rating and the game's weight. However I got to a put where there was to many of these that it would cause an error cause they were each separate simultaneous calls, especially when I left the sheet and came back it would want to refresh all of them.

So this is there the script editor came into help. Not only could I combine all the elements for one game into one request, I could also do multiple games at one time! So after working on it for a bit this is what I came up with:

function boardgamegeek(id)
//output an array
var output = [];

//url strings
var preurl = "https://www.boardgamegeek.com/xmlapi/boardgame/";
var posturl = "?stats=2";
var ids = id[0].toString(); //add the first id string

//for each id number combine them to the string
for(i = 1; i < id.lenght; i++)
ids.concat(",", id[i].toString());

//get the full url
var url = preurl+id+posturl;

//fetch and parse the xml
var xmlFeed = UrlFetchApp.fetch(url).getContentText();
var xml = XmlService.parse(xmlFeed);

//for each game
for(i = 0; i < id.length; i++)
//get wanted info
var rows = xml.getRootElement().getChildren("boardgame");
var row = rows[i];
var names = row.getChildren("name");
for(j = 0; j < names.length; j++)
if(names[j].getAttribute("primary")) //get only the primary name of the game
var name = names[j].getValue();
var minplayers = row.getChild("minplayers").getValue();
var maxplayers = row.getChild("maxplayers").getValue();
var playingtime = row.getChild("playingtime").getValue();
var age = row.getChild("age").getValue();
var averageweight = row.getChild("statistics").getChild("ratings").getChild("averageweight").getValue();
var average = row.getChild("statistics").getChild("ratings").getChild("average").getValue();
var mechanics = row.getChildren("boardgamemechanic");
if(mechanics.length > 0) //grab all the mechanics
var mechanic = mechanics[0].getValue();
for(h = 1; h < mechanics.length; h++)
var temp = mechanic;
mechanic = temp.concat("\n", mechanics[h].getValue());
mechanic = " ";
var categories = row.getChildren("boardgamecategory");
var category = categories[0].getValue();
for(k = 1; k < categories.length; k++) //grab all the categories
var tempcat = category;
category = tempcat.concat("\n", categories[k].getValue());
//add all that info to one layer of the array
output.push([name, Number(minplayers), Number(maxplayers), Number(playingtime), Number(age), Number(averageweight), Number(average), mechanic, category]);
//output the array
return output;

The last step to all of this was copy all these values to a new sheet, so the formula wouldn't try to update and to make it easier for mobile access.

Here is the end result that I shared with the community: https://docs.google.com/spreadsheets/d/1kRmvAvvem3SChRfdldJTgGpPvtj-2yzqcE2CR-HnIAQ/edit?usp=sharing

On my version I also setup some additional color conditions for columns like rating and weight, along with some filters and notes.

Finding smarter matchups in Marvel Legendary board game

Marvel Legendary is fun thematic deck building tabletop game, with plenty of expansions. While the game says the different types of cards should be selected by random during setup, this can create games that are very unbalanced. The extreme being that they are completely unbeatable.

I've been working on an app that will hopefully help in setting up more balanced games for a range of difficulties. The first major step has been to identify a method for finding the best and worst hero matchup for a given scenario. 

Here are two examples of the app trying to make the best combination:

And here the worst:

While these type of setups are still being tested, the goal is that once I identify these two extremes I can then rank other teams compared to these.

Unity UI Toggle

Unity's basic toggle setup is great for most uses, however if you want to be able to change the 'Is On' value from code without triggering 'On Value Changed' event you'll have to use the 'Event Trigger' component.

For example I want to save an int to the player's preference that was representing the state of the trigger. 0 for off and 1 for on. I'm saving it here cause the next time the scene loads I want to look at the preference and have my toggle set accordingly.  

So in the 'Start' function I'll set the toggle state based on the PlayerPrefs value, and then when the toggle is triggered I'll change the value accordingly. Code would look something like this:

using UnityEngine;
using UnityEngine.UI; //To access 'Toggle'
using System.Collections;

public class exampleToggleScript : MonoBehaviour {
    public Toggle toggle;

    void Start () 
        toggle.isOn = PlayerPrefs.GetInt("toggleKey") == 1;

    public void toggleExampleTrigger()
        //Toggle triggered do something.
            PlayerPrefs.SetInt("toggleKey", 1);
            PlayerPrefs.SetInt("toggleKey", 0);

The problem occurs when the 'toggleExampleTrigger' is linked to the 'On Value Changed' option of the Toggle component. Every time the scene loads and it changes the value based on the preference setting it will also trigger 'toggleExampleTrigger', causing the toggle state and the preference value to be out of sync.

To fix this I don't want to use the 'On Value Changed' event at all. Instead add the 'Event Trigger' component. 

Using the 'Pointer Click' event type to link 'toggleExampleTrigger' to, I'll avoid this sync issue and be able to change the state of the toggle in code without trigger an unwanted event.