Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

How tell if you can play a card with multi type 'Mana'

by Dr.Altaica (Scribe)
on Dec 26, 2019 at 21:27 UTC ( [id://11110637]=perlquestion: print w/replies, xml ) Need Help??

Dr.Altaica has asked for the wisdom of the Perl Monks concerning the following question:

HEllo I"m trying to program a TCG like game. I 'A' 'B' 'C' 'D' and 'AB', 'AC', 'AD', 'BC', 'BD' and 'CD' variables that hold how much 'Mana' they have of each type and you can use 'A', 'AB', 'AC', 'AD' to pay the 'A' cost to play the card and likewise for it's 'B', 'C' and 'D' costs. I've been trying to figure out a way to tell if you can play the card but just brute forcing and testing every combination with a if statements is the best I can think of. I'm betting their's some elegant solution to this problem. Can anyone think of it?
  • Comment on How tell if you can play a card with multi type 'Mana'

Replies are listed 'Best First'.
Re: How tell if you can play a card with multi type 'Mana'
by jcb (Parson) on Dec 26, 2019 at 23:43 UTC

    So each "mana" unit satisfies one or two types? Are the "mana" units also cards in the player's hand? I was considering a simple search over the player's "mana" hand, but I am unsure how to resolve a situation where the cost is satisfiable, but not with the most obvious match. It seems that backtracking is needed to solve this in general, which leads to a regex solution: (untested)

    sub can_play_card { my $cost = shift; # hashref of type => amount required my $mana = shift; # arrayref of mana types player holds my $pool = join '', map {printf "%2s", $_} sort @$mana; my $check = join '(?:..)*?', map {"(?:.$_|$_.)"} map {("$_") x $cost +->{$_}} sort keys %$cost; return $pool =~ m/$check/; }

    The "magic" — pardon the pun — relies on the pattern constructed for $check and the string in $pool: each available mana card takes up exactly two characters and each required mana matches exactly two characters, with one of them being the required type. The sets are sorted to ensure that ordering will not prevent a possible match from being found. If managing the different types is part of the game's strategy, you probably want to allow players to choose which mana to use to pay a card's cost — this function can determine both whether a player can possibly play a card and if a player's choices for mana to use when playing a card are valid, depending on whether you pass in all the mana cards the player holds or only the cards the player has selected to play.

Re: How tell if you can play a card with multi type 'Mana'
by roboticus (Chancellor) on Dec 27, 2019 at 04:30 UTC

    Dr.Altaica:

    You can do it by using a hash to represent the "cost" of the card/spell and use a hash with an identical structure to show the current resources for each player. As an example, suppose you defined your cards something like this:

    my @cards = ( { name => "Fireball", cost => { fire=>2, air=>1 }, # other card information... }, { name=>"Ice wall", cost=>{ water=>3, frost=>5 }, }, { name=>"Lightning bolt", cost=>{ air=>2, electricity=>4 }, }, );

    and your players were defined like:

    my @players = ( { name=>"Joe", mana =>{ fire=>5, air=>5, electricity=>5 }, # other information about player }, { name=>"Audrey", mana =>{ water=>5, frost=>10 }, }, );

    With this structure, each card has a "cost" hash and each player has a "mana" hash. All we need to do to find out if a player can cast a card, then, is to iterate over the resources the card requires and verify that the player *has* the resource, and if so, has *enough* of the resource. If any of the checks fail, the player can't cast the card, like this:

    sub can_cast { my ($rPlayer, $rCard) = @_; for my $manaType (keys %{$rCard->{cost}}) { return 0 if ! exists $rPlayer->{mana}{$manaType}; return 0 if $rPlayer->{mana}{$manaType} < $rCard->{cost}{$mana +Type}; } # Nothing rejected, so we can cast it! return 1; }

    So, putting it all together you'd get something like:

    $ cat mana.pl use strict; use warnings; my @cards = ( <<< snip >>> ); my @players = ( <<< snip >>> ); # Show which players can cast which spells for my $rPlayer (@players) { print "$rPlayer->{name} can cast: "; my $cnt=0; for my $rCard (@cards) { if (can_cast($rPlayer, $rCard)) { ++$cnt; print "$rCard->{name} "; } } if (!$cnt) { print "NOTHING!"; } print "\n"; } sub can_cast { <<<snip>>> } $ perl mana.pl Joe can cast: Fireball Lightning bolt Audrey can cast: Ice wall

    The trick that makes it work so easily is we structured the data to make the problem simple: Each card may have many attributes you want to describe, but we made the cost of the spell a smaller hash inside the card definition. Similarly, the players are going to have various data you care about, but their mana resources are segregated into a hash. That way, we can verify the presence and value of each key in the 'cost' hash against the related 'mana' hash in the player object, and we never have to write any code where we care about the number of mana types or even what there names are to see if we can cast it or not.

    I frequently use variations of this trick when programming: Choosing your data structures is every bit as important as writing your code. Do it well and things can be easy, do it poorly and your code can get ... difficult. ;^)

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      A hash! of course that would work so much better than 15 scalers... My brain was a bit fried from trying to think of how the algorithm should work.
Re: How tell if you can play a card with multi type 'Mana'
by bliako (Monsignor) on Dec 27, 2019 at 10:31 UTC

    I would understand more if you described this situation in more general terms. From what you described, a Tree with many branches at any node (n-ary tree) may be a suitable data structure to evaluate all scenaria at any depth you wish, given available resources. There are algorithms to find the route with the least cost. A hash (of hashes) can also be used but you will have to implement the search algorithms yourself. In a multi-player game such trees are used to enumerate all available moves/choices/scenaria by all the players at any depth (given resources!ouch!) Then winning the game is a matter of following the branches which minimise your costs (and maximise your opponents'), re: the minmax algorithm, assuming your opponents also make reasonable moves.

      after 3 days of struggling to write it manually I finally decided to write a script to write my program for me. I'm trying to learn Python so I can use PsychSim The more of python I learn the more I miss Perl. If there ware warnings my life would be so much easer. What I miss most is there's no 'PythonMonks'. If you want to look at my code it's on github
Re: How tell if you can play a card with multi type 'Mana'
by Anonymous Monk on Dec 26, 2019 at 21:30 UTC
    show us some code?
      Here you go it's pseudo code but something like this:
      sub testC(cost, 'AC'r, 'BC'r, 'CD'r){ ret=(); if(cost <= 'AC'r){ push(@ret,{'AC' => cost}); }else{ cost=cost-'AC'r; if(cost <= 'BC'r){ push(@ret,{'AC' => 'AC'r, 'BC' => cost}); }else{ cost=cost-'BC'r; if(cost <= 'CD'r){ push(@ret,{'AC' => 'AC'r, 'BC' => 'BC'r, 'CD' => cost} +); }; }; if(cost < 'BC'r){ push(@ret,{'BC' => cost}) }else{ cost=cost-'BC'r; if(cost <= 'AC'r){ push(@ret,{'AC' => cost, 'BC' => 'BC'r}); }else{ cost=cost-'AC'r; if(cost <= 'CD'r){ push(@ret,{'AC' => 'AC'r, 'BC' => 'BC'r, 'CD' => cost} +); }; }; if(cost < 'CD'r){ push(@ret,{'CD' => cost}) }else{ cost=cost-'CD'r; if(cost <= 'AC'r){ push(@ret,{'AC' => cost, 'CD' => 'CD'r}); }else{ cost=cost-'AC'r; if(cost <= 'BC'r){ push(@ret,{'AC' => 'AC'r, 'BC' => cost, 'CD' => 'CD'r} +); }; }; return(@ret) } ============= sub testB(cost, 'AB'r, 'BC'r, 'BD'r, ccost, 'AC'r, 'CD'r){ ret=(); if(cost <= 'AB'r){ @tail=testC(ccost, 'AC'r, 'BC'r, 'CD'r); foreach (x in @tail){ push(@ret,{({'AB' => cost}, %tail[x])}); }; }else{ cost=cost-'AB'r; if(cost <= 'BC'r){ @tail=testC(ccost, 'AC'r, 'BC'r-cost, 'CD'r); foreach (x in @tail){ if(defined $tail[x]{'BC'}){ cost += %tail[x]{'BC'}; delete($tail[x]{'BC'}); push(@ret,{({'AB' => 'AB'r, 'BC' => cost}, %tail[x +])}); }else; }; }else{ cost=cost-'BC'r; if(cost <= 'BD'r){ @tail=testC(ccost, 'AC'r, 0, 'CD'r); foreach (x in @tail){ push(@ret,{({'AC' => 'AC'r, 'BC' => 'BC'r, 'CD' => + cost}, %tail)}); }; }; }; }; #### if(cost <= 'BC'r){ @tail=testC(ccost, 'AC'r, 'BC'r-cost, 'CD'r); foreach (x in @tail){ if(defined $tail[x]{'BC'}){ cost += %tail[x]{'BC'}; delete($tail[x]{'BC'}); }; push(@ret,{({'AB' => 'AB'r, 'BC' => cost}, %tail[x])}) +; }; }else{ cost=cost-'BC'r; if(cost <= 'AB'r){ %tail=testC(ccost, 'AC'r, 0, 'CD'r); foreach (x in @tail){ push(@ret,{({'BC' => 'BC'r, 'AB' => cost}, %tail)}); }; }else{ cost=cost-'AB'r; if(cost <= 'BD'r){ %tail=testC(ccost, 'AC'r, 0, 'CD'r); foreach (x in @tail){ push(@ret,{({'BC' => 'BC'r, 'BD' => cost}, %tail)} +); }; }; }; }; #### if(cost < 'BD'r){ @tail=testC(ccost, 'AC'r, 'BC'r, 'CD'r); foreach (x in @tail){ push(@ret,{({'BD' => cost}, %tail[x])}); }; }else{ cost=cost-'BD'r; if(cost <= 'AB'r){ @tail=testC(ccost, 'AC'r, 'BC'r, 'CD'r); foreach (x in @tail){ push(@ret,{({'AB' => cost, 'BD' => 'BD'r}, %tail[x])}) +; }; }else{ cost=cost-'AB'r; if(cost <= 'BC'r){ foreach (x in @tail){ if(defined $tail[x]{'BC'}){ cost += %tail[x]{'BC'}; delete($tail[x]{'BC'}); }; push(@ret,{({'AC' => 'AC'r, 'BC' => cost, 'BD' + => 'BD'r}, %tail[x])}); }; }; }; }; } foreach tech in edeck: if(tech.cost.lust>(her.stat.lust-lustx)){ edeck.remove(tech) }; @tech[bills]=testB($tech[cost]['B']-'B'x, $her[stat]['AB'] +, $her[stat]['BC'], $her[stat]['BD'], $tech[cost]['C']-'C'x, $her[sta +t]['AC'], $her[stat]['CD']) if(@tech[bills] == 0 ){ edeck.remove(tech) }else{ }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11110637]
Approved by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (8)
As of 2024-04-18 15:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found