DEV Community

Cover image for Game::Terminal: Perl game implementations in a terminal
LNATION
LNATION

Posted on

Game::Terminal: Perl game implementations in a terminal

Recently I have been building https://peer2peergames.com, a site where two or more people play a board or card game against each other in a browser, each moving when they get round to it. Every game on it needs an engine: the rules, the endings, a bot to stand in when nobody else is online. So I wrote them, one dist at a time, each with the same discipline, the engine does no input and no output, a game is a pure function of its moves, and a terminal front end sits on top so I could play the thing before it had a web page. Cribbage was the one that existed before the site, everything after it was built for it.

That is how I have ended up with twenty plus terminal games and little memory of which script wanted which params.

So now I have one command.

$ cpanm Game::Terminal
$ game
Enter fullscreen mode Exit fullscreen mode

That gives you a menu. Arrow keys move, enter plays, q leaves, and a letter jumps to the next game starting with it. When the game you picked ends, win or lose or you ragequit, the menu is back with a line saying what happened.

Game                                                            21 games

 > backgammon  board  2    backgammon
   brandubh    board  2    the Irish 7 by 7 tafl game
   checkers    board  2    English draughts
   chess       board  2    chess
   cribbage    card   2    cribbage
   dominoes    tile   2-4  draw dominoes with All Fives scoring
   durak       card   2    Podkidnoy Durak, the Russian beating game
   fanorona    board  2    the board game of Madagascar
   floppy      arcade 1    a one-button bird through a field of tubes
   gin         card   2    gin rummy
   go          board  2    Go
   mahjong     tile   4    Mahjong, Chinese Official rules
   maze        puzzle 1    mazes in the terminal
   merrills    board  2    Nine Men's Morris
   oware       board  2    the African sow and capture game, Abapa rules
   reversi     board  2    Reversi, with its 1883 opening
   royalur     board  2    the Royal Game of Ur
   schnapsen   card   2    Schnapsen
   sixtysix    card   2    Sixty-Six, the German parent of Schnapsen
   snake       arcade 1    the classic snake game
   xiangqi     board  2    xiangqi, Chinese chess

backgammon: Game::Backgammon::Terminal 0.03, options: game backgammon --help
checkers finished with status 1 (lost)

up and down to choose, enter to play, a letter to jump, q to quit
Enter fullscreen mode Exit fullscreen mode

Yes, that last line of status is real. The checkers bot is not kind at level 4.

How it works

The obvious way to build a launcher is to exec the installed scripts. I did not do that, and the reason is the menu: I wanted it to come back when a game ends, and I wanted that to work the same on every platform without a shell in the loop.

So every game now has a class method with one boring, binding promise:

my $status = Game::Checkers::Terminal->run(@ARGV);
Enter fullscreen mode Exit fullscreen mode

It parses its own options from the array it is given, plays, and returns the exit status: 0 if you won, drew or quit, 1 if you lost, 2 for a bad option. It never calls exit. Each game's bin/ script is now two lines, use and exit ...->run(@ARGV), and the launcher just requires the class and calls the same method in its own process.

If you have a terminal game of your own and you want it in the menu, that run contract is the whole price of admission. Return the status, do not exit, take your arguments as a list. The roster is data; adding a row is a pull request though.

Where this is going

The terminal is one skin over these engines. The other as mentioned is the one they were written for https://peer2peergames.com.

A mobile app for peer2peergames is in development and coming soon. Same games, same engines.

Until then, cpanm Game::Terminal installs all twenty one games.

Top comments (0)