diff options
-rw-r--r-- | src/blog/hex-curler.html | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/blog/hex-curler.html b/src/blog/hex-curler.html new file mode 100644 index 0000000..8f5f1c6 --- /dev/null +++ b/src/blog/hex-curler.html @@ -0,0 +1,136 @@ +title: "Hex Curler: A Minimalist Webgame" +date: August 29, 2019 +--- +<p> +I just published Hex Curler, a tiny dungeon crawler, based on Jeff Moore's +<a href='http://www.1km1kt.net/rpg/hex'>Hex</a>. +</p> + +<p> +You can play it by running the following in a bash shell: + +<pre> +c=x; while [ $c ]; do clear; curl -c k -b k hex.m-chrzan.xyz/$c; read c; done +</pre> +</p> + +<p> +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 <code>curl</code>, a CLI tool already +available on most Unix-like systems. +</p> + +<p> +The source code is available <a href='https://gitlab.com/m-chrzan/hex-curler'>on +my GitLab</a>. +</p> + +<h3>Let's get curling</h3> +<p> +The whole concept arose from two ideas I had: + +<ul> + <li> + <code>curl</code> and a simple web server could be used to create a + simple remote CLI program. + </li> + <li> + For a webapp that implements a simple state-transition system (like a + simple game), one could forget about session management and a database, + and just store the state client-side in a cookie. + </li> +</ul> + +I abstracted these ideas away into a Ruby class called <code>Engine</code> and a +skeleton Sinatra app. +</p> + +<p> +To create a new "curling" system, you extend <code>Engine</code> and implement +four methods: + +<ul> + <li> + <code>step</code>: performs a single step of the state-transition + function. + </li> + <li> + <code>message</code>: outputs a message related to the most recent + <code>step</code>. + </li> + <li> + <code>hash_to_state</code> and <code>state_to_hash</code>: these are + just overhead glue methods. They should deserialize and serialize + between your engine's internal state and a Ruby <code>Hash</code>. + </li> +</ul> + +You also need to define a <code>secret</code> which is a string that is used to +validate that a submitted cookie represents a valid state. More on this later. +</p> + +<p> +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: + +<pre> +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 +</pre> +</p> + +<h3><em>O</em>(1) space webapp</h3> +<p> +Hex Curler is hosted online but has no session management, no database. It's an +<em>O</em>(1) space webapp. +</p> + +<p> +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. +</p> + +<p> +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 <code>checksum</code> 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. +</p> + +<p> +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. +</p> + +<p> +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. +</p> |