Porting code example (Ruby to Elixir)

As you may know, I am slowly/painfully writing an Elixir book.

There is a code example that I’ve written in Ruby – a simple
robot-type “capture the flag” game. (Not a real game, just a
coding exercise.)

I’m about to port the Ruby code to Elixir. If anyone wants to
look/comment/help, please feel free. (Those who contribute
will be mentioned in the acknowledgements fwiw.)

This repo will be public for at least two days:

Thanks,
Hal

2 Likes
  1. Put *.beam in your .gitignore
  2. defstruct team: nil, kind: nil, move: nil, see: nil, ... could be written as defstruct [:team, :kind, :move, :see...]
  3. Use tuples is more idiomatic elixir instead of fixed sized lists e.g. in def get(grid, [:red, x, y])
3 Likes

Agreed and committed. Thank you!

Hl

I think you can refactor the show_cell function to remove the conditional and assignments.

   defmodule Grid do
      def show_cell(grid, xx, yy) do
        grid
        |> Grid.get({:red, xx, yy})
        |> Bot.to_string
        |> IO.write
      end
    end

defmodule Bot do
  def to_string(nil), do: "-"
end
1 Like

Also excellent ideas. Committed.

I think, defender, fighter, scout, flag and related behavior are good to demonstrate how to work with Elixir protocols.

Created first small PR. I will help you more today or/and in next days. This will depend on your response times and my free time :smile:

That is a good idea. I don’t think I’ll introduce protocols here at first, but I
could always refer back to the code later and show changes.

Hal

Merged. Appreciated. Just remember we may be in different time zones. :wink:

By the way The Ruby version is not “ideal” either. The non-threaded version is
easier to watch/understand, but the threaded one is a massive free-for-all, and I
am not sure how I want to fix it.

Hal

Yes I mean I will send PR if I find some time in same day you merged previous.
What does mean:

FIXME pieces[team] << bot

?
I do not see a pieces declaration in this file …
And this comment:

line 22

:smile:

Tip: here you have a tutorial about creating a command line application in Elixir.
I will create a next PR in current week (first version of this app that works from command line).

Hey, I added new PR.
I rewrite Elixir code to much some guidelines.
Now we have Agent that stores our game data, each bot have AI Erlang process (TODO: turn).
Your project is now really configurable. For example you can setup 2 to 4 teams with their colours and names dynamically.
I added some two dependencies bunt to easy format grid and credo to keep code readability.
Review my code and say if you don’t understand something. The code is not 10 lines, so bigger explanation may be really long. Let me know what you think about my version. If you accept it I will implement simple AI.
I wrote that I add this PR in current week, so it’s not complete yet (AI and credo checks).
Run code several times to see different results.

Tip: I created new modules inside Vexil module, because it’s not a “Hello World” tutorial and you are going to show good code example. In your old code you have for example: Grid module which may conflict in other projects if they organise code like you.

I need also write some tests.

Yeah, things like defmodule Grid do should be like defmodule Vexil.Grid do or so. Namespaces should always be used! :slight_smile:

There are several things I don’t understand yet about this.
Let’s talk more via email?

Namespacing is a good idea, yes.

Hal

No need private messages. It’s thread for your project. Feel free to ask :smile:

First, what is your reasoning for getting rid of modules such as Bot?

These modules are for defining structs by defstruct.
Here you have details about structs.
I think it’s best way to store data like that. Of course I can forgot about other things. Feel free to add propositions to my version of code.

I still don’t understand why you did away with the modules.
Where would you store functions that manipulate those structs?

The main module (to manage grid) is Vexil.Battleground. It stores grid in Vexil.Agent and have functions to manipulate this grid. For example to store Bot or Flag structure. I wrote some function and split this module to some imports, so:
Vexil.Battleground imports: Vexil.Battleground.TeamUtils. TeamUtils (like a normal team) imports Vexil.Battleground.BotUtils and Vexil.Battleground.FlagUtils and both of them imports Vexil.Battleground.GridUtils.
Note: in your Ruby code Flag extends Bot, so it can move(!). I think it’s not a good to read your Ruby code, because Flag will not move at all.
In my code FlagUtils imports only functions for calculate position based on corner and spawn item. Ok, but why it’s all for Battleground? It’s simple. Bot and Flag do not need to calculate position from corner. I think my version is easiest to understand (if you know how import works).
More, flag do not think and bot do not see full grid, so they should not calculate coords. I know it’s not a bug, but it’s not easy to read - am I wrong?

This seems reasonable. I will look at it further tonight. Thank you.