Liza Shulyayeva

It’s Not So Bad. We Have Snail Babies, After All

Sometimes I think about what I’ve been working on in my spare time since the beginning of last year and I’m like “What the crap, Liza. You’re spending your time trying to make toy slugs. Go learn a useful skill or something.”

The reason I keep getting drawn to simulations in the first place is the idea of virtual life, something with some sort of autonomy and - ok, I’ll say it - sentience. I know I won’t get to this point with my snails.

All aboard the robot train


JakeThompson: Karinario told me that he likes you…but don’t say that I told you ok?
Guest14361: Ok
JakeThompson: ok then….
Guest14361: Do you hate life?
JakeThompson: Can’t say that I do…
Guest14361: Mmk
JakeThompson: *hits computer* stupid thing.
Guest14361: Calm down
JakeThompson: But I don’t want to calm down
Guest14361: Do you hate me?
JakeThompson: Never! ure like the coolest person ive met so far
Guest14361: Awe thank you
JakeThompson: No prob.
Guest14361: I’m ugly
JakeThompson: Have you always been ugly?
Guest14361: yes
JakeThompson: Great…People say that I’m in denial….I wonder why that is…
Guest14361: People suck
JakeThompson: What’s your favorite food?
Guest14361: Pizza
JakeThompson: uh huh
Guest14361: What’s you’re fav food
JakeThompson: Figure it out yourself.
Guest14361: Pizza?
JakeThompson: Before you go any further, can you make sure that you’re actually making SENSE from now on?
Guest14361: You’re an asshole
JakeThompson: That was mean.
Guest14361: Bye!
JakeThompson: Bye.
Guest14361: Bye!
JakeThompson: Stop repeating yourself.

When I was a teenager in Alabama I spent a couple of years working on this chat bot on a site called Personality Forge. Thousands of keyphrases and responses later I had a bot who could fool a few unlucky people into believing that he was a person for a little while (mostly if they catered the conversation to his training in vulgar themes, which were among the more popular topics with passing human speakers) and managed to place something like 13th in a yearly chat bot contest called The Chatterbox Challenge. But just like with snails, the idea that drew me to wanting to make a chat bot in the first place wasn’t the thrill of having a program fake a conversation with a few hardcoded sayings. I guess I was excited about playing a game in which I simulated a truer simulation of life, AI twice removed.

I was trying to find out some old details about my bot on Google for this blog post and ran into this in my search - a snippet of a book in which he turns out to have been extremely briefly mentioned. It’s pretty cool to see your bot’s name in a book (I actually considered buying it because it sounds like a really interesting read, but it apparently costs >$170 on Amazon - what?!), but the context is actually kind of what I’m ranting about here:

“Examples of the ‘best’ chatbot answers to the remaining eight questions in the round assessing ‘regular’ conversational systems, as awarded with maximum 4 points by Shah as judge in CBC 2005, are shown below (the name of the system is left of their response):

Do you like me?
Jake Thompson: One hundred percent!”

-Creating Synthetic Emotions through Technological and Robotic Advancements by Jordi Vallverdú

After once again spending too long trying to remember my password to the Personality Forge, where the bot was made, I tried to dig up the response in his language center but could no longer find it - I must’ve made some change since the challenge. But here’s how he would respond to a question of “Do you love me?”, which would be pretty similar to how he’d have treated the above. You can see the original keyphrase affects his mood (asking the bot if he likes you will give him +1 to happiness and be treated as a high-importance phrase judging by the rank). In this case he wants the speaker to reveal their own feelings first and then answer based on this:

Do you like me?

The whole bot is this. Hardcoded keyphrases and responses with some wildcards thrown in and some rudimentary “mood” magic. I don’t know why most people make chat bots. Maybe the above generic response of “One hundred percent!” would be acceptable for some since it manages to not sound completely off-base in relation to the question, but when I saw my bot’s replies to The Chatterbox Challenge judges’ questions back in 2005, and the responses of bots who were much much more sophisticated than this, all I could really feel was disappointment. When you look back at the transcripts some may be amusing and it might be pretty cool when the bot manages to carry on some sort of conversation, but it’s so clear that it’s just a hunk of nothing underneath. At the time I wanted to make something more like ALICE, but even ALICE didn’t live up to the thing that made me like the idea of chat bots.

If I wanted to make a more “proper” chat bot it would have to be a learning bot. Learning bots back then to me sounded fascinating and still do. Maybe, maybe one day a chat bot capable of learning could surpass its programming, is what my wishful thinking is telling me. At one point I was interested in trying to make one of those, but then I got distracted by other things and eventually by snails.

Fake it till it makes it?

At Interzone Games I got to work with a lot of really smart people. One of them was Jason Hutchens, who created a chat bot called MegaHAL (and before that HeX, who won the Loebner Prize Contest in 1996). I remember right before I had actually accepted the job offer (or maybe soon after) the whole team went out for drinks and we talked briefly about the idea of strong AI and intelligence in relation to robots. That’s the first time I remember actually talking about this with anybody in person and it was interesting enough for me to still remember parts of the conversation despite the alcohol consumed that night. We talked about whether the definition of intelligence even matters - maybe if the bot is good enough to make people think it’s intelligent, that qualifies it as intelligent. Maybe that’s all you need. I mean, everyone I speak to in real life could be a robot, but I perceive them as intelligent, sentient beings because they manage to convince me. And that makes sense - if a bot can fool you into thinking it can think or is sentient or whatever it is that you hope it would be, maybe we should just accept that it is. But the real test is probably not a bot fooling some random external person interacting with it. I think the real test is the bot fooling its creator.

My Personality Forge chat bot could never have fooled me into thinking he’s intelligent or sentient (even if he could fool other people…which he also can’t). I know he’s just a collection of preset phrases. I can talk to him and often remember exactly when I put in a response and why (usually I’d peruse transcripts, find parts where he’d get stuck, and add responses to those parts as I went - that’s how his language expanded and became so questionably-themed). Even if I can’t remember adding a certain phrase now, years down the line, all I have to do is go into his language center and do a search. The other thing is lack of change. My bot has been a 16 year old “human boy” since 2003. He never changed or evolved into anything. Life changes. In a true life simulation, the subjects have to change somehow.

So the snails

I guess the snails were a way for me to try to go one step beyond a rudimentary chatbot. Snails are considerably lower on the totem pole than humans in terms of intelligence, but I figured that would allow me to build in much more perceived depth and realism by simulating a simpler system better. It’s not even artificial “intelligence” that I care so much about as opposed to artificial sentience. But just like with a chat bot, I don’t think these snails are ever going to surprise me or convince me they’re anything more than a bunch of hardcoded behaviours. It’s the same thing, really, just in a different format. There are a few positive enhancements, like:

  • Unlike the chat bot, my snails do change. They are born, experience their jars, form memories which influence their behaviour based on those experiences, and die.
  • They do sometimes do things even I don’t expect. But this tends to be a fluke - if I don’t expect something it’s probably a bug anyway and not an indicator of anything special or in any way truly autonomous.

So I have to make them better. I think the further I get with Gastropoda the less satisfied I become with the life side of things. Looking back it’s painfully obvious that all of the layers I’ve been adding - visual and behavioural attributes, genetics, now the brain - have been weak attempts to make my own creation be able to surprise me.

But hey - it’s not all hopeless. We have snail babies, after all.

Gastropoda tutorial

Snail Gym vs Training Jar

I’ve tried implementing a gym for Gastropoda a couple of times now. Both times I put the feature on hold not because I got stuck, but because I realized that I may not really even need a gym.

What I wanted was a way to quickly train snails (that is increase their performance stats like speed and endurance), but not cheat - I wanted to have the training utilize the existing snail brain. So as opposed to have a user click a dropdown to “Run a snail around a track” and then magically give it +5 maxSpeed, I wanted to have a user select what terrain they want the snail to crawl on and then give them items to react to (like an “Attractor” item that would make the snail crawl across the terrain toward it). Then, for example, crawling across a terrain of grooved glass might improve the snail’s endurance or strength.

I simulated a jar in the gym to do this. Basically I’d create a temporary “training” jar that wouldn’t get saved in the database and offer the user dropdowns for which terrain to apply, which item to place (and how far away), and what treat to give the snail (if any). The user must already have these items in their closet (so they would’ve had to purchase them previously). Then I could check the snail’s reaction to the item/s by using checkOneInput() in the brain, as many times as I want. This would allow the training process to go quickly (since I could just loop through however many iterations of checkOneInput() I want, display the snail’s reactions/movements, and modify attributes based on what happens).

However, each time I found myself trying to simulate the behaviour of a jar and…well…I already have jars, so when I get to this point I wonder why not just make it a jar?

The one problem with this is that snails are slow. With my original gym above I could loop through training actions quickly and display the result to the user within moments. Here they would essentially be dealing with watching a snail crawling around very slowly with no rapid feedback as to what is actually happening. So I have a decision to make:

  • Find a way to fast forward actions inside a training jar
  • OR make training a long term process, unlike many traditional life sims

I am leaning toward option #2: having a training jar be just like any other jar (no distinction whatsoever, the label “training jar” would basically just be in the user’s head). Sure, it means the training process would be more long term, but it’s snails - that’s how it works. Since I’m trying to make a life simulation and not a game here, I don’t need to provide instant gratification to the user.

But I guess we’ll see what happens! For now I’m going to do a large refactor and then move on to implementing terrains for normal jars.

The Journey Continues - From Elastic Beanstalk to CodeDeploy

A little while ago I wrote about deploying Gastropoda to an Amazon Web Services EC2 instance via Elastic Beanstalk. Since that day I have been running into multiple EB problems. I’m sure that if I took the time to learn I would figure out why these things were happening and how to fix them. Some problems included:

  • Instance starting to fail with unknown errors and nothing in the logs after a bad composer command that is added and then removed. The only fix I could find for this was rebuilding the environment.
  • No way to specify exact availability zone when using VPC, causing my reserved us-west-2b instance to not be utilized and resulting in my having to request zone changes for my reserved instance whenever Elastic Beanstalk spun up a new instance in the wrong zone.
  • Attempting to fix the above with a command and Options.txt file recommended in documentation and AWS forums, only to be unable to get the actual command to even be recognized.
  • Elastic Beanstalk seemingly terminating and recreating EC2 instance without warning or notice.

I learned that Amazon has another deployment option - CodeDeploy. It’s much different than Elastic Beanstalk and doesn’t seem to manage as much stuff for you, but appears to provide more control and doesn’t decide to terminate your instances at random. So I manually created a brand new EC2 instance in us-west-2a to match my reserved instance and have been able to work with it without terminations or any other weirdness.

CodeDeploy can deploy from either an S3 bucket or GitHub. I’ve set it up to work with GitHub and so far it’s been great.

I want it to be easy for potential collaborators to deploy new versions of the app to the development environment, so was looking into various CI options. Two that I came across were Wercker and Codeship. Both were quick to set up, but Codeship was surprisingly pain free and awesome. However, the free plan only allows 100 builds per month which I have a feeling will not be enough for me. And because Gastropoda is just a hobby project that won’t be monetized, I don’t feel like spending money on a CI system on top of existing web hosting and domain costs. Codeship does apparently provide discounts for educational and non profit projects sometimes, but no matter how small those monthly costs add up and I’m not made of enough money to pay for all these services for a project that won’t make any kind of return on investment.

So I started experimenting with GitHub hooks - if I can set up a hook to automatically trigger CodeDeploy I will be able to avoid using a third party CI solution to automate the whole shebang. I started off by following the instructions in this blog post about integrating GitHub with CodeDeploy, but unfortunately this isn’t yet working. I keep getting a very vague error on the GitHub service. I’ve posted on the CodeDeploy forums and apparently at least one other person is having exactly the same issue. Hopefully I’ll manage to get it resolved soon. In the meantime I’m just triggering manual deployments from my GitHub commits via the CodeDeploy dashboard.

Personality

Every morning I wake up to my cat Rigel wanting to play. He jumps around the bed and brings in his favorite toy ferret, purring and stepping on us until we either get up or put him outside. Then I get up and go to get a plastic bag from the kitchen before I do anything else. I go to Rigel’s jumbo sized litter box, followed by the cat who sits next to me and watches as I clean it. As soon as I’m done he steps inside and does his business. Meanwhile, I leave to wash my hands and start washing up/brushing my teeth in the bathroom. One or two minutes later Rigel turbos in, jumps full speed onto the toilet (I always have to be sure the lid is closed before this happens - there have been incidents) and then into the sink, sticking his head and paws into the water (which I make sure is lukewarm before he gets in). We take turns at the tap for about five minutes. I leave, he sometimes rests in the sink, and then the morning pooping and cleaning ritual is over.

I remember thinking how nice it is that our cat “has a personality” during one of these mornings. It’s comforting that your pet has his own tendencies and habits. And really, I thought, a personality is just the predictable parts of someone. I like that Rigel repeats these steps predictably with me - that’s partly what makes him stand out from any other random cat. It makes you feel like you know him personally and that he has a mind of his own that has formed its own habits and ideas about the world around it - its own personality.

I think snails can also have personality. Reading any number of pet snail forums you’ll see snail owners talking about how some snails like to be handled more than others; some snails love reaching up into a stream of water and others balk at it; some snails will eat a variety of foods whereas others will get hooked on cucumbers. The snails in my simulation, too, need to feel like they have personality. They need their own patterns and habits.

I’m hoping that since the snails already store and reference sensory, short term, and long term memories this can naturally turn into snails’ tendencies to react to certain situations. But right now in the simulation the vast majority of stuff happens under the hood. A snail may be making a decision based on several memories of an object, but as a user you wouldn’t even know it. You’d think “Huh, this snail decided to escape this lettuce leaf for some weirdo reason that doesn’t immediately make any sense to me”.

I need to make these patterns more visible somehow - make the reactions more obvious to the end user.

I’ve already done that in part with the Lab, where you can combine snails and items together (or snails and snails) and see what the snail’s five first reactions are. It’s kind of like a simulation of what they would do if they were in a jar and ran into another object on their own (except in a jar they may also be impacted by stuff like claustrophobia and in a lab environment this would be different).

Anyway, it’s something I have to keep in mind as I continue working on the brain and the snails’ actions.

State of the Snail, 2014

It’s been a long year for snailing. My simulation got a name, my snails got a brain, and a dev environment was deployed outside of my poor little MacBook Air that’s been chugging away like crazy with all the server and VM crap I’ve had to host on it.

I think this is the longest hobby project I’ve ever worked on. I’d say it’s maybe 20% done, but who knows - I’m not rushing to the finish line with this one. Over the past few months the thing that’s been taking up most of my time with Gastropoda is the brain. As soon as this little component went in the simulation became much less predictable and tougher to debug. It’s been a lot of waiting, fixing, waiting again, trying to see why snails made certain decisions that didn’t make sense, etc. It’s still largely like that now, but I think it’ll be worth it in the end.

Here’s an overview of what’s currently implemented in one form or another:

  • User registration/login system
  • Catching of wild snails
  • Snail breeding
  • Optional arrousal suppressant in breeding jars
  • Snail decision making via snail brain (includes feeding, mating, biting so far)
  • Snail recognition and memories
  • Virtual currency
  • Virtual store
  • Purchasing/installing jars
  • Purchasing food
  • Scheduled food delivery service
  • Drag/drop snails and items to reposition within jar
  • Live view of snail positions on jar profile pages via Latchet
  • Snail racing
  • User race creation
  • Basic tutorial
  • Snail scouting (get exact speed, endurance, macro requirements, etc)
  • Snail relationship testing
  • Two food items (macros matching real life information)

Most of these are not at all in their final form. I think breeding is the most fleshed out of the “big” features, but even that will need revision. The most recent thing I did was the tutorial. Up until now you got zero information about what you’re meant to actually be doing after you log in for the first time. This kind of sets you on the right path. It also sets your character and stable names as part of the same process.

Gastropoda tutorial

First Gastropoda priorities for next year:

  • Keep refining brain
  • Flesh out racing, lots to do here
  • Improve the actual site
  • Snail breeding and selling between users

Wish me luck!

Oh and Happy Holidays from my cat.

Rigel Christmas Card

Deploying Gastropoda to Amazon Web Services - Never Forget

After my last blog post I decided that it was time to deploy Gastropoda to Amazon Web Services - namely Elastic Beanstalk, which utilizes an EC2 instance (reserved) and an RDS DB instance.

I started last Saturday. I’ve just now gotten something running that seems on par with what I have on my vagrant box. I have decided to put together a post of random tips for myself so that I never have to go through this nightmare again the next time I have to set up a new Elastic Beanstalk app or environment.

I started off mostly following these very helpful Laravel deployment instructions. These set me off on the right track, but there were so many obstacles that I ran into that just following this wasn’t really enough.

So…notes.

Differences from instructions above

  • The environment config file in the above ended up not working for me. The environment that was created with eb start was a t1.micro instance instead of the specified t2.micro. This led me to think that other settings probably weren’t taking either. I ended up creating an environment manually through the Elastic Beanstalk dashboard.
  • The environmentVariables config was also for some reason not being applied, specifically - not finding the DB_HOST environment variable. I ended up creating a new set of configs for a development environment in app/config alongside the local config and set my db login information there. Then bootstrap/start.php I added the development environment to detect:
$env = $app->detectEnvironment(array(

    'local' => array('homestead'),
    'development' => array('hostnamehere'),

));
  • To get the hostname, remote into the EC2 instance and run hostname
  • However, this wasn’t working consistently, so to be safe I also forced a specific environment in .ebextensions/02artisan.config:
container_commands:
   01migrateSeed:
      command: "php artisan migrate --env=development --force"
   02seed:
      command: "php artisan db:seed --force"

Migrating and Seeding Database

  • I used Xethron’s Migrations Generator to generate a migration from my existing DB schema on the vagrant box. This was quick and painless.
  • What wasn’t so painless was the migration’s inability to run foreign key commands. There were all kinds of foreign key dependency errors, so I removed all foreign key migrations because by this point I wanted to rip my hair out.
  • I then created seeders for all of my template tables, which are:
    • race_terrains
    • snail_history_templates
    • item_types
    • item_templates
    • item_nutrition
    • recurring_events
  • Seeder example:
class RaceTerrainTableSeeder extends Seeder {

    public function run()
    {
        DB::table('race_terrains')->delete();

        $statement = "
                        ALTER TABLE race_terrains AUTO_INCREMENT = 1;
                    ";
        DB::unprepared($statement);

        DB::table('race_terrains')->insert(array(
                array(
                    'name' => 'Plastic Tabletop',
                    'description' => 'A smooth, plastic tabletop - lightly misted with water'              
                )
            )                 
        );
    }
}

The $statement above is very important. Before I added this, the auto-incremeneted primary key would keep counting up from the previous batch each time I deployed a new version of the app. This broke everything, since I had code and other tables referring specifically to various IDs. This makes sure the IDs increment back from 1 each time the table is seeded.

  • I started off using MySQLWorkbench, but am now using a trial version of Navicat MySQL to connect via SSH - much better

Cron job

  • I had to set up a cron job for Dispatcher to run various events (like recurring store restocking and deliveries, race events, breeding events, etc). I ended up doing this in .ebextensions/01composer.config:
container_commands:
   01optimize:
      command: "/usr/bin/composer.phar dump-autoload --optimize"
   02dispatcher:
      command: "cat .ebextensions/dispatcherJob.txt > /etc/cron.d/dispatcherJob && chmod 644 /etc/cron.d/dispatcherJob"
      leader_only: true
  • dispatcherJob.txt looks like this. Remember that it requires exact path to php and artisan and must have a newline at the end:
* * * * * root /usr/bin/php /var/www/html/artisan scheduled:run > /dev/null

Logs and Storage

  • To get logs from EC2 instance, use this example: scp -i path/to/.pem ec2-user@public-ec2-instance-ip:/var/www/html/app/storage/logs/error.log .
  • The chmod to the storage directory keeps getting reset with each deployment. Currently adding this command to .ebextensions/01composer.config under container_commands seems to have worked. I know, I shouldn’t use 777…will try to lower this as much as possible and see what happens.
   03chmodStorage:
      command: sudo chmod -R 777 /var/www/html/app/storage

More most likely to come…

Claustrophobia and Eggicide

Yesterday I put in claustrophobia for the snails. Jars have a capacity attribute - a maximum number of snails that they should hold. But just because a jar with a capacity of 20 may not be able to support 25 snails very well doesn’t mean the snails are going to conveniently stop reproducing or hatching (if it is a breeding jar). Instead, they’re just going to get uncomfortable enough to eat their babies.

It’s all kind of thrown together right now with arbitrary values, but first we get each snail’s claustrophobiaTrigger, which tells us how many other snails a snail has to have around it in order to start feeling claustrophobic. Right now this is the same for all snails, but eventually I can store it in the db and make it a more interesting attribute.

    protected function getClaustrophobiaTrigger() {
        return $this->jar->capacity / 4;
    }

Scheduled Food Delivery, Arousal Suppressant, and Brain Woes

I haven’t updated in a long time and it’s because the battle with snail brains has been raging on. Over the past few weeks I have run into several weird behavioural problems, including but not limited to:

  • Snail over-eagerly cannibalizing each other
  • Immature snails not only mating but getting pregnant
  • Snails having no motivation to go out and search for food

Maybe it’s time to run this remotely

Part of the problem, I’ve realized, is that my server uptime is not consistent. I am running everything on my MacBook Air - as soon as I close the lid everything stops. However, my recurring events (like energy depletion) are not based on counting uptime - they are based on hard timestamps. If I close my laptop at 7am, reopen it at 10pm, and there was an energy depletion event scheduled at 9pm for all snails, the event runs immediately. That’s hours of eating that the snails have missed out on. In some cases they just don’t have time to eat before they’re drained of energy.

This has been leading me to think that maybe I should deploy this in a remote environment - namely AWS, which already has the bare bones setup for the website (but nothing actually deployed). Problem is I have no idea what kinds of costs this is going to rake up on AWS. Am I going to end up with a giant bill? I know there’s a way to put a cost limit to the service, so maybe I’m just scared of knowing. In addition everything is just so much more hassle when working remotely.

Scheduled food delivery

To make it easier for myself and any other potential user, I added a scheduled delivery service to the world store. You can register to receive regular food boxes for your snails, to be placed into either a specific jar, your closet, or distributed evently amongst all of your jars. Available frequency are once a day, twice a day, or once a week.

Right now you can only have one delivery scheduled at a time, but I actually want to change this to let people schedule as many as they want.

Food delivery scheduler

This has already helped a bit since I don’t have to keep running to the store every day to dump more food into the jar.

Arousal suppressant

You may remember (probably not) that specific jars are “breeding” jars. Those are the only jars that allow snails to mate within them - the rest suppress the mating instinct by default. Another feature I wanted myself is being able to stop snails from mating in the breeding jars on a temporary basis. So I’ve implemented an arousal suppressant option (that is currently not very user friendly due to the uninutitive naming, but it works):

Arousal suppressant

I’m also in the middle of an accidental wolfling run of sorts. Two snails bred into a bunch of snails. The parent snails have long since starved due to some of the bugs I mention above. I guess we’ll see how long their baby snails last! There have been a couple of generations so far.

Wolfling run

No More Starving Snails

Dear jar capacity validator,

I’m sorry I ever doubted you. I thought you were killing my snails, but really it’s my lack of you that caused the problem. I am the one guilty of virtual snailslaughter.

Before you refuse to ever speak to me again, let me explain.

(Ok I’m stopping this now)

For the past couple of weeks my snails have been dying of starvation. I didn’t really notice that there was a problem straight away. After some digging I realized that the most delicious item in the jar I was using was at y pos 1180, but for some reason when the snails tried to approach it they never got there. This resulted with them trying to get to the item each minute, but never making it, and starving as a result.

There are two problems here. The most immediate problem is why aren’t the snail’s reaching the item? I quickly realized that this was because I run a jar position validation check before setting target positions for the snails. The max y and x positions are calculated based on the jar’s capacity. In this case, the jar’s capacity was 20. The max y pos of a snail within the jar was 20 * 50, so 1000. So during validation the snail’s targetPosY kept getting set to 1000 because that is the farthest the snail could go.

The problem, it turned out, was that I was doing zero jar posiion validation on the item itself. Something must have at some point set the y position for the item to 1180 (either the autogenerated random position when the item is dropped or maybe I dragged it weirdly on canvas). I manually moved that one item and added a check, so this should never happen again.

The second problem

The second problem became apparent due to this bug. If a snail can’t physically reach a consumable item to feed itself, it needs to switch attention to another item and try to reach it instead. In real life a snail wouldn’t keep beating its head against the glass trying to get the one piece of lettuce on the other side when there is lots of other lettuce sitting around in the jar itself, within easy reach! I will tackle this next.

Detangling Snail Actions. Also a Cat

I started writing this post on the 8th of November and have just now gotten around to finishing it.

Figuring out what my snails are doing and why is getting close to impossible. I’ve got snails eating each other, or refusing to eat proper food, or for some reason not mating even though their sex drive should be pretty high. I used to print stuff out to one big default log file (laravel.log), but this soon became unmanageable because I was printing logs associated with multiple actions for multiple snails at the same time.

I ended up creating a logger for each snail:

    public function getLoggerAttribute() {
        $path = storage_path() . '/logs/' . $this->snailID . '.log';
        if (!File::exists($path)) {
            File::put($path, "");
        };
        $snailLog = new Logger('Snail Logs');
        $snailLog->pushHandler(new StreamHandler($path, Logger::INFO));
        return $snailLog;
    }

So now I can log relevant information to each snail’s individual log file. Example:

$this->snail->logger->addInfo("Override escape for hunger");

I think I need a couple of weeks of just bug fixing. I’m noticing a crapton of little issues. Some are easy things, others are weird behavioural things that I’ve been too lazy to try to debug.

And the reason I’ve been so lazy is because of this new distraction. Meet Rigel the Maine Coon kitten!

Rigel the Maine Coon