Re: Idiomatic Erlang?

Stanislav Ledenev <[email protected]>
Newsgroups gmane.comp.lang.erlang.general
Message-ID <CAOkK=AJ71LYJLyR_GTbBONRrWZeM_-Jmc4Rwp2LnApHYS-oUGg@mail.gmail.com>
Idiomatic is quite a wide definition and depends what goal you are trying
to achieve.

You can write your combattables.erl many ways and it would be idiomatic in
some sense. For example like this:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clericdruidmonk0() -> { 20, 18, 16, 14, 12, 10, 9 }.
fighter0() -> { 20, 20, 18, 16, 14, 12, 10, 08, 06, 04 }.
magicuserillusionist0() -> { 20, 19, 16, 13, 11 }.
thiefassassin0() -> { 20, 19, 16, 14, 12, 10 }.
monster0() -> { 20, 20, 19, 18, 16, 15, 13, 12, 10, 9, 8, 7 }.
f0(Level) -> (Level+1) div 3.
f1(Level) -> ((Level+1) div 2)+1.
f2(Level) -> (Level+3) div 4.
f3(Level) -> (Level+4) div 5.
monster_offset(Level) ->
if
Level < 0.5 -> 0;
Level < 1 -> 1;
Level < 1.5 -> 2;
Level < 2 -> 3;
true -> ((Level) div 2) + 3
end.

basetohit(Class, Level, AC) ->
    M = #{
        cleric => {fun f0/1, fun clericdruidmonk0/0},
        druid => {fun f0/1, fun clericdruidmonk0/0},
        monk => {fun f0/1, fun clericdruidmonk0/0},
        fighter => {fun f1/1, fun fighter0/0},
        paladin => {fun f1/1, fun fighter0/0},
        thief => {fun f2/1, fun thiefassassin0/0},
        assasin => {fun f2/1, fun thiefassassin0/0},
        magicuser => {fun f3/1, fun magicuserillusionist0/0},
        illusionist => {fun f3/1, fun magicuserillusionist0/0},
        monster => {fun monster_offset/1, fun monster0/0}
    },
    {F, D} = maps:get(Class, M),
    element(F(Level), D()) - AC.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

or like this:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clericdruidmonk0() -> { 20, 18, 16, 14, 12, 10, 9 }.
fighter0() -> { 20, 20, 18, 16, 14, 12, 10, 08, 06, 04 }.
magicuserillusionist0() -> { 20, 19, 16, 13, 11 }.
thiefassassin0() -> { 20, 19, 16, 14, 12, 10 }.
monster0() -> { 20, 20, 19, 18, 16, 15, 13, 12, 10, 9, 8, 7 }.

get_level(cleric, Level) -> (Level+1) div 3;
get_level(druid, Level) -> (Level+1) div 3;
get_level(monk, Level) -> (Level+1) div 3;
get_level(fighter, Level) -> ((Level+1) div 2)+1;
get_level(paladin, Level) -> ((Level+1) div 2)+1;
get_level(thief, Level) -> (Level+3) div 4.;
get_level(assasin, Level) -> (Level+3) div 4;
get_level(magicuser, Level) -> (Level+4) div 5;
get_level(illusionist, Level) -> (Level+4) div 5;
get_level(monster, Level) ->
    if
        Level < 0.5 -> 0;
        Level < 1 -> 1;
        Level < 1.5 -> 2;
        Level < 2 -> 3;
        true -> ((Level) div 2) + 3
end.
% or
% get_level(monster, Level) when Level < 0.5 -> 0;
% get_level(monster, Level) when Level < 1 -> 1;
% get_level(monster, Level) when Level < 1.5 -> 2;
% get_level(monster, Level) when Level < 2 -> 3;
% get_level(monster, Level) -> ((Level) div 2) + 3.

get_values(cleric) -> clericdruidmonk0();
get_values(druid) -> clericdruidmonk0();
get_values(monk) -> clericdruidmonk0();
get_values(fighter) -> fighter0();
get_values(paladin) -> fighter0();
get_values(thief) -> thiefassassin0();
get_values(assasin) -> thiefassassin0();
get_values(magicuser) -> magicuserillusionist0();
get_values(illusionist) -> magicuserillusionist0();
get_values(monster) -> monster0().

basetohit(Class, Level, AC) ->
    element(get_level(Class, Level), get_values(Class)) - AC;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

пн, 26 июл. 2021 г. в 13:43, Benjamin Scherrey <[email protected]>:

> Been a couple of decades since I did any Erlang coding from scratch and it
> seems to have improved significantly (didn't have proper strings back then
> for example). I have a little hobby project I'm using to get myself up to
> snuff so I can do some more serious work for an upcoming project. Would
> appreciate some feedback regarding a few issues/questions. The code can be
> found at https://github.com/scherrey/dnderl .
>
> If you've ever played Advanced Dungeons & Dragons you'll recognize that
> this is a simple implementation of the THAC0 (to-hit armour class 0)
> concept from the original combat tables in the Dungeon Masters Guide. So 'combat:thac0(fighter,
> 5, 2).' would correctly tell you that your 5th level fighter needs to
> roll a 14 or higher on a 20-sided die to hit an armour class 2 opponent
> whereas 'combat:thac0(thief, 5, 2).' would tell you that a similar level
> thief requires a roll of 17 or better. Here are my questions:
>
> 1) My top level module is combat.erl (
> https://github.com/scherrey/dnderl/blob/master/combat.erl ). All it
> really does is introduce the class atom type and re-export
> combattables:basetohit/3 (albeit under a different name, thac0/3). Is it
> necessary to create a forwarding function like thac0/3 like I'm doing when
> I'd really just prefer to establish thac0/3 in the combattables module and
> re-export it from combat.erl? (Don't read anything into the different names
> - I just decided to rename it in the top level module because I liked it
> better and would be happy to use that same name throughout.) Attempting to
> re-export a function declared in another module gives me an error.
>
>
> 2) In combattables.erl (
> https://github.com/scherrey/dnderl/blob/master/combattables.erl ) I put
> monster_offset/1 as its own function because I couldn't figure out syntax
> for how to get the result of the if statement as an intermediate variable
> which I would have put inside the last basetohit/3 implementation. I tried
> several things but nothing that seemed correct to me would compile so I had
> to break it out into its own function. I feel like I'm missing something
> obvious but perhaps it's simply not allowed?
>
>
> 3) Is the way I've overloaded basetohit/3 with guards depending on which
> class is passed in the preferred idiomatic way to implement such a
> construct in Erlang? I thought of trying 'case' or 'if' but this seemed
> "cleanest" to me. I generally avoid if statements whenever possible in my
> other programming languages like C++ & Python. Appreciate any insights for
> such circumstances.
>
>
> 4) Is there no such thing as a module scope for a variable in Erlang? In
> combattables.erl I have 4 functions that return tuples representing the
> combat tables for each class. My initial thought was that they would be
> variables that could be referenced by any function in the module but that
> doesn't seem to work. The tuples in this case are constant lookup tables
> not to be updated. Am I doing this in the "correct" idiomatic manner for
> Erlang?
>
>
> thanks & best regards,
>
>  -- Ben Scherrey
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.