I have the following piece of code:

SetAttributes[createPlayers, HoldAll];
createPlayers[names__] :=
   players = 
    Table[numOfPlayers = i; 
     player[i] = {names}[[i]], {i, Length[{names}]}]);

createPlayers["Aron", "Geoff", "Steve"];

gameStats[stats__] :=
    Table[SymbolName[Unevaluated[{stats}]][[i]], {i, Length@{stats}}],
    Table[{stats}[[i]], {i, Length@{stats}}]
    }, Frame -> All];

gameStats[numOfPlayers, player[1], player[2], player[3]] // Dynamic

This does three tasks:

  1. A function to create as many players as required. These players' names can then be viewed with player[i]. The total number of players is also stored in the variable numOfPlayers.
  2. It creates three players by the names Aron, Geoff and Steve respectively.
  3. gameStats creates a grid displaying useful stats about the game.

Functions 1 and 2 work fine. I can't get function 3 to work though. What I am trying to get at is to display a grid with the symbol names in the top row, and their values in the bottom row - like so:

enter image description here

Instead the best I can do is this:

enter image description here

Either the top row displays the variables' values - which means that both top and bottom rows are the same - or it displays this error message. How can I get the top row to display the variables' symbol names properly?


You might try this:

SetAttributes[gameStats, HoldAll];
gameStats[stats__] := Grid[{List @@ HoldForm /@ Hold[stats], {stats}}, Frame -> All];
gameStats[numOfPlayers, player[1], player[2], player[3]]



You might also want to try this as well. It simplifies your code for createPlayers. First remove the line

SetAttributes[createPlayers, HoldAll];

from your code. You don't need that; you are only passing strings, which are atomic to the kernel. They can not be evaluated into anything else. Then evaluate the following definition.

createPlayers[args__String] :=
  Module[{names = {args}},
    players = Length @ names;
    Do[player[i] = names[[i]], {i, players}]]

Update 2

This is in response to a request for me to "explain what is going on behind the scenes and why this works?". I am assuming that it is the expression {List @@ HoldForm /@ Hold[stats], {stats}} that is causing confusion. To explain it, I will introduced a function f that deals with this expression alone, thus reducing the issue to its bare bones.

SetAttributes[f, HoldAll];
f[args__] := List[Apply[List, Map[HoldForm, Hold[args]]], List[args]]

I have written the above code in long form so that all the functions used are clearly visible. I have given f the HoldAll attribute because it will use args, the sequence of one more arguments passed to it, in both unevaluated and evaluated form.

Now let's use Trace to see what happens when f is evaluated with the argument sequence a, b, c, where a = 1,b = 2,c = 3`.

{a, b, c} = Range@3;
Trace[f[a, b, c]]
(* 1 *)  {f[a, b, c],
(* 2 *)  {{List @@ HoldForm /@ Hold[a, b, c], {a, b, c}},
(* 3 *)  {{{HoldForm /@ Hold[a, b, c], Hold[a, b, c]},
(* 4 *)   {List @@ Hold[a, b, c], {a, b, c}},
(* 5 *)  {{{a, 1}, {b, 2}, {c, 3}, {1, 2, 3}},
(* 6 *)  {{{a, b, c}, {1, 2, 3}}}

Here is step-by-step explanation of what Trace is telling us.

  1. The function call.
  2. The unevaluated argument sequences substituted in the expression in two places
  3. HoldForm is mapped over the arguments a, b, and c, giving Hold[HoldForm[a], HoldForm[a], HoldForm[a]]. We don't see HoldForm anymore because Mathematica's output printer makes it invisible. Recall that acting like Hold but being invisible on print-out is the whole purpose of HoldForm.
  4. Apply replaces Hold with List returning a list of variable names still wrapped in HoldForm.
  5. The 2nd element in the list (* 2 *) is now evaluated; each variable is evaluated here because they are naked -- no holding form protects them.
  6. The output expression (wrapped in a list by Trace}.
  • $\begingroup$ Hi @m_goldberg, thanks so much for this! I understand what you've done with the createPlayers function. However although the gameStats function also works perfectly, could you quickly explain what is going on behind the scenes and why this works? $\endgroup$ – Aron May 11 '14 at 15:00
  • 1
    $\begingroup$ For what it's worth: HoldForm /@ Unevaluated @ {stats} might be easier to understand. $\endgroup$ – Mr.Wizard May 11 '14 at 23:28
   Table[With[{x = x}, HoldForm[player[x]]], {x, 1, numOfPlayers}]],
  Join[{numOfPlayers}, Table[player[x], {x, 1, numOfPlayers}]]}, 
 Frame -> All]

enter image description here

Note that player is a symbol, not player[n].


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.