From 4bf167df5d0abee939bf3ebfa925c4fe22cd0502 Mon Sep 17 00:00:00 2001
From: Marcin Chrzanowski Merry Christmas to all!
-Advent of Code 2020 has come to an
-end. At the time of this writing, around seven thousand people finished the
-whole thing, out of the 150000 that had submitted a solution to the first day's
-problem. And I'm one of them!
-
-You can see my solutions here.
-I started out with C, moved on to Ruby, and near the end switched to Lua. I'm
-going to need some Lua knowledge for the Redis section of the databases class
-I'm taking right now, so AoC was a good time to get familiar with the language.
-
-I found most of the problems fairly simple, but it was fun to go through them
-all anyways.
-
-Day 20 Part 2. My solution ended up being a good 340 lines of Lua split
-between two scripts. This is the last problem I solved because I knew it would
-require a lot of work to get working, so I procrastinated on it until the end.
-
-In the end, the process of solving this was actually kind of fun, and getting
-the final solution satisfying. I think it might have something to do with the
-geometric/visual nature of the problem. There's just something nice about
-rotating and flipping ASCII squares with code, and seeing them all line up
-correctly in the end.
-
-Day 19 Part 2. Rather than implementing a parser generator that could
-handle this grammar by hand, I bodged together a
-
- Bison (aka Yacc) solution
-. It's not very pretty, especially the Bash script that just calls the
-parser with each input word separately and counts how many times it didn't exit
-with a syntax error. But it works! And I finally learned something about
-Bison/Yacc and Flex/Lex, which I've had indirect exposure to before, but never
-actually used.
-
-I was quite pleased with my Part 1 solution though, where I implemented a simple
-recursive parser generator.
-
-Day 13 Part 2. I'll admit it, I just copied a Chinese Remainder Theorem
-implementation from Rosetta Code. I'm sure the Python guys just used
-
-Probably a tie between the already mentioned Day 20 Part 2 and Day 19
-Part 1. Day 20 had that cool geometric component and satisfaction of
-putting a puzzle together, but I'm a sucker for recursive parsers implemented
-with higher order functions.
-
-Learning Lua was probably the most useful outcome of this year's AoC for me. I
-feel pretty comfortable with the basic constructs of the language, and even
-played around a bit with metatable-driven OOP. I don't know how closely I stuck
-to general conventions, and didn't interact with any external libraries, but can
-definitely read and write the language comfortably now.
-
-My one sentence summary of feelings towards Lua is that Go is to Java what Lua
-is to Python/Ruby/JavaScript. Its very small vocabulary means you learn the
-language quickly and don't need to think much while writing it, but your
-programs can end up more verbose than the equivalent Ruby/Python.
- Merry Christmas to all!
+Advent of Code 2020 has come to an
+end. At the time of this writing, around seven thousand people finished the
+whole thing, out of the 150000 that had submitted a solution to the first day's
+problem. And I'm one of them!
+
+You can see my solutions '>here.
+I started out with C, moved on to Ruby, and near the end switched to Lua. I'm
+going to need some Lua knowledge for the Redis section of the databases class
+I'm taking right now, so AoC was a good time to get familiar with the language.
+
+I found most of the problems fairly simple, but it was fun to go through them
+all anyways.
+
+Day 20 Part 2. My solution ended up being a good 340 lines of Lua split
+between two scripts. This is the last problem I solved because I knew it would
+require a lot of work to get working, so I procrastinated on it until the end.
+
+In the end, the process of solving this was actually kind of fun, and getting
+the final solution satisfying. I think it might have something to do with the
+geometric/visual nature of the problem. There's just something nice about
+rotating and flipping ASCII squares with code, and seeing them all line up
+correctly in the end.
+
+Day 19 Part 2. Rather than implementing a parser generator that could
+handle this grammar by hand, I bodged together a
+'>
+ Bison (aka Yacc) solution
+. It's not very pretty, especially the Bash script that just calls the
+parser with each input word separately and counts how many times it didn't exit
+with a syntax error. But it works! And I finally learned something about
+Bison/Yacc and Flex/Lex, which I've had indirect exposure to before, but never
+actually used.
+
+I was quite pleased with my Part 1 solution though, where I implemented a simple
+recursive parser generator.
+
+Day 13 Part 2. I'll admit it, I just copied a Chinese Remainder Theorem
+implementation from Rosetta Code. I'm sure the Python guys just used
+
+Probably a tie between the already mentioned Day 20 Part 2 and Day 19
+Part 1. Day 20 had that cool geometric component and satisfaction of
+putting a puzzle together, but I'm a sucker for recursive parsers implemented
+with higher order functions.
+
+Learning Lua was probably the most useful outcome of this year's AoC for me. I
+feel pretty comfortable with the basic constructs of the language, and even
+played around a bit with metatable-driven OOP. I don't know how closely I stuck
+to general conventions, and didn't interact with any external libraries, but can
+definitely read and write the language comfortably now.
+
+My one sentence summary of feelings towards Lua is that Go is to Java what Lua
+is to Python/Ruby/JavaScript. Its very small vocabulary means you learn the
+language quickly and don't need to think much while writing it, but your
+programs can end up more verbose than the equivalent Ruby/Python.
+
-To stay productive in the command line, I maintain a personal
-"cheatsheets" repository.
-There are many commands, or particular options of certain commands, that I don't
-use often enough for them to become muscle memory, but often enough for
-
-I can recommend following a similar practice to anyone, though I don't recommend
-using my cheatsheets. They are usually quick notes that follow my own mental
-shortcuts, and in general are optimized to be quickly understood by me,
-based solely on my past experiences with these tools. I won't include options
-that are already obvious to me (if you haven't used
-There are existing tools that aim to improve command line productivity in
-similar ways, like
-
-Now, for any new UNIX system I intend on spending a lot of time on, I'll
-
+To stay productive in the command line, I maintain a personal
+"cheatsheets" repository.
+There are many commands, or particular options of certain commands, that I don't
+use often enough for them to become muscle memory, but often enough for
+
+I can recommend following a similar practice to anyone, though I don't recommend
+using my cheatsheets. They are usually quick notes that follow my own mental
+shortcuts, and in general are optimized to be quickly understood by me,
+based solely on my past experiences with these tools. I won't include options
+that are already obvious to me (if you haven't used
+There are existing tools that aim to improve command line productivity in
+similar ways, like
+
+Now, for any new UNIX system I intend on spending a lot of time on, I'll
+
-I just published Hex Curler, a tiny dungeon crawler, based on Jeff Moore's
-Hex.
-
-You can play it by running the following in a bash shell:
-
-Thoughts on AoC 2020
-
-Most Tedious Award goes to...
-
-Most Cheesed Award goes to...
-Runner-up in the Most Cheesed category
-numpy
's CRT, so treating it as a library function doesn't seem too
-cheaty for me.
-Most Fun Award goes to...
-Thoughts on Lua
-Thoughts on AoC 2020
+
+Most Tedious Award goes to...
+
+Most Cheesed Award goes to...
+Runner-up in the Most Cheesed category
+numpy
's CRT, so treating it as a library function doesn't seem too
+cheaty for me.
+Most Fun Award goes to...
+Thoughts on Lua
+man
ning them or internet searching for "how do I resize an image with
-imagemagick" to become tedious.
-git add -p
or
-git rebase -i
, you should go learn about them!), and might instead
-include tools that are already a second language to you (any ffmpeg
-ninjas out there?).
-tldr
- or cheat
. For my
-personal workflow, I figured that there's no reason to overcomplicate things
-when tools I already have (vim
+ git
) do the job fine.
-git pull gitlab.com/m-chrzan/cheatsheets
in my home directory. When
-I want to remind myself of a command's use case, or have just figured out a new
-cool trick that I know I'm going to forget if I don't write it down, my notes
-are just a vim ~/ch<TAB> tool.md
away. If I do write any new
-tips down, a quick git push
allows me to keep the cheatsheets
-synced across all other systems.
-man
ning them or internet searching for "how do I resize an image with
+imagemagick" to become tedious.
+git add -p
or
+git rebase -i
, you should go learn about them!), and might instead
+include tools that are already a second language to you (any ffmpeg
+ninjas out there?).
+tldr
+ or cheat
. For my
+personal workflow, I figured that there's no reason to overcomplicate things
+when tools I already have (vim
+ git
) do the job fine.
+git pull gitlab.com/m-chrzan/cheatsheets
in my home directory. When
+I want to remind myself of a command's use case, or have just figured out a new
+cool trick that I know I'm going to forget if I don't write it down, my notes
+are just a vim ~/ch<TAB> tool.md
away. If I do write any new
+tips down, a quick git push
allows me to keep the cheatsheets
+synced across all other systems.
+
-c=x; while [ $c ]; do clear; curl -c k -b k hex.m-chrzan.xyz/$c; read c; done
-
-
-This was an exercise in minimalism. The game server is implemented in less than
-a thousand lines of Ruby code. It is completely stateless, requiring no
-database. The front end "client" is a single line of bash, less than 80
-characters long. The only dependency is curl
, a CLI tool already
-available on most Unix-like systems.
-
-The source code is available on -my GitLab. -
- --The whole concept arose from two ideas I had: - -
curl
and a simple web server could be used to create a
- simple remote CLI program.
- Engine
and a
-skeleton Sinatra app.
-
-
-
-To create a new "curling" system, you extend Engine
and implement
-four methods:
-
-
step
: performs a single step of the state-transition
- function.
- message
: outputs a message related to the most recent
- step
.
- hash_to_state
and state_to_hash
: these are
- just overhead glue methods. They should deserialize and serialize
- between your engine's internal state and a Ruby Hash
.
- secret
which is a string that is used to
-validate that a submitted cookie represents a valid state. More on this later.
-
-
--The Sinatra skeleton instantiates an engine with the received cookie, -runs a step, sends back the new state in the returned cookie, and responds with -the engine's message. The code for it fits in half of a browser window: - -
-require 'sinatra' -require 'sinatra/cookies' - -# exposes `Hex`, which extends `Engine`, implementing a simple dungeon crawler -require './hex_engine' - -def secret - # get secret from environment - ENV['HEX_SECRET'] -end - -get '/:command' do |command| - # `new` uses `hash_to_state` to initialize the engine's state - engine = Hex.new cookies.to_h - engine.step command - # `state_h` uses `state_to_hash` to serialize the engine's new state - engine.state_h.each_pair do |key, value| - cookies[key] = value - end - engine.message -end -- - -
-Hex Curler is hosted online but has no session management, no database. It's an -O(1) space webapp. -
- --As mentioned before, the game's state is stored in a cookie. The server need -only know the contents of that cookie to return a new state back to the user. -
- -
-To prevent a user from tampering with the cookie, for example by increasing
-their health to a ridiculous number, becoming invulnerable to enemies in Hex,
-the cookie also contains a checksum
field. This checksum is the
-hash of the state together with an appended secret only known by the game
-server. The server will refuse to respond to requests whose cookie does not have
-a valid checksum.
-
-This introduces some interesting possibilities. For example, let's say Alice -wants to boast to her friends about how she just beat Hex, ended with 100 HP -remaining, and had upgraded her magic armor to level 5. Her friend Bob doesn't -just have to take her word for it, or trust a screenshot that could have easily -been photoshopped. -
- --Alice can send Bob her state cookie. If a request to the game server with it -succeeds, Bob can be assured that he has cryptographic proof of Alice's -claims. -
diff --git a/src/blog/hex-curler.html.erb b/src/blog/hex-curler.html.erb new file mode 100644 index 0000000..f3da399 --- /dev/null +++ b/src/blog/hex-curler.html.erb @@ -0,0 +1,135 @@ +title: "Hex Curler: A Minimalist Webgame" +date: August 29, 2019 +--- ++I just published Hex Curler, a tiny dungeon crawler, based on Jeff Moore's +Hex. +
+ ++You can play it by running the following in a bash shell: + +
+c=x; while [ $c ]; do clear; curl -c k -b k hex.m-chrzan.xyz/$c; read c; done ++ + +
+This was an exercise in minimalism. The game server is implemented in less than
+a thousand lines of Ruby code. It is completely stateless, requiring no
+database. The front end "client" is a single line of bash, less than 80
+characters long. The only dependency is curl
, a CLI tool already
+available on most Unix-like systems.
+
+The source code is available '>here. +
+ ++The whole concept arose from two ideas I had: + +
curl
and a simple web server could be used to create a
+ simple remote CLI program.
+ Engine
and a
+skeleton Sinatra app.
+
+
+
+To create a new "curling" system, you extend Engine
and implement
+four methods:
+
+
step
: performs a single step of the state-transition
+ function.
+ message
: outputs a message related to the most recent
+ step
.
+ hash_to_state
and state_to_hash
: these are
+ just overhead glue methods. They should deserialize and serialize
+ between your engine's internal state and a Ruby Hash
.
+ secret
which is a string that is used to
+validate that a submitted cookie represents a valid state. More on this later.
+
+
++The Sinatra skeleton instantiates an engine with the received cookie, +runs a step, sends back the new state in the returned cookie, and responds with +the engine's message. The code for it fits in half of a browser window: + +
+require 'sinatra' +require 'sinatra/cookies' + +# exposes `Hex`, which extends `Engine`, implementing a simple dungeon crawler +require './hex_engine' + +def secret + # get secret from environment + ENV['HEX_SECRET'] +end + +get '/:command' do |command| + # `new` uses `hash_to_state` to initialize the engine's state + engine = Hex.new cookies.to_h + engine.step command + # `state_h` uses `state_to_hash` to serialize the engine's new state + engine.state_h.each_pair do |key, value| + cookies[key] = value + end + engine.message +end ++ + +
+Hex Curler is hosted online but has no session management, no database. It's an +O(1) space webapp. +
+ ++As mentioned before, the game's state is stored in a cookie. The server need +only know the contents of that cookie to return a new state back to the user. +
+ +
+To prevent a user from tampering with the cookie, for example by increasing
+their health to a ridiculous number, becoming invulnerable to enemies in Hex,
+the cookie also contains a checksum
field. This checksum is the
+hash of the state together with an appended secret only known by the game
+server. The server will refuse to respond to requests whose cookie does not have
+a valid checksum.
+
+This introduces some interesting possibilities. For example, let's say Alice +wants to boast to her friends about how she just beat Hex, ended with 100 HP +remaining, and had upgraded her magic armor to level 5. Her friend Bob doesn't +just have to take her word for it, or trust a screenshot that could have easily +been photoshopped. +
+ ++Alice can send Bob her state cookie. If a request to the game server with it +succeeds, Bob can be assured that he has cryptographic proof of Alice's +claims. +
-- cgit v1.2.3