Jon Ureña's Blog, page 74

October 19, 2020

Temporary freedom

My last contract at the office (I work in the biggest provincial hospital) started back in late January, and the outbreak of the totally natural Chinese virus caught me working there. I ended up being involved in setting up networks, computers, etc., for newly built zones to handle Corona patients (even while some patients wandered there), up to the last day of this contract, which was a couple of days ago. Now that my current contract has run out I am beginning to experience the first vacation days since January. Unfortunately, due to my health issues, in particular the neurological condition I was born with, the list of jobs I have access to in practice is severely constrained; this current "vacation" could last from a few days to until mid to late December when I expect them to call me again, and even with such unreliability, it's the most tolerable job I've ever had.

I've saved enough money that I don't have to worry in that respect. My biggest concern is what to do with the time. Back in the day, some years ago, I could hardly work a week in an office without feeling as if I was suffocating because my place was hunched over my notebook writing whatever story I had to wring out of myself. Now that I don't feel that psychological need (I retreat into daydreams daily, very elaborate ones, but they are more of the wish fulfillment variety than of the "hero's journey" that would fit a fictional story one could write), reading, watching a few series and browsing the internet, the stuff I could reliably do in my free time while I was working, isn't enough. I've already picked up the guitar again, which I had abandoned in mid july. It has produced blisters in two of my fingertips; it seems that a few months is enough for the previously hardened skin to soften that much.

I've also been looking for elaborate games to lose myself into, but I'm in one of those limbos that occasionally happen in this hobby: although "Crusader Kings 3" is fantastic, I'm waiting for modders to release an alternate history mod that starts in the sixth century, before the Iberian peninsula was invaded by muslims; as I play in my birth province, regaining the lost territory, as a catholic king no less, is a pain. "Total War: Warhammer 2" has had some recent updates that have invalidated significant mods, and it's in one of those unstable states in which you wouldn't want to play without certain mods, but finding the right combination that won't crash your game is very time consuming. I'm hoping that "Cyberpunk 2077" is any good, but it comes out in a few weeks. I'm hoping to buy a next generation VR headset, the HP Reverb G2 in particular (I won't buy the new Oculus, as I hate Facebook's increasingly communistic policies), but it won't begin shipping until early November. I like playing "Project Hospital", which is a realistic simulation of running one, but I'm waiting for a DLC that comes out later this month. Although I could always go to the board games waiting on my shelves, until you get into that groove, the whole process of setting them up and relearning how to play them is a chore.

This afternoon I'm hitting Donostia/San Sebastián, the capital of my province, to buy some guitar strings and just browse some stores at my leisure, which I hadn't found the strength or energies to do since January; while I see that regular people have enough energy to spend when they leave the office, to deal with their family, get together with friends, etc., due to my birth issues just being around people for so many hours a day already squeezes me dry, and every afternoon I had to fight just to stay awake, let alone spend my time doing useful stuff. Likely all this new free time is going to do me some good.

Not much reason to write these words except that I felt like it.
 •  0 comments  •  flag
Share on Twitter
Published on October 19, 2020 05:26 Tags: slice-of-life

September 5, 2020

Released images generation programs (neuroevolution)

I'm content enough with the three programs I was developing to officially release them, or at least as official as uploading them to the releases section of their github repository. The link to get the programs is here. They are compiled already, and they run in my office computer, so those programs probably run in most Windows systems. No idea if they run on Linux, but I guess you can clone the repository and compile it yourself.

I intended to make a video slideshow with many enlarged images generated with the programs, but turns out that YouTube has turned off that feature. So here are some far fewer images uploaded to a free image hosting site.


















 •  0 comments  •  flag
Share on Twitter
Published on September 05, 2020 03:01 Tags: neuroevolution, programming, rust

September 3, 2020

Moved on to neuroevolution

I stopped programming back in mid to late 2018. I was too busy with work, I grew tired of dealing with Python, and my main obsession flipped to something else, whatever I ended up doing back then. This time I found the excuse to properly learn Rust through implementing the extremely convoluted logic of one of GMT’s most complicated board games. Turned out that it was that, an excuse: when programming that system stopped being a challenge because I had learned every aspect of Rust it would make sense to apply for that model, I lost interest. Fortunately by then I had become proficient enough in the language that I could move on to my main programming interest: machine learning. I went back to neuroevolution, the art of evolving neural networks through genetic algorithms, something that isn’t remotely as complicated as it sounds. Back then I had implemented it in Python almost from scratch. My concern with Rust is that with the language being so new (although it already feels mature as of 2020) and data scientists focused on exploiting the old, broken beast that is Python, there would be little usable in regards to machine learning for Rust. And I was right to a certain extent, because what seems to be usable uses Python and C++ bindings, or tensors. I don’t understand tensors, they don’t sound good to me in general. So I cobbled together what turned out to be a quite decent implementation of neuroevolution from zero. As usual, the code is available in GitHub: link.

“Crusader Kings 3”, what seems to me the best game since “The Witcher 3”, lingers in my SSD, as I can’t stop thinking about developing more stuff for this neuroevolution shit. I’ve managed to develop a small program to evolve images.



It isn’t much so far, but it works: the main training program will either spit out a generation of images from zero, or load a previous generation (hopefully rated on their individual merits) and produce the next one. Initially I had to open each json file and write the fitness score manually, but it annoyed me enough that I developed a little program to score them through passing the genome identifier and the score as command line parameters. As soon as I develop a small third program to force manually selected genomes to produce their corresponding image to user defined dimensions, I’ll release them on the GitHub page (which, again, is here).

Neuroevolution works like this: you start by needing the computer to decide on some stuff, anything at all. Might be as small as choosing heads or tails, or deciding on where to invest in the stock market. You always have values gathered from some environment, and what values you decide to pass to the computer is up to you. You need to analyze the environment properly, because you might miss vital aspects that the computer would reasonably need to consider to make an appropriate decision. For my generating images model, I settled on very few input parameters. All we know from the environment is the dimensions of the image the computer has to produce, and the aspects of those dimensions are in this case how far the current pixel is from the extremes of the dimensions (top left, top, top right, left, center, right, bottom left, bottom, bottom right). When the computer is fed those calculated values, for each pixel of the image the computer is queried on what RGBA value to put there. That means that for a 256 x 256 image, the computer needs to be queried 65536 times. Some algorithm should rate the proficiency of that final result, and in this case the algorithm is the brain of the human user. Then, an evolutionary algorithm based on genetic programming crosses over the involved genomes, potentially mutates some aspects of them, and then produces a new population that in the next generation will be queried to produce another set of images.

At the core of this process are, of course, neural networks, the almost magical black boxes to which you pass some values which get altered in the neural network’s black innards, only to get spat out through the other side. The internal composition of the neural network, unless you evolve it through an algorithm like NEAT (which I chose not to get into), is decided by the user. It could have as few as a layer and as few neurons as the outputs the network needs to produce (four in this case, red, green, blue and alpha for each pixel). Potentially it can have hundreds of layers and millions of neurons. At the core of the neural network are neurons: the nodes that receive values either coming from outside of the neural network or from the previous layer. The nodes then apply a magical mathematic thing called an activation function, that transmogrifies the input value to some other. The following image represents some activation functions.



Each node has a single activation function (there might be variations on this I’m not aware of), and each of them produces different visible results on the decision. Whether or not they help will depend on how their decision is rated, and whether they get selected out through evolution.

That’s as much of an explanation as I care to give on the subject. In any case, implementing a neuroevolutionary algorithm almost from scratch on Rust took some shit: I had to get deep into generics and closures, which I had feared dealing with through my previous project. To destroy my fears and out of general obsessive-compulsiveness, I followed the Jurassic Park principle: I was so focused in whether or not I could that I didn’t stop to think if I should. Generics help you use potentially infinite variations of each part involved in a process. In this case I didn’t use any variation: you use a single type of population, genome, neural network, layer and node, and yet I made it so I can expand the system at any point of the future. Any cloner of the repository can do so as well (or should be able to anyway). The cost of that is that the client has to write code like this in main:



Which in turn looks something like this in the corresponding structures (this is all the code for training any population, without the intentions of the client code):



The following are the declarations of the types and such for the controller that deals with training a population:


Pictured: the shocking need to learn algebra.

As I was writing all the generic functions, I wondered where the border between concretion and abstraction was. Generics have no runtime performance penalties in Rust: the compiler turns all generics into concrete implementations during compilation. I struggled to understand how to deal with the inevitable points where you just had to create a concrete class (neurons, populations, neural networks), and there’s no way to create something concrete from generics. The solution ended up being obvious, but it required a different mindset: you need to inject the production of concrete structures into the generic frame. Still, how on Earth would you inject something that produces concretion, when the specific details of whatever you need to construct isn’t known most of the time until the structures need to be created?

The solution is closures. You just pass functions as parameters to the generic core. It was obvious, but it’s such a high level, duck-typing-mindset solution used in languages like Python or Javascript that they seemed impossible to implement in such a hardcore language like Rust. But it’s tremendously easy: the type of a function/closure parameter is something like Fn(u32) -> u32, meaning it receives an unsigned integer and spits out an unsigned integer, and as the value of that parameter you could pass something like |value| { value } (or even without the brackets). That’s it. Value gets passed as a parameter whenever the generic code uses the function, and the client doesn’t need to worry about anything else.

That’s about as much as I can think to write right now. I’ll soon release the programs to evolve images, and I’ll likely play “Crusader Kings 3” for a few days.
 •  0 comments  •  flag
Share on Twitter
Published on September 03, 2020 05:47 Tags: code, machine-learning, neuroevolution, programming, rust

August 28, 2020

Mounting stress

I don’t know how other people (or their bodies) deal with stress, but in my case it’s like dehydration: by the time I’m already clearly thirsty, I’ve been needing water for a long time. I’ve been going to the office without a break since this year started, and the Chinese attempt to start World War 3 hit while I happen to work at a hospital. I haven’t taken a vacation while working plenty of saturdays, with more close on the horizon; in a couple of weeks I’ll work friday afternoon, get home at eleven at night only to wake up at six to go back to the office. I don’t deal with stress outwardly, as I’m the usual reserved, serious-minded guy who doesn’t open up and doesn’t want to share his break time with others. However, as I’ve been obsessed with programming for the last month, I’m not letting my brain rest remotely enough. While I was obsessed with board games, playing the games was leisure time even though they required plenty of thought, but programming requires serious thought and commitment. Yesterday, after seven hours of moving through the hospital complex, inspecting network closets, dealing with chatty nurses who seem to believe that computers work by magic (but Lord, the butts on some of these girls, so I'm not complaining), I had to find out why a phone that goes through the network was working intermittently. At thirty minutes to the end of the workday, my brain decided to completely shut off. I couldn’t tell the relations between the stuff I had to consider to solve the problem, and although I had slept enough for someone who at times has gone to work without being able to sleep for a single hour and still performs, I can barely remember anything about the bus and train ride back home. I kept dozing off, my guts and brain hurt. After I ate I laid down, put some ASMR on the earbuds and as I listened to some attractive YouTuber pretending to care about me in particular and making pleasurable sounds I fell asleep for a while. The signs for the temporary implosion had been there for a couple of weeks if I were able to identify them along the way: I had strange muscle pains in my legs and back, quick and sharp pains in my brain and stuff like that, but I inhabit a body that feels like shit most of the time (chronic ailments and issues like high-functioning autism that some government goons recognized as a significant disability level), so it’s hard to measure if I’m feeling worse than usual any particular day. I took the rest of the afternoon off, although today I went back to what passes for normal in my case.

It’s friday, got my paycheck (slightly inflated for us in the sort of medical field due to the Corona shit; thank you communists), the workday is coming to an end, and for the rest of the day I’ll go back to programming while some YouTube stuff goes on in the background. Good times. “Crusader Kings 3”, seemingly the best strategy game in a long time, and one of the most moddable, will come out in a few days. Things could be much worse, I guess. Certainly have been.

Also this video for no particular reason.
 •  0 comments  •  flag
Share on Twitter
Published on August 28, 2020 04:32 Tags: daily-life, programming, work

August 24, 2020

Nuking the codebase

Although it doesn’t feel like it, I’ve been working on the software adaptation of GMT’s “Fire in the Lake” board game for 21 days. I wanted to do so mainly to finally learn properly the programming language I’ve ever been interested in the most: Rust, a blazing fast, memory safe language that for me clearly will replace C++ for anything that demands speed, such as simulation, games, developing artificial intelligences, etc. In a comparison I’ve read quite a few times, in a taxing task related to AI, C++ managed to finish it in around 2.5 seconds. Rust did it in around 3.5. Python, the language popular amongst data scientists and people who in general aren’t mainly programmers, did it in around 730 seconds. Because I liked many of the upgrades they had done to Python in these last ten years, a few years ago I chose Python to develop some programs on neuroevolution, as well as three dimensional pathfinding. With both of them Python’s limitations were obvious: producing each generation for the neuroevolutionary experiments took what felt like way too long for what they were, and the multithreaded code for the three dimensional pathfinding often locked the main thread by just passing data to other threads in order for them to run the pathfinding algorithm. It could barely handle ten agents at once.

Rust forces you to handle programming constructs that in some cases are even absent in other languages: for example, you need to establish who owns each variable, and in order to prevent some of the hardest to solve bugs in other languages, only a single “structure” at a time can be loaned a mutable variable. That limitation pushes you towards functional programming: basing as much of the program as possible in “closures” that don’t produce side effects: immutable stuff goes in, immutable stuff goes out, and inside you don’t write to any file, you don’t manipulate any database. Obviously you cannot program realistic software like that in its entirety, as at some point you need to track permanent changes to variables at least in memory. However, basing your program on a functional architecture seems like the best possible choice in a language that can handle the performance overhead (because some stuff might need to be copied or cloned).

A couple of weeks ago I had hit a dead end programming my software: external, non-deterministic data (such as player input) entered through a mouth, so to speak, and the changes were done in the depths of the program. That meant that many mutable references were diving deeper and deeper into the code, and at some point the necessities of the code demanded I held on to some of them, which I couldn’t do because of the limitations to borrowing mutable references. In addition, the points of mutability to the data were scattered in the depths, which meant that I couldn’t test nor predict how they affected each other. It was obvious that I needed to refactor most of the program to a functional architecture, but in the end it was easier to learn the lesson and start from scratch. Now the program has gatekeepers (called controllers in a functional architecture) that hold mutable references, and that do as little of the thinking as possible. The decisions are made by structures further into the program, but they don’t get ideally any mutable reference: they just return back to the controllers whatever they decided. That means that the controllers receive a batch of mutations that they, or other controllers, can process sequentially in the outskirts of the program.



Deciding what will change and how, and when and how those changes are implemented, is completely separated in a functional architecture. You end up with abstractions such as ForcesMutation that holds a troop having been eliminated from a space, for example, but the board doesn’t change until those changes are persisted.

Beyond that, despite being a command line program, I made it look reasonably nice as per the following image:



I’m deep into implementing one of the factions’ bots. There is a suffocating amount of different stuff they can do; just the card events require around 120 individual functions to process their effects (and those are the base functions for the events, not counting all the functions involved in implementing each quantum of their effects). But now that I’ve gained fluidity with the language, it’s just a matter of putting many hours into it.

As usual, the code is available in its github page.
 •  0 comments  •  flag
Share on Twitter
Published on August 24, 2020 05:42 Tags: board-games, programming, rust

August 12, 2020

Refactoring my “Fire in the Lake” software

Although I had been refactoring bunches of code present in some methods into other methods, and created a couple additional structs when the original structs were handling concerns beyond what they were originally created for, at this point of the project some structs were accumulating massive amounts of methods. Refactoring them would require identifying the general purposes of the methods involved, classifying them and then isolating them from the original code so that area of the codebase wouldn’t be so brittle. I focused first in the area that handles executing the player or bot commands. As a general overview, each of the four players will push through the mouth of the system some words that will relate to their intentions, what they want to do in this turn. If they push through words like “event”, “operation”, “pass”, the system needs to understand that the player wants to play the active card for the event, or wants to perform an operation, or intends to pass. However, we also have words like “6”, “an loc”, “saigon”, “pacify”, “rally”. The system should reliably handle what kind of operation the player wants to play, in what space or spaces of the board, or stuff like how many troops it wants to deploy. In my initial design I simply passed an array of Strings through the command execution system, and those methods had the responsibility to figure out the intention of the player from whatever subset of words the method received. That was a clear violation of the separation of concerns, given that those methods should simply have to focus on executing an operation, a special activity, or delegating declaring that player as having passed, for example.


Before dealing with that major issue, I needed to take some scissors to the execute commands function. The mess of switches and ifs ended up being distributed into isolated functions that handled executing the events, others that executed each kind of operation, others that executed each kind of special activity, another that handled passing, and the biggest group, one that handled atomic executions such as deploying some units somewhere, manipulating the resources of a faction, setting a space to a level of support, improving the trail that the NVA faction uses, etc. That refactorization into a couple dozen files passed the integration tests without much trouble; thankfully, the three almost end-to-end tests that I wrote and that simulated three entire turns of the game are very resistant to refactorization.


There was another section of the code that handled the entirety of the flow of the game: how to deal with the couple of current cards, how to determine what factions were eligible or ineligible, how to slot those factions so that other parts of the system would know that the choices of those factions were already occupied, etc. It ended up being a tremendous chunk of code. I found three major different concerns for the methods involved: some methods just handled the general game flow: setting the active card, informing whether the turn had ended, moving to the next eligible faction according to the order shown in the active card, taking in the general player choices, being able to answer to whoever asked whether the turn had ended or not, etc. Another concern involved handling all the different possibilities for the factions: whether some faction is eligible, whether all are eligible, whether some faction has passed, determining the eligibility of a faction depending on some previous one’s actions, etc. The final concern was related with slotting the factions and moving them around into “holes” that can only hold either one of them at a time or four (maximum number of players). Whether a player has chosen, for example, to perform an operation without a special activity, is very important in this game system, because that means that the following player can only do a limited operation, while if the first player had chosen to play the card’s event, the second player would have been able to do a full operation plus a special activity.


The most pressing concern regarding the following features I had to implement had to do with the fact that I was passing an array of words from the “mouth” of the system to the lowest levels that handled command execution (in some cases to the very lowest level of executing atomic commands). It reeked of primitive envy; what the system should truly know is whether the player intended to perform one of the main choices (passing, event, operation), what operation if the player went that route (ex. rally, train, sweep), whether the player chose to do the additional action allowed for some of the main operations (such as improving the trail), or if the player chose a special activity, which one. We also have the fact that the player might have written the names of spaces (can be cities, provinces or lines of communication), and the program has to figure out if those locations are related to the event, the operation or the special activity. So I refactored out the entirety of that system and created an interpreter that chews the initial commands and just registers the player intentions. It can be asked “does the player want to activate the event?”, which returns a boolean response, and it can be asked to provide the locations associated with the event, for example. Far, far cleaner than the original, system, and not particularly hard to write. It suffers from a case of “excess of switches/ifs”, but it’s not pressing to figure out how to refactor that out. It reads each word as it comes, and depending on what intentions had been “detected”, it will convert to internal enums stuff like the names of places. If it receives the name of a space, the program determines whether, for example, the name actually refers to a space, and in that case if the player had previously sent the word to perform a operation, and in that case if it also had sent the word to perform a special activity. In that case the following spaces would be sent to a list of spaces associated with the special activity, but they would get associated to the operation or the event in other cases.


Again, thanks to the integration tests, the first time I got the major changes to compile, they immediately passed all the tests, so I knew that the previously codified functionality remained intact. That’s the advantage of test driven design: you can dismantle main areas of the code, improve it substantially, and remain confident that everything keeps working as it should. You wouldn’t dare to risk major changes otherwise.

 •  0 comments  •  flag
Share on Twitter
Published on August 12, 2020 02:29

August 10, 2020

Rusty days

As I mentioned in the previous post, the addiction to board games I have been struggling with during these last months had collided with my years long interest, and sometimes obsession, with programming. That was due to me having found mechanically complicated and generally engrossing strategy board games, and that some users in the BGG forums had created software to run those board games as well as their opponents. Those companion apps just tell you which pieces of the opponent to move, but otherwise let the tactile experience of playing those board games intact, with the difference that now you just have to focus on your own actions. That's very important in games such as those that might take five minutes to plan out your turn, and you don't want the experience to be bogged down by following the simulated opponent's logic. I have more than enough trying to follow my own logic.

The COIN series of games from publisher GMT are maybe the most mechanically complicated and involved board games in the market. Famously designed, originally at least, by an ex-CIA analyst, they feature, usually, four asymmetric factions trying to get ahead in a web of complicated alliances and enmities set during a historical quagmire. For example in their most simple game, "Cuba Libre", that simulates the communist revolution and takeover in Cuba, has you playing as either the government trying to resist the communist horde, or the communists led by Castro, or a student group trying to oppose both the government and the communists, or the American mafia trying to stay in favor of whoever could win, so they can remain in business. Each has its own victory conditions, and at times you might favor a faction over the remainder for purely tactical reasons, just to betray them later. Each turn you draw a card from the "event" deck, which acts as a propagandistic maneuver that can play in your favor if you push for it, but whether to exploit that historical moment or pass (because you can't play the following card, which you can always see, if you play the current one) is where a significant amount of its strategy lies.


Pictured: some of "Fire in the Lake"'s cards.

In addition you can also do many different actions for each faction, such as rallying support, marching through the map, attacking some positions, going underground, recruiting, etc. As I play board games almost exclusively by myself (I don't like being around people, to put it mildly), I would have to command one of those factions and then follow the very complicated flowcharts of each of those simulated opponents in order for them to act. These games are marvelously designed and tremendously engrossing, but having to check each condition of the flowchart and then execute their chosen actions feels too much like work, and takes you out of the fun and involvement of just dealing with your own problems and opportunities. That has a solution, albeit a complicated, time-consuming one: just program your own command line software that can run their logic.

Curt Sellmer did wonders with his software adaptation of Labyrinth (with both its expansions) as well as Colonial Twilight (that simulates the Algerian revolt against the French). In my case, I've never been as interested by a programming language as I've been with Rust since I found out about it; Rust is a blazing fast, memory safe and reliable programming language the likes of which, it seems, had never existed. Amongst programmers it was known that if you wanted the kind of speed that you really need for programming complicated simulations or artificial intelligence stuff (including games), you needed to learn C++, an old and convoluted dinosaur that despite its closeness to machine language, it doesn't save you from inadvertently creating memory holes that will end up popping up as almost unsolvable bugs. Microsoft mentioned how they were moving significant parts of their codebase to Rust, because 70% of the software patches they send out have to do with memory leaks or issues with memory management in general. Rust stops all that; you don't have to allocate the memory yourself, but there's no need, because you do need to establish ownership and lifetimes for all those variables and structures for which the compiler cannot find the obvious declaration (it can deduce most lifetimes, but those it can't more often than not indicate a design problem).

This last few weeks I've been programming like a madman to translate GMT's "Fire in the Lake", about the Vietnam war, into a Rust program. The code is openly available at its GitHub page. I've already cleared most hurdles related to how you need to change your programming mindset regarding Rust's safety model. Some of my habits were related to programming in a garbage collecting language, and they are more often than not impracticable in Rust's environment. For example:

-The biggest hole I fell in had to do, of all things, with a structure that held the parameters, many, that had to be sent to the struct that handles and delegates the decision making of all the factions. It had to be sent the number of the card in play, the faction that had to decide, the full map, all the tracked variables (such as resources, victory markers, etc.), the available forces of all the factions, etc. In any other program you would gather all those parameters into its own class, something like DecideParameters (for the "decide" function), but Rust has a problem with that: you can only ever hold on to a particular mutable reference once. To pass it to some other structure, the structure that held on to that reference has to drop it somehow. The parameter class required plenty of mutable references in its constructor, and it would be doling them out to whoever asked for them. Even though you could program that safely by just making the "decide" function take those references and work with them, you can't really prove that those references held and distributed by the parameter gathering structure wouldn't end up holding a reference to something that had passed away. You can't prove it either in a garbage collected language. The fact that we were doing this is an example of the recklessness that other languages allow; Rust isn't being fastidious by disallowing you to do that: it's just making sure your program can't create those bugs. That means, however, that you are more likely to move on gradually towards a functional style of programming: create structs just when there's some field that really needs to be tracked, and work with functions otherwise. Rust's memory model has no issue with you passing mutable references through functions, as long as they don't stay there somehow, and they can't stay in functions. This limitation does mean, though, that you will end up with parameter lists of potentially 7-10 entries. For example, the only point of entry to the decision making process, the function "decide", looks like this:

fn decide(&self, active_card: u8, current_eligible: Factions, map: &Map, track: &Track, _available_forces: &AvailableForces) -> Decision

-My biggest previous issue with Rust when I looked into it back in 2018 was that you couldn't create collections or in general "group" different structures, even if they implemented the same trait (Rust's more complicated version of other language's interfaces). It's one of the main principles of code quality that you need to program to interfaces instead of to implementations to avoid code coupling, and particularly to isolate volatile and non-deterministic subsystems. That Rust would complain if you were to create a collection of spaces, for example, in which the space in question could be a interface to an implementation of a province, of a city or of a line of communication (as is the case in "Fire in the Lake"), was a tremendous problem without a reliable solution; there's an unsafe way that Rust sort of allows, by creating a dynamic link, but that is 10x slower, handling those references is messy and annoying, and it defeats the purpose of programming in Rust to begin with. However, the community came to the rescue, and there's a fantastic library called enum_dispatch that uses the richer Rust enums to allow a sort of "type identification and grouping" as well as keeping the implemented traits working. It looks like this:

extern crate enum_dispatch;
use self::enum_dispatch::enum_dispatch;

#[enum_dispatch]
pub trait Space {
(...)
}

#[enum_dispatch(Space)]
#[derive(Debug)]
pub enum Spaces {
City,
Province,
LineOfCommunication,
}


When instantiating the structs you just have to call the "into" method in order to "transform" them into the enum-like form, but that's all. Otherwise they work as you would expect in any other language.

-In general I've had trouble avoiding some redundancy or close repetition that in other languages you would solve through duck typing or generics. Generics in Rust is a prickly area that I won't dare touch until I'm comfortable enough with the integration tests to make sure there are no regressions.

-Amongst the biggest priorities when attempting to codify a system is figuring out how to isolate the volatile, non-deterministic elements. This game has random input from the dice throws, but much worse is that you have players that are bots and are controlled by complicated flowcharts, but those factions can also be controlled by a human being. At first I considered creating two "paths" through the main system depending on whether a player was a human entering commands with the keyboard or it was a bot, but I found a more elegant solution: to the system, all players behave like humans. The bot's decisions and actions are translated to typed-like commands such as "event", "rally", "operation", or the numerous names of spaces, or the amount of forces it wants to move around. The system that processes those commands and executes them just carries with it a list of commands in an order it can understand, and it doesn't know, nor has any need to know, whether those commands were produced by a human being or a robot. So far I have proved three turns of the playbook that comes with the game, and that's a big deal given how complicated these games are and how many different things the factions can do. For example, this is the code that tests the second turn. I just input the player dummies for the test in the same slots as I would input a regular bot or a human being, and the system doesn't care. Awkwardly, though, I had to store the definitions of the test doubles in the main crate, because num_dispatch doesn't allow the implementations of a trait to be in an extern crate. It just bothers me because of general code quality reasons.

-I'm reading through Vladimir Khorikov's "Unit Testing: Principles, Practices, and Patterns", which seems to be a modern bible on test driven design. I've always been a fanatic of testing first, but I realized as well that while you do need to create a test first, you shouldn't be creating dumb stuff such as whether you can instantiate a struct or access its members: just incorporate whatever struct you create as part of an integration test that proves a system necessity. Through proving the first three turns of the plabook I created many structures and functions, and their behaviors are locked in place, for the most part, through participating in those tests.

I have those familiar itches that make me want to open Visual Studio Code and keep coding as soon as I get home. These obsessions are my particular version of a venereal disease. I hope they last until this small project ends, which shouldn't be that far away.

EDIT: All this talk of testing a program reminds me of one of the biggest legends of gaming, and also the most complicated game ever created, "Dwarf Fortress", that has been going strong for fourteen years and that is gearing up for a Steam release with an updated interface and graphics. Created by a mathematician, he learned programming through writing the game in its initial states, and he readily admitted that his code was probably disastrously structured. I always wished to take a peek at that mountain of code, although it also terrifies me. That game kept piling up features without being able to solve huge bugs that it had introduced years ago, and likely because they cannot be solved at this stage. I doubt their codebase includes any test, so the only safeguard against regressions is whether or not the code compiles when you make a change. That makes me shudder. Still, I wish they would use the Steam money, a significant part of it at least, to just get a bunch of systems analists and coders to rebuild the code from scratch. It would be a thing of beauty.
 •  0 comments  •  flag
Share on Twitter
Published on August 10, 2020 02:22 Tags: board-games, code-quality, programming, rust

August 5, 2020

About board games and programming

Due to my particular neurological curse I’ve been born with, my life has been succession of obsessions. At whatever point of time, I find joy in little else than constantly thinking about whatever I’m obsessed with and whatever projects can come out of it: if it’s programming, I program something. If it’s boardgaming, I try to design a game. If it’s narrative theory, I write novels (got around four of those from 2012 onwards, and of the four I finished I “published” two). If it’s a person, stalking-like stuff happens. In any case, I’ve fallen hard into boardgaming again. As a result I tend to peruse BGG more these days (link to my BGG profile) and I fill my very limited free time immersed in the mechanics-rich world of board games. I used to play videogames regularly, mainly strategy games made by Paradox, but also the rare series like UFO and some others I can’t even recall right now. I also enjoyed cinematic stuff like Red Dead, GTA and others. However, I agree with the old quote that a game should be a series of interesting decisions, and these days most decisions in games seem to involve stuff like whether to walk in a cardinal direction while enjoying the pretty views. And that was fine until this current generation of games; we have TLOU 2, a quite overt vehicle for marxist subversion, and even Paradox, for the upcoming Crusader Kings that comes out this September, have hired a person that seems to be almost exclusively in charge of adding alternative female supremacy as well as homosexual and bisexual majorities in a MEDIEVAL SIMULATION GAME. Paradox are a Swedish company, so such stuff is to be expected as their society collapses. In any case, I’ve mostly had enough. With board games I’ve rediscovered the joy of sweating to decide whether to take this decision or another, while I consider the pieces and markers distributed upon the board, and I hold cards so full of possibilities that merely touching them makes my heart race.


Pictured: ending the spread of jihadism at least in board game form

I’ve discovered many different sub-genres of board games as well as variations inside of them. For non-insane levels of involvement I prefer deckbuilders, but my favorites ended up being very mechanically complicated games that also simulate sort of human-like opponents. GMT does it best, and amongst them the COIN series are probably the best modern iteration. When I got “Labyrinth”, above pictured, I found out that I disliked a lot to follow the logic of simulated opponents in order to move their pieces, because I already have to deal with enough analysis paralysis during my turn that each game I play always tends to take around two times or more what is indicated on their boxes. However, turns out that in modern board gaming programming has solved that issue in many cases: you get the tactile immersion of handling a board, its pieces and the cards, but a more or less complex program simulates the opponent. Although similar stuff had been done for chess, many modern board games are very different beasts. I had some of my best sessions of gaming in any medium thanks to the assistance of those unsung heroes that programmed the systems and the artificial opponents just because they could and wanted to.

That ended up sparking an old obsession of mine, programming, which is actually my trade. I currently work as a technician doing stuff unrelated to programming, and all the programming projects I had been interested in were related to artificial intelligence, 3D map representations and exciting stuff like that. Through those projects (link to a video of some stuff I programmed in Python) I realized that there wasn’t a programming language I knew and could care about that performed as I needed: it had to be fast, secure and reliable. Python is a mess, burdened with a core that forces you to do black magic to allow multithreading, and even in those times it rarely works as you would expect. Java has improved a lot in these last years, but it’s still heavy and generally annoying. The kind of performance I needed demanded something like C++, but I have no wish to learn such an old, base level language that drags so many archaisms and whose tools don’t seem to have adapted to the current world. However, Rust seems to have changed all that. Rust popped up as a language that incorporated memory and thread safety into its base idioms: you need to establish the ownership and lifetimes of your variables. You can’t do crazy shit like duck typing everything, sending whatever crap you want to a function and just through the magic of on-the-fly garbage collecting have the receptor treat the parameter as whatever. So stuff like having a collection full of random garbage and then recognizing whatever you want through its properties is out of the picture. In exchange you get a mostly high level language that’s almost as fast as C++ and even thread safe. Back when I read a few books on Rust two years ago, some vital stuff hadn’t been implemented into the codebase yet, but now it looks like a mostly mature language with all the modern commodities like easy packaging, compilating and distributing, as well as the best error reporting I’ve ever seen in a programming language. What I wanted to do with the language two years ago was still shit like neuroevolutionary algorithms, but the language is far too complicated and peculiar to start with stuff like that. Still, I couldn’t care about any simpler program I might create.

However, now I can combine two obsessions by programming one of those hyper-complicated COIN games in Rust. Pendragon seems to be the most mechanically hard, but doesn’t seem as interesting to me as Fire in the Lake, a game about the Vietnam war in which four asymmetric factions deal with that whole mess. A mere two days ago, I think, I started the GitHub page for it: link to the project page. Now I’m getting the usual tingles to devour everything I can on Rust and programming techniques, immerse myself in codifying a system and through it get some meaning out of this horrible world. Unfortunately at this hour I’m stuck at work, but I’ve been gifted with the kind of shift that allows me to write these stupid words and use at least half of the remaining time researching the needed shit. Pretty exciting autistic times ahead for me, for a few months at least.
 •  0 comments  •  flag
Share on Twitter
Published on August 05, 2020 07:38 Tags: board-games, programming, rust

July 5, 2020

About my diseased brain and other disgraces

Last week I was working on the afternoon shift and I spent most of friday moving and setting up stuff in a series of operating rooms. I had to patch the network point for a printer, only to find out that despite the printer detecting that it was patched to the network, and myself seeing in the rack that the corresponding network jack had traffic, I couldn't get the damn thing to respond. I realized that I wouldn't manage to solve it that day, which I dread because I know the consequences: it would unsettle me all weekend. It's not that I care that the people that I'm doing this work for wouldn't be able to use the stuff, but that I still don't know the solution, and the anxiety could go as far as stealing sleep from me. I would spend hours turning in bed without being able to shut my brain off, and I know what nights like those have in store for me.

It's five in the morning on a monday and I was supposed to wake up at six to drink a cup of coffee, take a piss, shit, shower, dress myself, walk across town, take a train, take a bus and walk to my office. I haven't slept a single hour. Whenever I go to bed I need to make sure that I'm so tired that I will fall asleep soon, because otherwise my brain will torture me like it has tonight: it's an endless parade of everything that has gone wrong in my life, from my earliest childhood to a few days ago, from simple embarrassments to failures and loses. It kept sending me images and sequences of intimate relationships I wish I never had, of encounters and falling-outs with people I wish I never met.

A mere half an hour ago it burned me with an image of a cat of mine as she looked up to me from my doorway, wanting to sit on my lap and for me to pay attention to her. In the late afternoon of that memory I was too tired, so I picked her up and left her on the living room. The next day she was broken in half by a pitbull. Another cat was wasting away from a cancer that reduced him to almost nothing in less than a month. I was exhausted from work, so I didn't go see him one day, and I never saw him again. I doubt other people's brains work the way mine does; I remember so few happy or positive moments that it feels as if I never had them. The longer I live, the bigger the mountain of painful memories. I know I had far more positive moments with those loving cats than negative, and yet since they died I can only feel grief and regret at the thought of them, so I need to push their memories out of my head just to keep going. I usually can manage to do that during the day; after all, the pointless, uninteresting crap that life and work throws at you tends to drag you out of your thoughts. But whenever I endure a night like this one, I have to face stuff about myself that I'd rather not know, mainly that I should never have been attached to anyone, from people to animals, because I barely have the energy to push through whatever garbage life throws my way in addition to keeping myself from falling apart.

These days I feel there's something fundamentally wrong with keeping pets, raising living beings that almost with certainty will die before you do. But in my case it goes beyond that. I never got along with my family and I remember always wanting to stay away from them. My parents pushed me into my older brother's room so they could use my bedroom for a new child. That ended up being a girl, who for the first ten or twelve years looked up to me. I recall her telling my mother when she was in preschool that she used to wait in front of the fence that separated her school from the one I attended so I would go talk to her. I never did. I never had any interest in sharing my daily life with other human beings. I was always occupied making up stories, reading, fantasizing. I guess that the person I have to consider my sister needed that contact, and she certainly wasn't getting it from home: my mother is a loon, and for most intents and purposes we never had a father. I don't recall much of us growing up except that she used to play plenty of games by herself and read some dumb series about witches. One day she showed me something she had written, but I didn't say anything back. When she was eleven or twelve she got electrocuted bad by a toy from the seventies, and although I might be linking unrelated stuff here, from then on I just remember her being a complete nightmare. For as long as I had to live under the same roof, she started screaming matches every single day, to the extent that the neighbors complained many times. She stole to fund her drug habits, dated a dealer in his twenties, and in general made me organize my day to day so I never had to spend time around her. Since then I have barely looked at her face twice, and never spoken directly to her. Years later my brother decided to have a child, and when they intended to involve me as the uncle, I completely refused any responsibility, even the slightest emotional one. I can't stand children, and I stand even less those parents that because things aren't going right in their relationship they believe the next step is to reproduce. I have kept as little contact as possible with them since, and they clearly resent me for it.

Since I was a child I minded my own business, but teachers pushed me towards other kids or even asked them straight to involve me in their activities outside of school. Many of those people, until I stopped hanging out with "friends" when I was around eighteen years old, grew attached to me, only to end up realizing I didn't care for them. Most of them went straight to cause trouble for me. One of them, a malignant narcissist that was heading straight to the higher positions of the local socialist party, attempted to destroy every aspect of my life until he died in a car crash when he was around 24-25 years old. At the jobs I've had the pattern has repeated itself to a certain extent: coworkers intend to get close, involve me in their personal lives, try to make me ask about aspects of themselves that they care about, but I keep everybody at arms length. If I let them in, I know how it ends, and what I will have to endure for the rest of my life for having allowed myself such weakness. I've had coworkers get the hint that I don't want to interact with them and act offended as if they were owed my energy, I've lost jobs because some supervisor said that I didn't work well in teams. During the years when I was trying to make it as a writer, I realized that I didn't want any part of the grind of having to convince people and deal with other writers whose brains didn't work like mine. I've met around twenty autistic people in person, and although I can tell the similarities, that hasn't made me want to get involved with them. During my free hours in which I'm not forced to any interaction I don't want, I focus on solitary stuff; I never cared about any other, as much as I've forced myself to in the past. I know my brain all too well to expect anything to change.

There's little point to any of these words. I was writhing in bed and I thought I should write about it. In twenty minutes I'll have to get up from this chair and start another day when I never wanted to exist in the first place. I wish the entire world would go away so I could get some peace.
 •  5 comments  •  flag
Share on Twitter
Published on July 05, 2020 20:56

December 6, 2018

Rediseño del renderizador

Ahora que voy a pasar a otra etapa en el desarrollo de lo que algún día podría convertirse en un juego, no quería dejar algunos ámbitos vitales del motor como habían quedado. Durante el desarrollo, la implementación de la renderización se había dividido de manera que para dibujar algunos elementos se usaba una clase y para otros otra. Además, el hecho de que el dibujo se realizaba en capas tampoco se reflejaba en la arquitectura. Para ello he revisado todas las piezas funcionales y reducido la implementación a sus conceptos principales.



¿En base a qué se divide una fase de renderización de otras? Por ejemplo, primero se dibuja el terreno, que include el suelo y el agua. El terreno lleva asociada una textura específica; cambiar de textura es una operación que cuesta bastante para la tarjeta gráfica, lo que ha hecho que la mayoría de juegos intenten incluir los gráficos en la menor cantidad de archivos de imagen posibles. Sin embargo, la misma textura se usa en otras fases del dibujo; cuando el usuario mira desde una altura considerable, sobre las casillas de terreno debe dibujarse una casilla traslúcida, y esas casillas leen de la misma textura. Algo similar pasa con la textura de donde se sacan los dibujos de las criaturas. Se lee de ellas durante la fase en la que se dibujan las criaturas situadas en la misma altura desde la que el usuario ve el mapa, y durante la fase en la que se dibujan las criaturas situadas bajo el nivel de altitud actual.
Lo que parece único de este proceso es el concepto de capas, o layers en inglés. Primero se dibuja la capa de terreno, luego la de actores bajo el nivel de altitud actual (si existen), luego las casillas traslúcidas, luego los actores en el mismo nivel de altitud, y sobre esas capas obligatorias también se utilizan, en algunos programas, una capa para mostrar las regiones (que no usa una textura, además), y por último una capa para dibujar los overlays, o iconos; por ejemplo, para indicar al usuario la casilla situada bajo el cursor del ratón.
No todas esas capas están activas en todos los programas. Es la responsabilidad del usuario activarlas.

[image error]


Unas funciones aisladas se encargan de gestionar esa activación, lo que ha permitido refactorizar todo ese código para aislar lo poco que cambia.


[image error]



Idealmente, la renderización de todas las capas debería poder realizarse con una sola llamada, en vez de que otras clases intercalaran renderizaciones cuando lo consideraran necesario. Por fortuna existen dos fases claras a la hora de interactuar con los renderizadores basados en OpenGL. En la primera fase se introducen los valores que componen los cuatro vértices de un cuadrado. Cada vértice puede tener hasta nueve valores en el sistema actual: tres valores para la posición, cuatro para el color y dos para la coordenada de la textura. Pero esos valores introducidos en el renderizador sólo se dibujan cuando se le exige que lo haga. Eso facilita dibujar las capas en sucesión.

[image error]



Por desgracia uno de los programas, el que genera imágenes, ha evidenciado que no todo el renderizado puede reducirse al concepto de capas. Para ello se le permite registrar “órdenes de dibujo”, funciones que se ejecutarán durante la fase de dibujo, aunque se desconozcan los detalles de los renderizadores utilizados.

La única otra mejora que se me ocurre ahora mismo es limitar los cambios en los datos de los vértices a cuando el mapa se desplace, pero en el futuro algunas de las casillas podrían estar animadas, y para sólo cambiar los datos de esas casillas implicaría crear estructuras nuevas y registrar esas coordenadas específicas. Demasiada complicación para lo que me solucionaría ahora mismo.


 

 •  0 comments  •  flag
Share on Twitter
Published on December 06, 2018 00:41