<![CDATA[House Fish Balloon - Behind the Games]]>Wed, 26 Jun 2024 05:33:40 -0700Weebly<![CDATA[Back in Action]]>Fri, 10 Mar 2023 05:43:13 GMThttp://housefishballoon.com/blog/back-in-actionThis blogpost refers to the “Back in Action” Trickdraw card. You may have received it by backing the Trickdraw Kickstarter, by requesting it to be used with a Promotional Edition, or by some other top secret means. “Back in Action” is not part of the base game. Its use is entirely optional.
This is the first card in Trickdraw to interact with the discard pile. As such, it is important when playing with this card to keep the discard pile tidy, and to stay mindful of which card is on top. This is not necessary for normal Trickdraw gameplay (but still recommended).
How do I include it in the deck? After you’ve had a chance to play the base game without Back in Action, shuffle all 4 copies into the deck and play as normal. Note: since we are still in the process of testing this card, we aren’t sure if 4 is the correct quantity. Feel free to also try with 2 or 3 copies (we think 1 is too few). Regardless of how many you choose to shuffle, email us your thoughts about the card at info@housefishballoon.com. It helps us out a lot to hear what you think! Below I’ve outlined the rules and some specific interactions. If you have further questions, please include them in your email so I can note them in future rule clarifications (such as the expansion rulebook!).
Card Text: “Activate the effect of the top card of the discard pile.”
What does “activate” mean?
Cards in Trickdraw “activate” whenever they are played or flipped face up. When a card is activated, you read the card and do exactly as it says. For example, if you play a Prophecy, it activates. If you flip a face down card face up, revealing a Prophecy, it activates the same. Therefore, if Prophecy were the top card of the discard pile, and you played Back in Action, you would activate Prophecy exactly the same way.
But what happens when you “activate” a card like Rally or Local Hero? If you play a Rally face up from your hand, it “activates” in that it is now in front of you, granting you points. Since its effect is ongoing, it is considered to be continually “active” until it flips face down. Similarly, if you flip a face down card face up, revealing a Local Hero, it is now “active” until it flips face down (regardless of whether its currently granting you points or not).
Now what if we use Back in Action to reactivate one of those cards? Does Back in Action gain that effect indefinitely (Local Hero until the end of time)? No. Back in Action only reactivates a card’s effect as Back in Action is played to the field. I’ll break down some examples for what happens if the following cards are in the discard pile:
Insurance Fraud: Simple enough. Upon playing Back in Action, flip three of your cards face down (this can include the Back in Action you just played). No further action needed.
Trickdraw: Simple enough. Discard a card from your hand to activate. Steal a card in play. You may flip it. The only thing to note is that as with all discard effects, you MUST discard a card to activate them. If you don’t have enough cards in your hand, you cannot activate the card.
The Treasure: If you have the Key or the Temple, you win! If not, nothing happens.
Local Hero: You gain 3 points if over half your cards are face down, and no points if they are not. Remember to include Back in Action when counting face down cards. After gaining these points, check if you’ve won the game. If you haven’t, then nothing happens. You don’t keep the points past the moment you play Back in Action.
Rally: You gain as many points as you have Rally cards. If you have no Rally cards, you gain no points. As with Local Hero, check if you won the game. If you did, great! If not, nothing happens. You don’t keep the points past the moment you play Back in Action.
Diplomacy, Thieves Guild, Money Talks, Black Market: The effects of these cards are activated for the duration of the Back in Action effect. That means until you play another card, activate another card. or pass the turn, you can utilize their benefit (once). For example, if you activate
Diplomacy: you don’t have to discard a card if your next action this turn requires you to discard a card. Obviously, if you’re out of actions, then activating Diplomacy does nothing.
]]>
<![CDATA[Implementing AI in Art Direction]]>Fri, 02 Sep 2022 18:02:44 GMThttp://housefishballoon.com/blog/implementing-ai-in-art-directionby Michael Kuroda
Picture
Drawing Barrelmouth City with AI assistance

Introduction

    AI generated art just made the jump from jumbles of spaghetti to nearly indistinguishable expert artworks. 
    As both an artist and production manager, this development is impossible to ignore. My artwork can suddenly be replaced by a robot—instantly drafting images as fast as you can type their prompts. At the same time, I can order countless high-quality illustrations for a fraction of the price I used to pay artists on Fiverr. 
    My current project is the world of Saloondria. It’s a world that merges the wild west with magical tropes. A world of untamed magic faced against a technologically superior frontiersman. The theme is featured in my card game but goes much deeper in terms of lore and artwork. You can learn more about it here.
Picture
Prompt: Hand drawn, sketch of a starry wizard hat with a cowboy hat brim, drawn on parchment, Full page sheet, detailed description written on page, fantasy paper, fantasy script, concept sheet sketch, colorful, 8k resolution, photorealistic: Midjourney
    It’s reminiscent of the position I find myself in today. It is easy to sympathize with the endangered native groups, those peoples that are being shunned, forgotten, and replaced. But, as I hope to explore in this piece, we artists are uniquely positioned to also become the pioneers of a burgeoning era. Instead of six-shooters and dynamite we have Midjourney and Dall-E. 
    In this blog post, I hope to help artists use this tool to their advantage while providing insight from my own experiences as a manager. How to evolve into an AI artist and embrace this exciting new technology.

Drafting your Concept Art with AI

    The drafting process is key to effective art direction, and one of the most exploitable steps by AI artists. This is a time intensive step that lets the art director figure out the “mood” of a world or scene. Some professionals contract artists across the world to bring in a large variety of personal styles. Others may contract a single concept artist to see a range of moods made by a single person. 
    Adding an AI to the mix is incredibly easy. My latest painting is a city built into a giant ravine. It is a 19th century gilded age version of a dwarven metropolis. But to fully immerse yourself in the idea of the city, it needs to be consistent across the lore and mood. 
    Now is the perfect time in the process to experiment with various AI generators, as well! While Dall-E 2 costs roughly 13 cents per prompt here, and Midjourney charges $30 for unlimited prompts, you can also try Craiyon or StableDiffusion for free. Here is an example of "​A crowded dimly lit magical underground Art Deco victorian Times Square with carts and vendors everywhere, built into a giant cave, skyscrapers stacked on top of each other, epic photorealistic concept art" using four separate AI generators.
​​
    At first I was inspired by Edward Hopper’s Nighthawks, and the melancholic mood of a lonely twilight. This gave the city a bit of a Bioshock feel. A video-gamey liminal space feel, that didn’t evoke much emotion. 

Current Prompt: An underground roaring 20s metropolis, built into a giant cave, skyscrapers stacked on top of each other, bright windows, and incandescent signs, photorealistic epic concept art painting by Edward Hopper
    I changed the prompt slightly, indicating " 1800s victorian," and "day." Removing Edward Hopper also brightened the scene considerably. This made the scene a lot brighter, but still felt a little empty without anyone walking around the city. 

Current Prompt: An underground 1800s victorian Times Square, built into a giant cave, skyscrapers stacked endlessly on top of each other, bright windows and incandescent signs, photorealistic epic concept art painting, day
    As such, I changed the wording to find a more bustling and vibrant scene. After a few iterations, the scene was already looking more like a lived in version of Barrelmouth City. People were crowding around the world, criers stood on crates, and vague cart shapes seemed to materialize. Here are the three finalists I selected from the drafting process.

Final Prompt: A crowded dimly lit magical underground Art Deco victorian Times Square with carts and vendors everywhere, built into a giant cave, skyscrapers stacked endlessly on top of each other, bright windows and incandescent signs, photorealistic concept art painting, day
    The first of which gave the impression of a New Orleans inspired market district. Buildings crowd together, while people and carts scatter around the street. Red shapes around the painting indicate the signs of various shops as well as a festive red clothesline. But it doesn’t show off the underground nature of the city at all. This is a problem shared by the second picture. I love the idea of criers standing on boxes while crowds of people wander around—but it feels like a common outdoor area more than anything else. 
    This leaves us with my selected picture. Crowds of people are scattered throughout the scene, and the varied buildings give a sense of scale to the scene. The main building is dwarfed by the stone arches that loom above. It reads as a gilded age city, and one that is built into the earth. While there isn’t too much in the way of magic, we can use Dall-E’s editing feature (and our own painting) to make some minor adjustments.

Adjusting your AI generation (manually and in Dall-E)

The selected concept picture works well, but it isn’t perfect. After generating several unsuccessful variations on Dall-E, I find that it’s best to make edits to the picture itself. By erasing key issues and generating variations, we can make the painting align even closer to our original vision.
    For my main picture, I generated some variations on the crowds and added an Airship to the scene. These took a few iterations, but you will know when it looks right. 
Prompt: The bow of a magical floating ship levitating docked over the city
Picture
award winning poster of a historic musical production. The portrait of a fat balding king in red robes with a shining golden crown frowns at the camera. A wildfire rages behind far him, with crowds of rioting people in the background. Epic photorealistic painting by raphael
Picture
Various Faces added in one by one to each figure in the background. Also edited some of the figures to make them less "blobby"
    NOTE: One trick for paintings of smaller groups is to AI generate the individual faces and add them back onto the picture. Use Dall-E’s upload function, and crop the picture down to the person’s head and shoulders. This is extremely credit intensive but very worth it.
    You can continue to edit your picture with Dall-E throughout the painting process. Much like Photoshop’s new smart filters and old content aware tools, this editor can help with some of the more tedious work of your painting. This allows you to focus on the more interesting parts of your image. As I manually fix the windows, perspective issues, and add in the first billboards with ProCreate, I used a few more edits to generate some additional arches and try out some different directions for my painting. Not all of them are successful, but it remains extremely helpful.
Prompt: Crowds of people wearing magical witch fantasy clothing, in a bustling victorian city, photorealistic concept art.
Picture
Barrelmouth City, drawn by me over a 3d model base
Picture
Barrelmouth City, drawn by me over an AI generated base

Finishing Touches

    The final image took several hours to complete. Painting over windows, ensuring that the crowds are witches with newspapers, and making the salmon restaurant in the foreground were some of the main steps. I also made sure to incorporate some extra lore with a bit of graffiti and finalizing some of the billboards and signs.
    Where I would usually spend hours mocking up picture variations, trying different color schemes, and adding environmental depth, I can now spend that time adding effects and billboards. As a result, this new painting of Barrelmouth City is much more lively than my previous attempt while simultaneously taking much less time.

Final Thoughts on AI generated Images

    I previously played around with using 3D renders as a base for my cityscapes. Production designers sometimes use tools such as Sketchup to quickly put together scenes in a perspective view. I also tried Maya and Daz Studio to place shadows (at the expense of a much longer creation process). Finishing this picture helped me realize that AI renders might just take that place for now. They have a ton of power for creating small images and drafting ideas. But I’m not too worried --  they aren’t fully replacing a stylized artists or concept artists just yet.
    That said, we are still in the wild west of AI art. Maybe one day, you will be able to completely develop a scene by cropping down an image and specifying certain logos, billboards, types of people, and so on. But until then, I’m going to be using it to my advantage as an artist.
]]>
<![CDATA[How to Win Machi Koro, using Machine Learning]]>Mon, 08 Aug 2022 00:22:34 GMThttp://housefishballoon.com/blog/how-to-win-at-machi-koro-using-machine-learningby Michael Kuroda
  • What is Machi Koro?
  • What am I doing?
  • The Setup
  • AI Strategy
  • Initial Results
  • Best Strategy based on Win Time
  • Best Strategy based on 1v1 Matches
  • 2 Player Results
  • As for Adaptability
  • How to Win at Machi Koro

TL;DR

Just want to read a summary? That's cool too! I ran a Python algorithm and found that four strategies outperform everything else. And those are Cheese FactoryBakery, Convenience Store, and One-Die-Spread. Scroll down to two Player Results to see how they win against each other and when to use them.

What is Machi Koro?

Machi Koro is a fast-paced game for 2-4 players. Each player wants to develop the city on their own terms in order to complete all of the landmarks under construction faster than their rivals. On their turn, each player rolls one or two dice. If the sum of the dice rolled matches the number of a building that a player owns, they get the effect of that building; in some cases opponents will also benefit from your dice (just as you can benefit from theirs). Then, with money in hand a player can build a landmark or a new building, ideally adding to the wealth of their city on future turns. The first player to construct all of their landmarks wins!

What am I doing?

Ever since playing this game for the first time, I realized that this is not at all a balanced game. Expecting to progress from a simple one-die early game to a two-die mid game with reasonably balanced mid-game industries, then to a late game of grabbing up Stadiums and finally the sought-after Landmark cards, I was quickly struck down from that expectation. One player bought 6 Cheese Factories in the first 6 turns, 2 Ranches, and a Train Station in the next few turns, and nothing after that. While I was busy grabbing my Mines and Business Centers, the player rolled a 7. They received 36 coins in one turn. Then they rolled a 7 again, and received another 36 coins. Without even worrying about late game industries, they simply bought all four landmark cards at their leisure. All because they owned two secondary industry cards.
So, after being inspired by a post on BoardGameGeek, I decided to run my own tests on the game. After all, user Travis Archer suggests that Cheese Factory wins nearly 75% of all 2 person games, and almost 50% of all 4 person games, making it severely overpowered. Is Cheese Factory really that powerful? Or was I unlucky in my first playthrough? I decided to run my own code to test it out.

The Setup

First of all, I sought to replicate Archer's results in my own Monte Carlo Algorithm. This required the inputting of each major strategy and each card. Here are the following strategies:
Note: I also included a Genetic Algorithm section. I was incapable of getting any reasonable results (nothing could beat Cheese Factory even 10% of the time after several hours of running the program). As a result, I will not discuss it in this post.
Monte Carlo methods, or Monte Carlo experiments, are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. The underlying concept is to use randomness to solve problems that might be deterministic in principle. 
  • One Die Spread: Focused on adaptability over everything, this strategy buys just  few of each base card, and tries to win the game by making a little money each turn.
  • Convenience Store: Focusing on the Shopping Mall, the Convenience Store strategy gets 1 additional coin for every one of its establishments.
  • Furniture Factory: Focuses on maximizing the lesser-used Furniture Factory Card. 
  • Fruit and Vegetable Market: Focuses on maximizing the Fruit and vegetable market. A low cost card with a low roll chance, but a high payout if landed. 
  • Mine Spread: Why receive points on your turn only? The mine spread loves it when anyone rolls all sorts of numbrs.
  • Nothing Strategy: Screw playing the game, this player just saves up for his Radio Tower, Train Station, Shopping Mall, and Amusement Park.
  • Cheese Factory: The infamous 75% win rate strategy. Makes a ton of money on the most likely roll. 
Meet the Contenders:

AI Strategy

I made a few deviations from Archer's Code. Most notably, I changed the buying algorithm pretty severely. Rather than purchase the most valuable card a person can purchase, my AI purchases each card in order of desirability. In other words, it needs to buy the popular cards first, otherwise it may end up dead in the water with only its now-useless secondary industries. In other other words, I have a list of things, and the AI buys each thing in the order of the list, unless the card is unavailable or if it cannot afford the card.
Each player has a value list made up of two sections; on their roll, and on other player's roll. If Player A purchases a Wheat field, they will receive 1 value at 1 their roll, and 1 other player's roll. If Player B purchases a Cafe, they will receive 1 on other player's 3 roll, and everyone else will lose 1 on their 3 roll. 
Once buying could be solved, the rest of the algorithm is very straightforward. The computer rolls a dice, and doles out money depending on what values each player has on that number.  We just need to simulate this about 80 times per player, until the game ends, and over the course of 10,000 games. With a running tally of who wins and when they win, we can find our Results.

Initial Results (Beating random strategies)

First of all, I had to replicate Archer's results myself. This was surprisingly easy, as it just required fixing all of the bugs in my code* and putting together a single algorithm. Playing against random strategies, the Cheese Factory performed very well. Note: As my algorithm runs a bit differently, I was able to focus my one die strategy on buying Ranches first, or buying Bakeries first. This has a non zero impact on its win rate. Although its not significant enough for me to continuously adjust it throughout the following steps.

*Exaggeration, fixing bugs is never easy.
But this is not a very realistic game state, unfortunately. This blog post is about Winning Machi Koro more consistently, not beating up some low performing strategies. If you want to beat the Fruit and Vegetable Market, for example, you can use almost anything. 

Best Strategy Based on Win Time

This box and whiskers plot shows how long it takes various strategies to win the game. The AI they play against is randomly generated and is incapable of winning the game. Initial tests saw heavy selection bias, as it would only show the winning version of each strategy's times. Meanwhile, having no opponent would leave strategies that rely on card stealing, or opponent rolls would be left useless.
in this plot, we can see which strategies perform best given no competition. In theory, you should always play the Bakery strategy if nobody else is buying bakeries. Ranch is a very close second. Both of them will collapse if the other players decide to purchase 3-4 Bakeries or Ranches, however.

Best Strategy based on 1v1 matchups

Pitting strategies against each other in 1v1 matchups yields some different results. Based entirely on how often a strategy wins a matchup, the Convenience Store strategy suddenly pulls ahead. This strategy relies a little bit on the Bakery, but it also uses the rarely used Convenience Store to boost its revenue with the Shopping Mall. This strategy is extremely strong in 1v1 matches, and only regularly loses to an unopposed Cheese Factory. Meanwhile the One Die Spread is a interesting contender here. Its strategy never gets destroyed, but it doesnt purchase enough key industries to destroy the other power strategies.
Illustrated version of the chart above. Each building's opacity is equal to its win% over the other strategy. (50%-100%) As I tested two One-Die-Spreads, I had two different results on only the Cheese Factory/One-Die-Spread Matchup.

2 Player Results

With two players in the game, no strategy of the three major strategies wins consistently. However, all three of them outperform everything else aside from the One-Die-Spread. 
The Cheese Factory strategy is the second fastest and regularly beats anything that diversifies. But Cheese Factory is extremely RNG focused, and will lose to the more consistent Bakery 53-60% of the time. And the Bakery can easily be destroyed by any strategy that takes up its precious bakeries, such as the Convenience Store, about 60-65% of the time. Cheese Factory beats the Convenience store around 60% of the time.

As for Adaptability

The most concerning results of the previous sections is that there is no easy way to beat the three major strategies in a 1v1 matchup. A one die spread can sometimes outperform the Cheese Factory and Bakery strategies, but even buying two of a strategy's main card is not certainly going to stop them. You can buy more than that, but then you will eventually be playing the same strategy as they are. And if you do attempt to play the more adaptable One-Die-Spread, you can still get squashed by the Convenience Store strategy.
This is where multiple players come into play. While a One-Die-Spread is the worst of the major strategies in a 2 person game, it actually gets significantly better once the other strategies are pitted against each other. Two Cheese Factory players will make each other irrelevant. Two bakeries have the same effect. Even the Convenience store gets destroyed when its key cards are lost. The One-Die-Spread does not suffer from this problem at all. As long as you are focusing on a group of different strategies with more players, you can actually pull ahead of most.

How to Win Machi Koro

To consistently win at Machi Koro, just keep the three major strategies in mind. If you are in a two player game, just play the winning strategy against the person who starts going for another strategy. Stealing their cards doesn't usually work unless you take half of the available pile, at which point you might as well follow the same strategy. 

However, with three or more players, keep your options open and go for a strategy if you can. If nobody is taking ranches, destroy them all with the Cheese Factory. If nobody is taking Bakeries, then beeline victory with the Bakery. And if nobody is taking wheat fields, do not for the love of God buy the Fruit and Vegetable market because that strategy is more of a lottery ticket than a real strategy. You can instead try the One-Die-Spread as a safe option against known strategy players.
]]>
<![CDATA[A Data-"Driven" Approach to Mario Kart Wii Tiers]]>Sun, 24 Jul 2022 23:13:52 GMThttp://housefishballoon.com/blog/a-data-driven-approach-to-mario-kart-wii-tiersby Michael Kuroda
My final vehicle tier list. My character tier list is slightly further down the page.

SECTIONS

1. Introduction
2. ​Method
3. Results
4. The Tier List
5. Conclusion
               ​​Ever since getting back into Mario Kart Wii, I have been looking into ranking the Karts and characters. However, every list I could find is mostly based on empirical observations. (I enjoy playing the sneakster because…) While this is great for the #1 Kart and #1 character, it doesn’t effectively rate anyone beyond the #1 Kart and #1 character. Other approaches use oversimplified equations (10x speed, 9x drift…), which fail to accurately rate karts and characters, as speed isn’t 2x as good as the 5th best stat, it might be 8x as good. It also fails to address drifting, and Kart type. 

Introduction

               ​Luckily, I have a few tools to improve the existing lists on Mario Kart tiers. In this case, I am opting for the straightforward data analysis approach of a Liner Regression Model.
               ​What is Linear Regression? It is the first model you learn for analyzing data. By taking a cluster of random observations, and a series of traits that each observation has, it attempts to predict the observation’s output based on its traits. For example: the output, or dependent variable may be a student’s final grade. The traits, or independent variables denote things such as study time, previous grades, and participation. Running a Linear Regression attempts to predict each student’s final grade based on a multiplier attached to each variable (study time, previous grades, participation), minimizing the difference, or residual, between the predicted observations and real observations.

Method

               ​As I am attempting to find a list of the best characters and best karts based on stats, I need a group of reasonably consistent stats to work off. Time Trial Data is what I settled on. All staff ghosts need to be reasonably challenging to beat but are at around the same skill level. Meanwhile, to find the optimal time on a course, I selected world record times for each Time Trial. 
Example of where I collected data from. Using youtube playlists, manually writing down the best time, as well as the character (Daisy) and Bike(Mach Bike)
               ​The first step lies in data collection and data cleaning. This step is probably the most tedious of all of them. It requires the extraction of data from spreadsheets, websites, or even videos (how I collected this data). And if you are lucky enough to have an easily accessible source of data, its often difficult to “clean” it, so that you can run a regression model easily.
               ​After pulling Staff Ghost times from each track, as well as World Record Times (glitchless) from each track, I took the stats for each vehicle and character that the times were made with. This was the most time consuming step but was mostly just a matter of linking Karts to a few tables showing their stats, then adding the character stats. VLOOKUP is your friend here.
               ​Initial regressions failed, as certain tracks are very different than others. This includes tracks like Sherbertland or Shy Guy Beach, where off roading is disproportionately powerful. With all the tracks together, I was getting the Offroader as a #1 overall vehicle, which doesn’t seem right. I removed every World Record Time that wasn’t made with Funky Kong and the Flame Runner to address this problem. 

Results

               ​My regression model now measured the time difference between the staff ghost and the world record, based on Speed, Weight, Acceleration, Handling, Drift, Off Roading, and Mini Turbo. And using the staff ghosts as a skill level that we’re following; I found some interesting results. Speed is obviously the most important aspect of a Kart or Character. But Handling was the second most important, followed by Mini Turbo. Acceleration was a very neutral stat, off roading was the third least important, weight was the second, but drifting is weirdly the worst stat for staff ghosts. If a staff ghost must drift, they will have much worse times in comparison to Funky Kong and the Flame Runner. 

Speed*61.7742 - Weight*17.9345 - Acceleration*5.301 + Handling*23.08 - Drift*25.2 - Off Road*9.1 + Mini Turbo*19.84 + 3950.93

               ​There are a few issues with this model. The R^2 is pretty low on this equation (around 0.359, which is usually negligible), with an adjusted R^2 of 0.0142. The worst part is that the P values for each variable are very high and therefore insignificant. In the future, I should find better data sources to work off of, but this should still function a little better than the crude existing equations. 
The Final Ranking system is as follows:
Bikes with Inside Drifting are bolded
               Obviously this is not showing us the best karts or characters in general. In general, the best Kart should be the Flame Runner. The best Character should be Funky Kong. But as our data follows the Staff Ghosts, we are measuring the best vehicle for the staff ghosts, and the staff ghost skill level. Most Mario Kart players in general are around this level, but a lot of people playing now are probably much better than the staff ghosts. That being said, we can always remove things such as handling from the equation or run a different regression if more data is made available.

The Tier List

By now you've already scrolled past my two final tier lists, but here they are again. There is not too much science behind how I placed the vehicles or characters here, but I did penalize Karts and outside drifting bikes before assembling the vehicle tier list. Beyond that, these are my final results, for the best characters and karts for the average Mario Kart Wii player.

In Conclusion

               Why am I exploring this on House Fish Balloon’s blog? Because Mario Kart is a video game and uses a lot of different characters with different skills and different balancing decisions. When we work on our own games at House Fish Balloon, we use similar approaches in solving game design problems. Trickdraw (Kickstarting until the end of July) is the most recent card game that we tested this with, but we have been using game testing algorithms for a few of our upcoming new games, as well. 
]]>
<![CDATA[Optimizing your Fantasy Map using Mapbox Javascript]]>Sun, 24 Jul 2022 17:26:29 GMThttp://housefishballoon.com/blog/optimizing-your-fantasy-map-using-mapbox-javascriptTL;DR: Using Mapbox JS documentation to add markers, toggleable layers, and raster images. Check out the map here.

What will I Cover?

  1. Using Map Tacks
  2. Swapping between Map Styles
  3. Using Raster Layers
    A few weeks ago, I used Mapbox in an unorthodox way—to create an interactive fantasy map for the world of Saloondria (home to Trickdraw, Kickstarting until the end of July). This meant exporting GEOJson data from Azgaar’s Fantasy Map Generator, coloring them by height and biome in Mapbox, and embedding the map onto our website. It was a fun process, and I got a lot of encouraging comments wherever I posted it! I was encouraged to develop it beyond what I had before
​    This time, however, I am mostly going to guide you through how to develop your Mapbox HTML on your website. This part is a lot more code-heavy than my previous post. Anyone can copy/paste one of these segments for their own fantasy map, but I recommend having a basic understanding of coding before you attempt to merge these segments together. 

Using Map Tacks

The Mapbox Documentation can be found here. It explains how to do what I'm doing below pretty well.
    Map Tacks are an awesome way to show off points of interest. For me, those points of interest are my Saloondria Short Story locations, as well as posts to Reddit.com/r/Worldbuilding. Both of which look into the lore behind the world of Saloondria and are usually centered around certain cities or regions.
    This endeavor was definitely the hardest when I first started working with Mapbox documentation. It requires delving straight into some of the major Mapbox features. What will you need to do to create your own map tacks? 

Style your Popup Box

Picture
    ​Step one is to create the Popup style. What will it look like when you click on one of the many markers on your map? Here is an example of how I formatted mine. (style tags removed to show on weebly)
     .mapboxgl-popup {        max-width: 390px;         font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-          serif;     } 

Adding a Source For Your Markers

    ​With the popup style out of the way, you can begin creating your geojson data. I created mine in HTML on my website, but you can also import your tacks and tack locations if you have that available. This is an example of one data point added to my “places” geojson source:
map.addSource('places', {            'type': 'geojson',            'data': {                'type': 'FeatureCollection',                'features': [                    {                        // Hatbrim Council                        'type': 'Feature',                        'geometry': {                            'type': 'Point',                            'coordinates': [0.481724, 41.875105]                        },                        'properties': {                            'title': 'City of Hatbrim',                            'image':'INSERT POPUP HTML HERE',                        }                    },
  Breaking apart this code, I am creating a single feature for the geojson data set. This feature could be as as simple as ‘type’: ‘Point’, ‘coordinates’:[0.4, 41.8]. However, for my popup window, I attached an image, some text, and a link. This is a miniature HTML group, all nested within the properties section.

Create a Layer From Source

      Next up, we need to make these tacks into an actual layer. Create a layer using map.addLayer({});. Within the layer, you should add an ID, type, source, and layout. Here is how I formatted mine:
Adding the layer:
        map.addLayer({            'id': 'Saloondria Short Stories',            'type': 'symbol',            'source': 'places',            'layout': {                'icon-image': 'custom-marker',                'visibility': 'visible'            }                            });   
Adding the custom marker image:
        map.loadImage(            'https://housefishballoon.comhttp://housefishballoon.com/uploads/1/3/3/5/133560731/published/fishpin.png?1654512979',            (error, image) => {                if (error) throw error;                map.addImage('custom-marker', image);            }
    The id and visibility will later be used to toggle the map tacks on and off. Meanwhile, the icon-image is linked to a custom image I loaded using map.loadImage(). 

Showing Information on Click

Showing the information you set up when the user clicks on a Map Tack is a matter of creating a map.on('click') event, setting the coordinates to equal that of the map tack, and initializing the popup with the html info you created earlier. This section of code also changes the user's cursor to indicate that a map tack is clickable:
map.on('click',['Saloondria Short Stories','Worldbuilding Posts'], (e) => {                        map.flyTo({                center: e.features[0].geometry.coordinates            });            // Copy coordinates array.            const coordinates = e.features[0].geometry.coordinates.slice();            //const description = e.features[0].properties.description;            const image = e.features[0].properties.image;            // Ensure that if the map is zoomed out such that multiple            // copies of the feature are visible, the popup appears            // over the copy being pointed to.            while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {                coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;            }            new mapboxgl.Popup()                .setLngLat(coordinates)                .setHTML(image)                .addTo(map);        });        // Change the cursor to a pointer when the mouse is over the places layer.        map.on('mouseenter', ['Saloondria Short Stories','Worldbuilding Posts'], () => {            map.getCanvas().style.cursor = 'pointer';        });        // Change it back to a pointer when it leaves.        map.on('mouseleave', ['Saloondria Short Stories','Worldbuilding Posts'], () => {            map.getCanvas().style.cursor = '';        });                // If these two layers were not added to the map, abort        if (!map.getLayer('Saloondria Short Stories') || !map.getLayer('Worldbuilding Posts')) {            return;        }
    This map.on('click') function allows for the map tacks to toggle the popups we designed earlier in this section. I supplemented this by adding a map.flyTo({}) section. Historymaps was a huge inspiration for that addition.

Swapping Between Map Styles

    Again, the Mapbox Documentation can be found here and here. Skip this step if you're satisfied.
    Map Styles is an interesting step, and the biggest change I made from the previous map version to the current version. It adds depth to your world by allowing the user to swap between different display options. Maybe they want to see what your geography looks like. Maybe they also want to know the religion, or the political intrigue? This can be done in two ways: By adding all of the information on one, very dense, map. Or by allowing the user to toggle between different maps.
    To do this, you will just need to understand two major functions. A toggle system for layers that can be turned on and off, and a switch that disables other layers when it is enabled. 

Creating the Menu

Lets start by creating the menu itself. This will be the GUI that the user can click on to change which map style is enabled and which map layers are visible.
Adding the Menu style to our <style>
    #menu {        background: #fff;        position: absolute;        z-index: 1;        top: 10px;        right: 10px;        border-radius: 3px;        width: 120px;        border: 1px solid rgba(0, 0, 0, 0.4);        font-family: 'Open Sans', sans-serif;    }    #menu a {        font-size: 13px;        color: #404040;        display: block;        margin: 0;        padding: 0;        padding: 10px;        text-decoration: none;        border-bottom: 1px solid rgba(0, 0, 0, 0.25);        text-align: center;    }    #menu a:last-child {        border: none;    }    #menu a:hover {        background-color: #f8f8f8;        color: #404040;    }    #menu a.active {        background-color: #404040;        color: #e5d4a8;    }    #menu a.active:hover {        background: #3074a4;    }
Create Menu using our style guide.
        for (const id of LayerIds) {            // Skip layers that already have a button set up.            if (document.getElementById(id)) {                continue;            }            // Create a link.            const link = document.createElement('a');            link.id = id;            link.href = '#';            link.textContent = id;            link.className = 'active'
Picture

Adding Toggleable Layers

    Remember the layer name and visibility we used in the previous section? Toggling a layer style is about as simple as enabling and disabling that layer's visibility. (swapping between 'visibility':'visible', and 'visibility':'null'.
How I added toggle layers:
link.onclick = function (e) {   const clickedLayer = this.textContent;   e.preventDefault();   e.stopPropagation();                   if (toggleableLayerIds.includes(clickedLayer)){      const visibility = map.getLayoutProperty(      clickedLayer,      'visibility'   );   // Toggle layer visibility by changing the layout object's visibility property.   if (visibility === 'visible') {      map.setLayoutProperty(clickedLayer, 'visibility', 'none');      this.className = '';   } else {      this.className = 'active';      map.setLayoutProperty(         clickedLayer,         'visibility',         visible'      );   }
Note: The basic Mapbox Documentation does not consider swapping layer styles, as well as making layers visible and invisible. To address this, I added a variable "toggleableLayerIds" which contains the layers that can be swapped on and off.

Adding Map Style Selection

However, I want to push things a little further today. Layers are fun to enable and disable, but we still need to show off the various maps that a user can switch between. Lets add another style! 
    Just copy and paste your mapbox style. Using the second version, you can edit the colors of your cells based on something else. I chose "Country ID" for one, and "Religion ID" for another. This gives us a couple more style options to choose from.
    With links to your new styles, you just need to create a function that lets you toggle styles on and off. The trickiest part of this would be disabling the other styles, and toggling your main style on and off. Aside from this, its as easy as a few "if" statements, and a for loop if you have more than a few styles to work with.
How I implemented this:
else{ if(clickedLayer == 'Religious Map'){    if (this.className == ''){       map.setStyle(RELIGIOUS MAP STYLE HERE');       document.getElementById('Country Map').className = '';       document.getElementById('Illustrated Map').className = '';       document.getElementById('Geographic Map').className = '';       this.className = 'active';    } else{       this.className='';       map.setStyle('DEFAULT STYLE HERE');       document.getElementById('Geographic Map').className = 'active';    }}
    With that finished, you should have a functioning menu to swap between styles! Congrats!
NOTE: If you decide to change map styles with your pins, you should make sure that your pins only load when the map style loads: map.on('style.load', () => {, as opposed to on initial load. Otherwise they will disappear when you change the style.

Raster Layers

    If you finished the previous steps, you should be a master of raster layers. Here is the Mapbox documentation for this step.

Raster Layer Example

    Adding raster layers is actually much simpler than the previous steps. The main difficulty lies in finding the exact coordinates you want to set each corner of an image at. If an image is a square, you can just move each coordinate the same distance each time. However, if its a rectangle, you may need to do a bit of math (or trial and error) to reduce distortion.
Adding the Raster Layer:
        map.addSource('Sea-Monster', {            'type': 'image',            'url': 'https://i.imgur.com/yUBlrGs.gif',            'coordinates': [                [-1.416139, 42.011105],                [-1.116139, 42.011105],                [-1.115966, 41.711105],                [-1.416139, 41.711105]             ]        });        map.addLayer({            id: 'sea-monster-layer',            'type': 'raster',            'source': 'Sea-Monster',            'paint': {                'raster-fade-duration': 0            }        });
    Working with the Raster Layer itself is as easy as importing an image link. .gifs seem to work the best. Using a link to the actual .gif image, you can import that as the url, and give it your desired corner coordinates. (you can find coordinates on your mapbox editor if necessary).

Toggleable Raster Layer

Lastly, if you desire to toggle a raster layer the same way you toggle your pin layers and map styles, it is not too difficult. Just make sure to set a layout style, with visibility set to "none." This way, if you update your map with every style change, this isn't the first thing that shows up!
Adding layout to allow for toggling.
        map.addLayer({            id: 'Illustrated Map',            'type': 'raster',            'source': 'Old-Map',            'paint': {                'raster-fade-duration': 0            },            'layout': {                'visibility': 'none'            }        });

In Conclusion

    Hope that this guide can help any worldbuilders out there. It took a bit of searching on my part to find these particular documentation pages to work from, but each part of it certainly adds to my fantasy map of Saloondria. If any part of this is confusing you, just let me know in the comments and I will try to address it in an updated blog post, or in the comment section.
    And if you are in need of a game to play after reading through all of this, I suggest checking out Trickdraw (on Kickstarter until August 1st)
]]>
<![CDATA[[Tutorial] Building an Interactive Fantasy Map in HTML]]>Mon, 06 Jun 2022 12:56:41 GMThttp://housefishballoon.com/blog/building-an-interactive-fantasy-map-in-htmlby Michael Kuroda

TL;DR

If you’re like me and want to get to the point, here are the basic steps:
  1. Azgaar World Generator
    1. Build your world with Height, Biomes(optional), Markers(optional)
    2. Export GeoJson Cells and GeoJson Markers(if used)
  2. Mapbox
    1. Create an account
    2. Make a new Style
    3. Import GeoJson file
    4. Edit map
    5. Grab your accessToken and Style link
  3. HTML
    1. Use the Tutorial of your choosing, but with your own Style
    2. Play around with features such as onClick and flyto.

An Introduction

A few days ago, I noticed a very interesting Reddit Post around a website (https://history-maps.com/) that uses JavaScript and HTML to display history in relation to the geographic location of each event. Being a history nerd, I found the page to be extremely interesting. But being a worldbuilder, I wondered whether it would be possible to go a little further and build a history map around a fictional world.

The first thing I did was explore the Reddit comment section. One commenter mentioned the Mapbox API, and u/vaznok mentioned using GeoJson data generated in Azgaar world generator. A great start to this journey. 

Azgaar World Generator

I couldn’t recommend this application enough in terms of worldbuilding potential. Azgaar World Generator made it easy to upload a picture from one of my latest worldbuilding posts (slightly modified for the import), and edit the landmasses to look a little better. The fractal land patterns aren’t ideal, but building a proper GeoJson dataset is practically impossible to make otherwise. And I did enjoy creating biomes and changing population sizes throughout the map.

Some things to note when building and exporting a world from Azgaar World Generator include:
  1. Don’t expect an easy transition to Mapbox. Most data is exported as just data. You will have to edit a map extensively afterwards.
  2. Not everything is important in the end. I edited populations, rivers, etc. I couldn’t import rivers at all and had to completely lose my work in that area. Meanwhile, cities and population does not seem to be easily transferable to Mapbox, either.
  3. Remember to click the OK button after painting anything. I had to repaint the biomes countless times because of my negligence.
  4. Keep it simple. In the end, the only things I really used were Biomes, Height, and Markers
Once you finish building your world, export the data as GeoJson files. One should be a cell file and the other should be a set of your markers. You can ignore everything else. With those files ready you can begin the next step,

Working in Mapbox

Azgaar is easy to understand. Starting in Mapbox is also easy to understand. Moving the data from one program to another is a little more challenging. Firstly, you must make an account in Mapbox and note the predatory payment scheme. Next, you need to create a new style. We will just be working in the Style editor for most of our time here.

Firstly, I go to the Layers tab. Here we can add and delete Layers for our project. I started by deleting the preset layers (mostly of the real world), to make room for my own layers. This can be accomplished in Add New Layer/Upload Data. Upload your GeoJson Cell File first.

Once your data uploads, select the GeoJson Cell File as your dataset for the new layer. Under Type, select Fill-Extrusion. This way we can include some topography. Then, on one of the top tabs, switch from “Select Data,” to “Style.”

Here is where some “coding” begins. Edit the Height first. By selecting Style across data range, you can select the Height data from your GeoJson file. Do this, and make sure that your minimum value is 0, and your maximum value is around 10,000-20,000 or so. You will have to repeat this in the Color menu.

​To color your cells, all you have to do is color by the data range of height. I like to start with 0 as ocean blue, 1 as beach, and then immediately ramp up from there. 200-500 would be a good middle value, 1000-2000 is great for forests or hills, even the base of a mountain. At 10,000 you can use brown(mountains), and at 20,000 white (snow caps). If you really want to get into it, you can color it by Biome, as well!
You may notice something that says, “Style with data conditions.” If you want to style by Biome, you can make your world more immersive. Just go through the various biomes and adjust the colors accordingly. I tried to keep colors mostly like the fallback colors that each biome starts with, until getting to more exciting biomes like glacier and desert. If you have even more exciting biomes, just go crazy. 

For example, with a volcanic biome, I was able to change 0 to a bright orange color. The main color was brown, and the mountains were a dark grey. I also included a new England style deciduous forest, with some random spots of orange and red to give the map more life.

But once you’re done with this, add a new layer with your GeoJson Marker file in order to include some titles throughout your map. If you are going to edit this further in HTML, avoid using icons or circles. Instead, select Type Symbol, and disable the symbol immediately. Symbols don’t allow these markers to render properly in HTML and adding them back in HTML is more doable. If you are just exporting the map, you’re done here.

If you are instead interested in coding the map with clickable icons, you will be going to the HTML step. 

HTML

Unfortunately, I am not an HTML coder by schooling, so you may have to use your own tutorials for this step. However, I found that Mapbox includes some neat documentation for the inclusion of custom markers, as well as for clickable markers. I used those two resources to create custom and clickable markers for my map. Meanwhile, if you swap in your own Style and access token, you should be good to follow any tutorial you wish. It’s straightforward from this point on. I recommend checking out flyto, and onclick. You can even change text color using the Paint effect. 

Furthermore, we had a lot of resources to pull from with our recent Reddit posts. By adding some image CSS to our code, I enhanced the map with some of these posts.  

In Summary

In the end, the map seems functional on both desktop and mobile. In fact, even though I have already developed my world using various in-universe drawings and a few maps, the maneuverable 3d world makes it much more immersive. The whole project took me around 14 hours of trial and error, but even then it was completely worth it. You can see the final result here. 
]]>
<![CDATA[[Game Design] Balance in the Age of Machine Learning]]>Thu, 16 Dec 2021 00:45:54 GMThttp://housefishballoon.com/blog/game-balance-in-the-age-of-machine-learningby Blake Propach

An Introduction to Balance


We’ve all played games that have felt like they had never been tested a single time before getting put on the shelf. Some of us have been lucky enough to fall in love with a game that felt like a strategic masterpiece, maybe simple, maybe complicated, but every part of it felt honed and complete. I personally take balancing very seriously. A truly competitive game is built on pillars that those playing the game expect to be solid. Not all players may be aware of the pillars. In fact, a game is best when no matter what level of scrutiny a player or group assesses it with, it should be just as competitive.

One, choices must matter. If the player is not inputting meaningful choices, they aren’t affecting the game enough to make it more than chance that they’re winning or losing.

Two, these choices should be reasonable. Reasonability for me comes in two steps. I should both understand the question, and the solutions that I have choice of. In an economy game, it should make sense the difference between constructing a resource building for later use, constructing a unit for immediate use, etc. I should have some idea of why I would build a unit before I make it.

And three is why I’m writing this. Choices must be equal. If I were playing some form of chess where I can add any piece to the board at any time, I’d want an equally good reason to choose a bishop or rook over a queen. When an obvious solution appears to a game, it becomes unbalanced.
It’s important to note that when a game is unbalanced, that doesn’t mean the game is inherently less competitive than other games. At the top level of any game, no matter how broken and unbalanced, the playing field is even. The problem with a lack of balance is the lack of choice that is left to the players. If the top ten players of Magic: The Gathering are playing the exact same deck that exploits a certain combo that is impossible to beat, the game is denying those players the choice to play something different, because the power level of all other decks is too far below this new standard.

Trading card games like Magic can constantly adjust and ban cards from their constantly evolving game. Most board game manufacturers do not have the luxury to balance their games after production, so to make a good, unbreakable game prior to print, they must test it extensively, with as many different types of people as possible. My first, second, and third iterations of my games are often broken by game testers on their very first playthrough, games I thought were polished masterpieces. To avoid this tedious process of crafting and recrafting my babies after my friends and family tore them apart, we turned to nonhuman methods.


Computer Randomizers

From our first game, Michael and I turned to the computer to solve some of our balancing problems. This was before either of us was confident enough with our projects to share them with anyone other than our close friends and family. It began small, with simple code to run basic randomizer simulations so that we could adjust frequencies thousands of times faster.

The first game we applied this to was a (still unreleased) board game with a randomized board. Unlike Settlers of Catan or similar economy-based board games that start with the same resources scattered in random ways, our game revolved on dice that had a chance to entirely remove certain resources from some starting boards entirely. Additionally, each die was unique, so each needed to be individually balanced against a hundred other unique dice. Each time we rolled the board, it was a different game, and I mean that the game itself was so different that you felt like you were playing a different game. The biggest problem about it (yes, there was an even bigger one than those mentioned) was that one of the win conditions of the game was based on a certain tile type that even had a very small chance never to appear on the board at all. More likely than not, the board randomization would favor one player’s spawn heavily over another’s for this reason.

It’s probably not hard to see why that game hasn’t made it to market yet. But stay with me for another paragraph. Michael created a board randomizer for us, and we had it run a few thousand iterations of the board. Next we defined what a ‘balanced’ board looked like, ‘player favored’ board looked like, and what an ‘unplayable’ board looked like (one where the win condition was not frequent enough to justify the game). We had the computer analyze the percentages of each outcome, and quickly flipped through some board states to look at ourselves which the computer decided were good and bad. In this way, we could very quickly balance and adjust hundreds of dice and set up hundreds of boards in the time that it would have taken us before to make a single physical board.

We now apply this computer randomizing aspect to the balancing process of each relevant game. Panic Buy! is a good example because it has four decks that contain the same cards in differing quantities. To keep with my balancing rules and avoid hypocrisy, I want the game to have meaningful choices. Each turn, players choose one deck to draw cards from that turn. To give the decks variety while keeping them balanced we recreated the decks with a randomizer so that we could quickly deal hundreds of hands and adjust quantities on the fly. We adjusted the quantities of Panic Buy! in their entireties about five times before ever testing the game in person with another person.


Machine Learning

We haven’t stopped there with our use of computer tools for balance. Michael has also tried his hand creating weak AI bots to ‘solve’ our games for us.

For Fashion Cents, we created a few bots with different goals. It is a deckbuilding game like Dominion, so we had to worry that certain strategies were not simply better than others. One bot buys as few cards as possible to win, one bot buys as many cards as they can each turn, and others had combinations of those two strategies. It should be noted that at this stage we didn’t implement game logic. It simply bought cards that we assigned expected values to, had it run a simulation until meeting our simplified win condition, and then told us how many turns it took to arrive at that victory.

For Two Old Men Fight on a Glacier, an abstract game I designed where players maneuver around each other in a magical battle of wits to toss the other player off the iceberg, we brought in the big guns. A friend of mine constructed the entire playable game online so that we could play with each other before we had a physical prototype, and we worked with him to build an intelligent bot that not only could play against humans, but consistently beat us. Like a very weak version of Stockfish (the most powerful chess computer in the world, at the time of writing), we played our bot against itself to try to answer the question: Is this game solved? Short answer, we don’t think so. But we wouldn’t know that without the use of computers. We simply don’t have the time or understanding to brute force and solve an abstract game without the help of our mechanical friends.

Implementing computing tools is just one way we’re trying to take our game balance to the next level. If you want to learn more about HFB’s online testing tools and strategies, I’ve also written about that.
]]>