I went through to the GGJ meetup near me, where this year we had tons more than we would have ever expected before! Due to the time constraints for starting with so many people (for the first time), it happened to be fine for allowing people to stick to the teams they expected to be in before coming to the venue.
We should encourage people to work with new people. That sentence feels like it is slightly incorrectly worded… However, it just happens to be what added a slight disaster for certain new people this year. “Hey, let’s talk about our ideas, I need to find a team…“
I tried several times. It would have been amazing to get a random team. My friends unfortunately also stuck to “we have a programmer, sorry.” Perfectly fine, however, it means I didn’t actually do the GGJ theme properly. When your point is to work with new people every year? Yes, I just couldn’t get that to occur.
The SokoBomber 2 Grind
Friday evening I started with more development for SokoBomber 2. An understandable project, I just chose to do something completely different. Friday happened to be starting Encryption…
This added the issue that we need to see what characters we can use:
static void Main(string[] args)
{
byte[] yes = new byte[256];
for (int i = 0; i < 256; i++)
{
yes[i] = (byte)i;
}
for (int i = 0; i < 256; i++)
{
System.Console.Write((char)yes[i]);
}
System.Console.ReadLine();
}
Sure, that is not optimal code, we could take a lot out. It just happens to be what was used to see what we can use for ourselves. We don’t have to worry, we then needed to start encryption.
After making the steps we needed for encryption we have bytes from 0 to 256. I had to start the encryption mapping for myself to understand that. It just happens to be something that brings adjustments to the rarity I need.
private RijndaelManaged _rijndaelManaged;
private ICryptoTransform _encryptor;
public SBGenerator()
{
// Create Rijandael instance
_rijndaelManaged = new RijndaelManaged();
_rijndaelManaged.Key = new Byte[32] {
37, 161, 152, 35, 68, 12,
126, 213, 16, 101, 97, 72,
10, 87, 187, 162, 233, 81,
38, 27, 48, 1, 231, 4,
8, 28, 128, 56, 74, 127,
1, 191
};
_rijndaelManaged.IV = new byte[16] {
92, 21, 83, 173, 211,
1, 99, 103, 127, 164,
29, 9, 63, 74, 200,
171
};
_encryptor = _rijndaelManaged.CreateEncryptor(_rijndaelManaged.Key, _rijndaelManaged.IV);
}
As you can see, after testing several methods I stuck to a certain method. Rijndael Managed happens to be too long to even say. When referring to any encryption, this is part of what we are discussing.
We start out by creating an instance of it for ourselves, we need to reference the encryption class. I’m sure you can understand, there is more to the Key and IV, we will only reference what they are for you in their respective links. This is the entirety of what is needed for us to encrypt.
With the reference of the encryption
The encryption is the grind for SokoBomber 2? This is slightly confusing… Getting the encryption to work for us was the “starting grind“. The only reason it was a grind was that it can be complex.
Using Encryption
This can confuse people, which is why the easiest thing is to share what sparked this idea.
Games like Binding of Isaac gave me the idea. Every game has a seed, with that we have the same rooms with the same enemies. This isn’t guessing how they do it, it is using it as inspiration.
This is most likely completely confusing, we don’t need to count the hatched chickens yet. I was inspired by one of my other go-to games as well. Minecraft allows you to start a new world with a random seed, however, you can create the random seed as a string.
I figured I wanted to allow the seed to be numbers or string with no changes. Sure, it is different though. Using the encryption I can guarantee that levels will be different for absolutely every seed.
This relies on the fact that using encryption we can
decrypt it. Sure, we won’t ever need to for the style that I’m looking for.
public string SeedGen(string _in)
{
string answer = "";
var msEncrypt = new MemoryStream();
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, _encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(_in);
}
}
var array = msEncrypt.ToArray();
for (int i = 0; i < array.Length; i++)
{
answer += ((char)array[i]).ToString();
}
return answer;
}
There we have it, we input a string and output a string. Through the conversion you can see we will get a different string every time.
For starting out, this is supposed to generate using the seed “1“. That way we can see what is happening. As you can see we have a few problems.
Èx¼£p\u0011¢\u0091öþÇ\u0001\u0012°zý
The pieces above are in bold for you. Unicode characters. This is where we couldn’t convert it to a string character we could use.
There are numeric values to these, and the easiest thing to do is swap out those characters for characters we can use. For “!“, you can see in the images above on the console, the HTML happens to be “33”. So when the character is below 33 we need to swap it. This can mathematically add a few problems.
We also need more in the range we create, that should be a problem we look at afterwards.
for (int i = 0; i < array.Length; i++)
{
var val = array[i];
if (val < 33)
{
val = (byte)((int)val * 7);
}
answer += ((char)val).ToString();
}
There we go, now we have usable characters for there:
Now to look at the range of the characters in the middle that have the same issue. It is from “127“, to “160“. We happen to just use a different method here. Mostly, I can’t really think of much…
if (val >= 127 && val <= 160)
{
val = (byte)(val + 33);
}
That is very minimal, however using both we will definitely continuously get the characters we need.
So, What Will This Mean?
This is where it is awesome, we have several sets of characters to use. Fixed on a mapping for the seeds.
We will be using these for ourselves, in an extremely simple way. I say “extremely simple” in an incorrect way, it isn’t. We just don’t need to worry about that.
This is a string we can manage for the level generation. Now, I can’t share more about how it is working out for us, only describe what it will do. This is not proper use of encryption either, it is literally to generate a string we can use for levels.
Considering the string above, see how we would process it:
- First character: level length, this one maps to “7” pieces
- First piece “x”, this is a corridor
- First helper “the quarter”, this says the corridor uses a small bomb door
- Second helper “pound”, this says we have a single “2 bomb” map
- Second, the piece starts at “the quarter” again, which happens to map to a diagonal bomb room, now that the pound is second it means we use large diagonal bombs, etc
- And so on…
You can, no doubt, tell I don’t completely know where I will go with that. I am slowly working that out for SokoBomber 2 for us. I would love thoughts on this as it is what I am using.
For the mapping my plan is to soon have it with a single item in each category. This will take some time for my to randomise for us (as in, there will be separate switch statements). The switch statement will have ~200 elements all going to a single option for the generation at the start. When I add a new item I can just move it over to halves, then thirds, quarters… I’m sure you can understand
The goal would be to have everything available possible in generation from the start. Play first, then we can add features constantly. Eventually, that would map to intense
This happened to be what came out of the GGJ weekend for me this year, and hopefully, I can join a team next year. I still jammed, I made sure I did something related to the home. My game dev projects have my heart, and the home is where the heart is. Well, so to speak.