SNISAC

Out of the abundance of the heart the mouth speaks

Index

These are the snisac creations.

Undated

Timeline

Newest first. Dates are written in the great date format of YYYY.MM.DD!

About Snisac

A website about with topics like programming, math, writing, and pixel art.

Snisac.com is a single-page website that I started in the beginning of 2025, although there are posts dated older than that because I copied them from an old website of mine.

Snisac has no official affiliation with any accounts on any social media sites.

Pixel art

99 splotches of pixels on the screen, 99 splotches of pixels...

Cow

Golden omega

inset

marmalady

moon

stan64

while-its-hot

wiz

world

bunny

div

div0

div0_button

flower2

fox1

fox2

fox3

fractal_9

fractal_10

fractal_11

fractal_12

fractal_13

fractal_14

fractal_15

fractal_16

fractal_17

fractal_18

bee-box

berry

blocks1

cartoon-food

cipher

dino-eggs

fire-sharp

flags

flower-1

fun-horse

gentlebug

helium-2

hen

hidden-depth

icecream

inset

kitty

majesty

moon-rocket

neon

no-stars

nope (2017)

pines

existence2

rainbox2

raspberry

shapes-and-colors

solar-wisp

space-fish

space-rock

spheres

spiral

spruce

star-fractal

stereo-skull

time

gnome

unicorn

weirdness

Learn programming by being a programmer

()

This is a small amount of unsolicited advice.

If you want to start learning programming, your purpose for learning determines how much time you have, what programming topics you want to learn about, the language you want to learn, and how well to learn (certain parts of) that language. In the end however, your success depends on your ability finally to finish and ship the project you want to program. Programming is yet another thing learned by doing, and experienced by creating many projects (even/especially small ones). Some useful skills you will want to pick up before or along the way are touch typing, computer file management, basic understanding of computer some parts, and some math.

Math

Math is good to know because it allows you do less programming. It's a useful tool and sometimes a shortcut that avoids a need to write more code. The math you want to know about are algebra, functions, sets, and boolean logic. Each of these is useful to know at least for avoiding over-complicating your code's math and flow control. It's useful to know algebra because you need to get very comfortable with variables. It's useful to know about function domain and range, and about total and partial functions. It's useful to know about set terms such as membership, union, intersection, and complement. It's useful to know some boolean logic because that is foundational to understanding conditions and flow control in most programs.

Language recommendations

The type of project could predetermine the programming language. The language depends on personal preference and what you want to do. Languages are meant to be general purpose, but the other people who are using it and the language's paradigm makes it easier or harder to accomplish certain things. What language to learn if that decision is not already made? I recommend Python, C, Lua, or Common Lisp. But, if you want to learn C++, learn C first. C++ is so large and multi-paradigm, that the common reference point of fundamental C really helps.

Baby steps

Start with learning a simpler language such as C or Lua rather than C++ or Java. And start learning with super small projects such as: print out the numbers 1 through 1000.

Sleep is nice

()

It would be so nice to naturally wake up at dawn without an alarm clock.

Living in the light,
Sleeping through the dark.

,

Anno Domini

( A.D.)

I was $today years old when I realized that A.D. (anno Domini), which means "year of the Lord" in Latin, is in line with the tradition of reckoning the years based on the rule of a king. You know, like, in the olden days where it would the Nth year of the reign of $king. Well now, by our convention in dates, it is acknowledged that Jesus Christ is Lord. We can never escape God or time, can we? But, sadly for programmers (except Lua programmers), there is no year 0 A.D. The years of this epoch start at 1.

,

Videogames no more

()

Time and attention is precious, so the best relationships to have towards videogames are total avoidance or to only play games with friends for the purpose of socializing.

Otherwise, you are voluntarily spending time on unnecessary tasks and entertainment that does not give you anything else in life. These games keeps you in a stasis (or an indoctrination) in the guise of activity and achievement. It is silly to spend hundreds of hours playing a game alone.

However, tiny little games, like some that I have made myself, tend to not trap people but simply provide a moment of novelty.

Big videogames are art + manipulation.

,

Trollish notes on hosting a web page

(updated )

These are some rantings on what I've learned from having a website.

The simple static site generator

If you know some programming... The idea is: just write a specialized program that generates your website, and just put all of your site content inside of that one program. There is no need for external data files or parsing a markup language. Just run your script (and maybe pipe the output to a file) and it is done!

For example, I have successfully done this with Python, Lua, and Common Lisp. You can just have long string literals for each page and print them out to the page's destination file path.

So then if you are using Python and you have just one webpage, your command to generate your site would look like this:

python site.py > index.html

Since languages commonly have an easy way to do string interpolation or concatenation (not you, C!), you can just put functions or variables inside of or concatenated with your other content strings.

And, if you do this, what have you done in the end? You have basically just used that programming language as static PHP (not dynamically, server-side)!

Mini-pages

If you want to have the appearance of multiple pages on your website, and you're not using a CMS, then you may need to do some extra work to maintain all of those files. But, there is an alternative: put your "pages" all in the one main page (index.html) as "mini-pages". The trick is to use the CSS selector called :target. If you make top-level articles which are all on the same page only show as visible when they are the target link, you get mini-pages.

Since I am nice, here is the template CSS code, which applies to HTML elements with the "hider" class:

/* Show one article (the currently targeted one) at a time */
.hider { display: none; }
.hider:target { display: block; }

,

Unsafe squares

Announcing Unsafe squares – Boring minesweeper clone

,

Eyes in the skies

Announcing Eyes in the skies – Bow-shooting mini-game

,

Prevent a #DIV/0 error

()

Here's a quick tip for avoiding #DIV/0 errors in Excel spreadsheets…

The tip

In Excel, doing math with cells treats blank cells as zero, so if you are ever dividing by cells values which may be blank, you get #DIV/0 errors. To avoid this, you can use this function to wrap your original formula, f:
=IFERROR(f, "")
Now if you have blank cells as inputs, whatever calculation uses them will be blank too. This transmits blank cells over division.

Example

This is useful, for example, if you are calculating price per square foot from a column of prices (column A) and a column of square footage (column B). Then, when you create a column (C) for the price per square foot with the formula something like:
=A1/B1
If you have some unknown square footage values in column B, so those unknown cells are left blank, and you want to avoid the ugly error value showing up in your C column, then you can change to formula to:
=IFERROR(A1/B1, "")
so the cells in the C column will be blank in the same row as the blank cells in the B column. This is what I mean by transmiting blank cells. The blank values propogate to the result column instead of an error showing up in the result column.

Bonus

If you know some Common Lisp, then you may recognize Excel's IFERROR as being similar in function to Common Lisp's UNWIND-PROTECT special operator.

,

On content creators

()

A rant on so-called content.

I see content creation and the content it produces in a negative light. A friend of mine is a film enjoyer and is studying the art. One time, he told me how he hates the usage of the word content, and I did not need to ask why because the moment it was mentioned, I think I knew his pain.

Content is the catch-all term for internet information. And I mean information in the broad sense, because in the specific sense of the word, information is actually useful or edifying. However, the information of internet content often does not have this quality.

Computers, smartphones, and the internet have opened up the realm of sharing creative works to almost everyone. Some people get into making money off of the attention that people spend consuming the works. In a sense, content represents how creativity has been turned into a commodity in order to harvest the other commodity of attention. In the end, this drives a massive overabundance of low-quality materials being hosted online with the goal of gaining something from the people in the role of consumer.

On the side of the new content creator, this puts pressure on him/her to value the quantity of content produced over the quality, and this can box him/her into low-grade creativity as a career.

,

Game loops: the heart of computer games

Written on

This is a short article about what a game developer should know about the computer programs that run games. This is not about gameplay loops, which are loops that game players themselves are put into. This is a simple concept that I think is taken for granted in game programming tutorials and needs a more explicit explanation. I think it is necessary to explicitly state the mechanics of using a game loop in an architecture. The page at GameProgrammingPatterns.com and this page from GafferOnGames.com are excellent reads. I am assuming that the game in question is a real-time graphical game that responds to user input immediately, as opposed to a command line interface game that has buffered input.

Why use time steps

In a game, you write the code for how the game world behaves over time, which expands into how each type of game object behaves over time. More specifically, you break down time into slices, time steps. You program what each object does at each game update call or frame or tick or time step. This constraint comes from the fact that you need to display the game world on the screen at a certain frame rate so that things appear to be moving. Since the output needs to sliced up into a sequence of frames, like a movie, you have no choice but to somehow calculate what the game world is like in those different frames. Also, it is difficult to model the behaviors of many interesting game objects as a long-term function of time, but it is simpler to describe what a game object does next in a short period of time at each step.

How do computer games work with these time slices? Well, there is one essential idea for game programs. Games can run for a long time or an indefinitely long time. In programming, running the game for a long time requires a loop of some kind. Usually this loop is infinite or only broken out of when the player closes and quits the game. The time steps are then simulated in this loop as long as the game is running.

So, somewhere in every game program is a loop that in general means the same thing as the C code below (ignoring the time step for now):

while (!game_should_quit) {
  update_game();
}
  

The elements game_should_quit and update_game would be substituted with the proper variables or function calls for your game architecture.

This loop is fine and dandy, but there can be a big problem with just updating the game like this without a time step duration variable. Typically you are writing a game that will run on multiple different computers, which will simulate and run the game at different speeds. The performance of the computer's hardware that the game will run on affects the speed of the game. If you adjust speeds solely to work on the computer you are developing on, then a different player who uses a slightly faster or slower computer will run the game, and it will feel completely different or could be unplayable due to being too fast or too slow.

A common solution to this is to introduce a time step variable or parameter, usually called "delta time", "delta t", or just "dt". This could look like the following in C code:

while (!is_quit) {
  float dt = time_since_last_update();
  update_game(dt);
}
  

While there is some nuance about whether you want a fixed time step or a variable time step, you usually want the computer that the game is running on to determine the time step amount before the loop begins or continuously during each loop tick, like in the example above. This can make the game physics/simulation updates not run faster or slower based on the computer's performance. A more performant computer will have a smaller time step than a less performant computer, and the more performant computer will execute more of these smaller time steps and thus have a higher FPS but will still get the same (or at least close enough) result in the physics updates. Having a smaller time step can lead to more accurate results, but if your game physics are mostly linear calculations, there should not be much of a difference between having a few big time steps versus many smaller time steps.

A simple derivation

So how is the time step dt used in the game update function update_game? Generally, you use it as a multiplier for physics steps. Say that you want a bullet to move at 50 pixels in a second. If you were running at 1 frame per second, the code would then look like this:

bullet_x_pixels += 50.0f;
  

However, you want way more than 1 FPS. Say that you ideally want 60 FPS. Then your game_update function runs 60 times in a second. Each update tick, you move the bullet by how fast it moves in a frame. Ideally you may want 60 frames per second, so your formula for speed would be something like the following:

bullet_x_pixels += 50.0f / 60.0f;
  

The above code will run 60 times in a second, and by the time one second has passed, the bullet will have moved: (50.0 / 60.0) * 60 pixels, which is 50 pixels. The equivalent math is replacing the division by 60 with a multiplication by 1/60:

bullet_x_pixels += 50.0f * (1/60.0f);
  

Then, if we extract the 1/60 into a variable called dt, we get the following:

float dt = 1/60.0f;
bullet_x_pixels += 50.0f * dt;
  

Then, the last step would to let dt be a parameter to the function that the bullet update code resides in. This gets us a general form that we can apply in any update code. So, in general, we can specify what we want to happen in our game per second and then multiply by the fraction of a second that each game tick (a function call to update_game) represents. The dt value is passed as a parameter to many other functions that update_game may call. So, much of your game update logic ends up being a function of dt, rather than time, t (which starts to look a lot like function integration)!

A typical strategy is to have a hierarchical function call tree to update your game:

∟ main_loop()
∟ update_game()
∟ update_gui()
∟ update_world()
∟ update_particles()
∟ update_entities()
 ∟ update_players()
   ∟ update_a_player()
 ∟ update_bullets()
   ∟ update_a_bullet()
 ∟ update_enemies()
   ∟ update_a_zombie()
   ∟ update_a_fireball()
  

And then dt is passed to each function, or it is a global variable, or a larger data structure of game info, including dt, is passed to every function or is globally accessible. Of course, if you must pass dt as a function parameter to update_a_fireball, for example, then you will probably end up having to pass it down from update_enemies, which gets it passed from update_entities, which gets it passed from update_world, which gets it passed from update_game.

Functions of t or dt

However, your game logic might not all depend on dt, or it could be better to have some logic depend on elapsed game time, t. A function of time is more numerically stable because floating point errors do not accumulate on a per-frame basis. Also, behaviors that are only a function of t instead of dt do not need to store as much current state from the last frame. An amazing example that exploits this fact, in a particle system, can be seen in this YouTube video about running particle systems efficiently on the PlayStation. Another example is animation. If you have a sphere that shrinks and grows at a certain rate over time, you could express it in terms of dt or t. If you express it in terms of dt, then you specify how much it changes over a little slice of time and add that to the sphere's radius, which needs to be stored as state somehow. But, if you express it in terms of t, then you always just compute the sphere's radius to be some function of time that does not require knowledge of the sphere's previous state, the radius.

(I may make a web page of its own about functions of dt versus functions of t in games, because it seems that a bunch of people mistakenly think that they should always or only use dt.)

The most important limiting factor

Depending on your game's technology stack (the game, engine, libraries, operating system), you may or may not have control of the event loop. In pygame, for example, you do have main control, but you need to query the event queue to make sure the main window keeps functioning. Other setups may require you to provide a callback function for game updates that gets called at times determined by the OS or the library, and so game loop is outside of your control.

A Pygame example

Below is an empty example main game loop for use in pygame:

import pygame

ORIGINAL_WIDTH = 1280
ORIGINAL_HEIGHT = 720
TARGET_FPS = 60

pygame.init()
screen = pygame.display.set_mode((ORIGINAL_WIDTH, ORIGINAL_HEIGHT))

def update_game(dt):
# add the start of your game logic here
pass

clock = pygame.time.Clock()
should_quit = False
# This try-finally block makes sure that pygame quits when Python has an error
try:
while not should_quit:
  if pygame.event.get(pygame.QUIT):
    should_quit = True
  dt = clock.tick(TARGET_FPS)
  update_game(dt)
  pygame.display.flip()
finally:
pygame.quit()
  

Further Exploration

,

Simple Headers

Written on

I remember reading an online article about how headers are very useful and then feeling inspired to create a program that can use plain text headers at the beginning of files. So I wrote a program to parse simple headers.

It really is simple. The computer just has to read the beginning of the file line by line until it encounters a blank line. Each line before that blank line is a key-value association between what is on the left of the colon and what is on the right of the colon. I use this system for almost all of the pages on div0.com, and it makes it easy to add whatever metadata I want to any page.

For example, the header for this page looks like this:

title="Simple Headers"
year="2023"
month="01"
day="22"

I know it is maybe too meta or self-interested to talk about how a blogging system works on that very same blog, but, this simple header system could be so useful for many different applications. It gets around the problem of OS-specific or filesystem-specific metadata fields by putting them at the beginning of the file's actual data, where it is safe.

Also, take a look at the arguments for writing in plain text at this page.

,

Enchanted Food

Written on

Quite a few video games have potions, and it is getting old. Minecraft and Terraria both have potion crafting. Potions use potion ingredients collected throughout the game world. What is the purpose of potions in these games? There are two main ideas for the purpose: the journey and the destination. The player goes on a journey through the game world each time they desire to reach the destination. The journey is a quest to acquire the ingredients for making the potions. And the destination is that the player gets temporary buffs that make them more powerful and able to complete other goals they may have in the game. Potions are secondary and are sub-goals for larger ones.

In Minecraft and Terraria, those goals are along the lines of defeating bosses and enemies, and making exploration and building easier. It is a way for the player to become more powerful temporarily. It rewards players for putting in effort exploring the game world and acquiring ingredients that prepare them for later stages in the game. Potions just become yet another item that happen to also be consumable. Later into the game, potions can become grind-y because the player eventually just realizes that they need to farm potion ingredients. But I have a different idea that may be implemented somewhere as a form of consumable buff items.

Here is an alternative to potions: enchanted foods. Enchanted foods open up an opportunity for connecting the game to real-life experience and knowledge. A game with food enchantment can justify having a whole cooking system... that happens also interacts with magic. This magic can make the system feel fantastical, and yet be relevant to real life. The cooking is especially a practical skill that someone playing video games could benefit from. You could legitimately claim that your game is educational (with the disclaimer that: no, there is no magic food).

This also opens up an interesting door in multiplayer games: deception. In Minecraft or Terraria, potions aren't very interesting items from a social point of view. You always know what they will do, because the items say what they are. If another player gives you a potion and says Here, drink this, then you can just look at the item and be like, Uh no it's clearly a Potion of Poison, ya goof. But, if your game has food, and makes eating food a good thing, then your game can allow enchanted food to appear as not enchanted, or have other tricks that make it harder to tell exactly what enchantments a food item has. Then, players will have to build up trust and not rely on the game to tell them everything. Also, enchanted foods can fit well into your game's story better than potions usually can.

Q: What did the Evil Queen give to Snow White?
A: Not a potion!

Why else are enchanted foods fun? It's MAGIC FOOD! There are so many more creative possibilities here than for potions. Well, it's also not as common, so it makes the game more unique. So, your game's players won't experience yet another potion system.

Of course, enchanted foods and potions are not mutually exclusive. You can have normal food too. The in-game item hierarchy would probably go something like this:
Normal food < Enchanted Food < Potions < Really Good™ Enchanted Food.

Q: What did the Evil Queen give to Snow White?
A: An Enchanted Apple!

Let's put the fun back in food.

,

Docker Simulator 2001

Announcing Docker simulator 2001 – Short space game where you dock the spaceship!

,

Nested Tiles

Written on

Kitty cat next to the book A New Kind of Science

Yesterday, I was inspired by skimming through Stephen Wolfram's book A New Kind of Science. He wrote about cellular automata, and I thought of another type of system in the genre of tiles-with-rules that I am calling nested tiles. It's a way of generating an image like a context-free grammar is a way of generating text.

Alternative names for this concept could be

and you could stick the word context-free in front and/or stick either of the words system or grammar at the end.

A nested tiles system consists of a set of rules. Each rule has a type/color of cell that it applies to and a rectangle of cells that the cell is replaced with. The nested tiles process is applied to an initial image and produces a new image according to the rules. In this way, the next step of applying the rules for each tile is independent of any other tile. My simplest example is for a ruleset where each tile is substituted with a 2x2 rectangle, which implies that the image size grows with each step. In my implementation, if a multiple rules apply to a tile, one of the rules is chosen at random.

Example nested tile rule:

example nested tiles rule set

Gallery of nested tile results:
nested tiles result nested tiles result nested tiles result nested tiles result nested tiles result nested tiles result nested tiles result (kinda looks like canvas)
(click on images to see full details)

Each of the previous images in the gallery started with the initial state of a single 1x1 image.

At the moment, I haven't heard of a image system like this, so if you know about one, please let me know. I think that this is a nice technique for making generative art. I plan on making a dedicated nested tiles page soon!

I plan on more updates to come

,

Rainy

Last summer, I wrote a poem while in Alaska, and I thought why not keep it online?

(August, 2021)

Rainy, rainy, wet and rainy
Dreary is this sky
So gray, oh what a shamey
It makes me want to cry

First pitter-patter, then spitter-spatter
Hail the cool drops from on high
Drip, drip, the wet beads chatter
We are the waters come dropping by.

Then muddy pond, this muddy muddle
That soggy flat ripples in the pour
A car goes by, steps in the puddle
The soak and splash for me a chore

In times like these, in pleas I ask
Who is thirsting for this old spray?
And in weather so, had I no task
I'd rest inside -- away from rainy day.

Page last updated on Thursday, 2025.02.20, 10:15:49 (GMT-7).