o
odinpkg.dev
packages / library / dice_algebra_calculator_odin

dice_algebra_calculator_odin

45f8f42library

A dice algebra expression parser & calculator written in Odin. Intended to be complex enough to learn a few things about Odin but simple enough to do in a short time.

No license · updated 5 days ago

Dice Algebra Calculator - Written in Odin

A dice algebra expression lexer, parser, & executor written in Odin.

The purpose of writing this application is to have fun trying out Odin by writing a simple application. A dice algebra calculator (including lexing, parsing, and execution of string expressions) was selected as something that is probably complex enough to be interesting yet is simple enough to do in an afternoon.

It's also something that can be extended later if that seems like it would be fun (e.g. this application could run a GUI window in which expressions can be input & a breakdown of the results can be shown, etc.).

And finally this is a project which can be done in any language, which allows comparing and constrasting (also fun).

The goal here is to write a program with source code which is as clean as possible (not an easy task without an old hand to ask questions to) and learn about tooling around the language.

What is "Dice Algebra?"

Dice algebra consists of simple mathematical expressions where operands may be a "dice roll."

A simple dice roll takes the format xdy (or xDy) where both x and y must be integers. xdy means that a y-sided die will be rolled x times. For example, 3d6 will roll a 6-sided die three times and sum the results.

The leading x may be omitted if it is 1. For example, d4 rolls a 4-sided die one time.

When rolling more than one die it is possible to keep only the lowest n rolls or the highest n rolls by appending ln or hn, respectively, to the roll. For example, 2d20h1 will roll two 20-sided dice and keep the highest result.

In addition to rolling dice, it is possible to include integers, addition +, subtraction -, multiplcation *, integer division /, and parenthetical expressions (...). For example, (2d6 + 5) * 10 will roll two 6-sided die, add five to that result, then mutiply that result by ten.

All integers must be positive (or 0).

ANTLR Grammar

The above dice algebra format can be expressed as the following ANTLR 4 grammar. This grammar is more-or-less what this application targets when parsing input.

grammar DiceAlgebra;

// Parser

add : mult (('+' | '-') mult)* ;
mult : atom (('*' | '/') atom)* ;
atom : (roll | '(' add ')') ;
roll : (integer | longroll | shortroll) ;
longroll : integer D integer ((H integer | L integer))? ;
shortroll : D integer ;
integer : NUMBER ;

// Lexer

WHITESPACE : ' ' -> skip ;
NUMBER : [0-9]+ ;
D : 'd' | 'D' ;
PLUS : '+' ;
MINUS : '-' ;
MULT: '*' ;
DIV : '/' ;
OPENPAREN : '(' ;
CLOSEPAREN : ')' ;
H : 'h' | 'H' ;
L: 'l' | 'L' ;

How to Run

The dice algebra calculator compiles to a CLI application binary. When the CLI is executed, it prompts the user for a dice algebra expression. Then it computes the expression and prints the result.

An example invocation looks like:

> ./dice_algebra_calculator
Please enter a dice algebra expression: 2d6 + 10

Your result is: 14

The binary may be invoked with the --v flag for verbose output (which prints all dice rolls):

> ./dice_algebra_calculator --v
Please enter a dice algebra expression: 2d6 + 10

Rolling 2d6...
You rolled: 3
You rolled: 1

Your result is: 14

How to Build Locally

To compile, run the following make command from the root directory of this repository.

make compile

This will create a dice_algebra_calculator executable in the repository root.

How to Run the Unit Tests Locally

To run the unit tests, run the following make command from the root directory of this repository.

make test

Retrospective Thoughts

I found Odin to be suprisingly productive. Compared to its closest peers in terms of features, C and Zig, it felt a lot easier to write. The level of productivity felt more similar to C++ than either of these two I would say. Considering the language syntax is pretty obviously inspired by Go, maybe this is because I write a lot of Go code. Or maybe it's just because this is the third of the three that I wrote this app with... I should probably find another "Hello, world" project.

It's unfortunate in my opinion that the author of Odin is a bit of a luddite in his attitude towards package managers. It would be great to see a go mod type tool for this language. With that said, Odin seems to be targeted particularly at game devs so perhaps this audience doesn't need a ton of library support (unlike us web devs who use massive libraries/frameworks like Spring Boot).

Given the above, for a small low-level project of the kind that might be written in C - Odin would be a top choice for me. Even if it won't be replacing Go/Java/Node/etc. in my day-to-day work anytime soon (which C++ could).

Ok, comparison time...

For lines of code - welp, looks like Odin didn't just feel concise - it was concise! It's second from the bottom and getting real close to edging out Rust.

Language Lines of Code
C 1456
Ada 734
C++ 716
Zig 701
Odin 581
Rust 568

For how pleasant each language feels to code, I'd rank them: Odin == C++ > Ada > Rust >> Zig >> C. Yeah... I write a lot of Go code. Two thoughts I had here are (1) I wonder if I should try Zig again after writing this to see if perhaps I feel differently about it now - and (2) I bet this ranking would change if I was writing a project complex enough to make OOP desirable.

In terms of how likely I would be to choose each language for an actual project, I'd rank them: C++ > Odin > Ada > Rust = Zig = C. Rust got edged out by Odin somehow, despite Rust being the more full-featured & popular language (+ it has more libraries & a package manager). Gotta love that Odin syntax I guess.