This may have been asked already, but I am considering making a game in Mathematica that two people can play. However, the issue with my idea is that the other player can't view the cards of the first player. Does anyone have any suggestions as to how I would tackle this problem? I would use two different computers, both with Mathematica installed.

  • $\begingroup$ this is far too vague. How are they communicating in the first place? $\endgroup$
    – george2079
    Commented Mar 14, 2014 at 14:59
  • $\begingroup$ That is my question. Is there any system in Mathematica that would allow two notebooks to communicate? @george2079 $\endgroup$ Commented Mar 14, 2014 at 15:22
  • 1
    $\begingroup$ @indiaash524 I've never used it, but you can read about MathLink in the docs and see if that's what you're looking for. Especially there is an article in the docs named "Using Mathlink to communicate between Mathematica sessions" $\endgroup$
    – C. E.
    Commented Mar 14, 2014 at 22:13
  • 2
    $\begingroup$ An example using MathLink is provided here for two Raspberry Pis. I think this question is interesting but too broad at the moment. $\endgroup$ Commented Mar 15, 2014 at 0:46

2 Answers 2


MathLink can be used to establish communication between two kernels on different machines using TCP/IP.

A basic example that illustrates the technique can be found in the Mathematica documentation.

The basic sequence of events is like this:

  1. The server creates an endpoint using LinkCreate.
  2. The client connects using LinkConnect.
  3. When one side wants to send a message to the other, it uses LinkWrite.
  4. Each side periodically polls to see whether the other has sent a message using LinkReadyQ. If it returns True, then the message can be read using LinkRead.

There are some gotchas to be aware of:

  • A client should write a message to the server immediately after connecting. This establishes the actual connection. Also, I have experienced erratic behaviour from LinkConnectedQ and LinkReadyQ until that first message arrives at the server. UPDATE @OleksandrR. points out that the undocumented function LinkActivate will correct this issue. See his discussion here.
  • On principle, I recommend reading incoming messages in held form using LinkRead[..., HoldComplete] and interpreting them using purpose-built code. If you simply evaluate the messages directly, it opens a window for a prankster (or worse) to execute arbitrary code on your machine.
  • During the initial debugging stage, it is easy for communicating programs to get out of synch with one another, resulting in hangs. Sometimes the kernel resists aborting or interrupting expressions when engaged in blocking I/O. I have found it useful to create buttons somewhere in a notebook that will close or interrupt the active link when pressed. The button actions run with a separate kernel link and can sometimes be helpful to forcibly terminate a cranky connection.
  • The link connection name needs to be communicated from the server to the client by some out-of-band means (e.g. the server player must tell/text/IM/email his chosen IP address and port to the client player).

The following (v9) code implements a toy one-line chat application for a client/server pair. First, a function to create the chat panel used by both sides:

chat[link_] :=
  DynamicModule[{button, tick=0, valid=True, ready, connected, in="", out=""}
  , button = Function[, Button[##, Enabled -> Dynamic[valid]], HoldAll]
  ; DynamicWrapper[
        { {"Link name:", Dynamic@If[valid, link[[1]], "Closed"]}
        , {"Tick:", Dynamic@tick}
        , {"Message:", Dynamic[in]}
        , {button["Send", LinkWrite[link, out]; out=""], InputField[Dynamic@out, String]}
        , {button["Close", LinkClose[link]]}
    , Refresh[
        tick += 1
      ; {valid, connected, ready} =
          Quiet @ Check[
            {True, LinkConnectedQ @ link, LinkReadyQ @ link}
          , {False, False, False}
      ; If[ready, in = LinkRead[link]]
      , If[valid, UpdateInterval -> 0, None]
      , TrackedSymbols :> {}

Next, a function to create a server-side chat panel that listens on a specified IP port:

chatServer[port_] :=
  chat @ LinkCreate[ToString@port, LinkProtocol -> "TCPIP"]

Finally, a function to create a client-side chat panel using the link name shown on the server's panel:

chatClient[linkName_] :=
  Module[{link = LinkConnect[linkName, LinkProtocol -> "TCPIP"]}
  , LinkActivate[link]
  ; chat[link]

The server creates his panel...

server panel screenshot

... then communicates the link name to the client by some means. Only the first part of the name needs to be communicated, [email protected] in the example. The client then uses this name to create his panel:

client panel screenshot

The two can then communicate until one of them presses the Close button.

The Tick field in this example simulates the background work performed by the game while waiting for communication from its peer. The code polls for messages as fast as possible, but this rate can be throttled by adjusting the UpdateInterval option to Refresh in chat.

As is customary in these toy examples, little attempt is made to recover from error conditions.

  • 3
    $\begingroup$ Regarding some of your "gotchas": I ran into these myself and discussed it here. John Fultz mentioned in response that the meaning of LinkConnectedQ/LinkReadyQ simply differs for the unconnected link--it tells you whether it is safe to try writing to the link or calling LinkActivate on it. $\endgroup$ Commented Mar 26, 2014 at 11:32
  • $\begingroup$ @OleksandrR. Thanks for that very useful information. I have updated my answer to incorporate it. $\endgroup$
    – WReach
    Commented Mar 26, 2014 at 13:05
  • $\begingroup$ Should the server side be client side in the line right above chatClient[..]:=? btw +1, very concise guide. $\endgroup$
    – Silvia
    Commented Apr 6, 2014 at 19:29
  • $\begingroup$ @Silvia Yes, corrected. Thanks. $\endgroup$
    – WReach
    Commented Apr 6, 2014 at 20:20
  • $\begingroup$ It just works in LAN... $\endgroup$
    – Apple
    Commented Aug 18, 2015 at 13:42

Thanks to the new Channel functionality in Mathematica 11, it is now easy to make (basic) multiplayer games with Mathematica!

To demonstrate, I'll modify my hex game from The Game of Hex in Mathematica. Start by copying all that code into a notebook and evaluate it. Then evaluate the following code:

boardClicked[{i_, j_}] := If[
  board[[i, j]] == 0 && currentPlayer == me,
  board[[i, j]] = me;
  currentPlayer = opponent;
  ChannelSend["test", {me, {i, j}}];

receiver::"hacks" = 
  "Incorrect/illegitmate message received, proceed with caution";

attomHACQ = Function[Null, TrueQ@AtomQ@Unevaluated@#, HoldAllComplete];

validHCMQ[hcm_] :=  
           {_Integer?attomHACQ, _Integer?attomHACQ}}];

receiver[m_] :=
 Module[{sender, i, j, hcm},
  hcm = m["Message"];
   {sender, {i, j}} = ReleaseHold[hcm];
   If[sender == opponent && currentPlayer == opponent, 
    board[[i, j]] = opponent;
    currentPlayer = me;]

$AllowExternalChannelFunctions = True;

listener = ChannelListen["test", receiver];

me = 1;
opponent = me /. {1 -> 2, 2 -> 1};
currentPlayer = 1;

board = ConstantArray[0, {11, 11}];
Dynamic[renderBoard[board], TrackedSymbols :> {board}]

Now, open another notebook and assign a different kernel to it. Evaluate the same code in the new notebook as for the first one, except set me = 2 instead of me = 1. The result should work like this:

Multiplayer demo

  • $\begingroup$ It looks like there's another thing I should become familiar with. :) $\endgroup$
    – rcollyer
    Commented Sep 4, 2016 at 1:13
  • $\begingroup$ I didn't think Mathematica would be a reasonable tool to use and build a version of Catan...seems I might have been wrong $\endgroup$
    – Sascha
    Commented Sep 4, 2016 at 8:57
  • $\begingroup$ @JacobAkkerboom Ops, fixed it now. $\endgroup$
    – C. E.
    Commented Sep 4, 2016 at 10:03
  • $\begingroup$ @C.E. I've edited the answer with a modified version of receiver that validates its input. Please roll back or do another edit if you don't like it. I think HoldComplete@System`DisableFormatting@patt can safely be replaced by _@_@patt if you find it too long. I figured I would explicitly add System`DisableFormatting because it is not in the System` context in a fresh kernel and failing to prefix it with System` gives a namespace error. $\endgroup$ Commented Sep 4, 2016 at 20:29
  • $\begingroup$ @JacobAkkerboom It's a good edit, showing how to match messages is useful also for cases where several different messages may be sent. $\endgroup$
    – C. E.
    Commented Sep 4, 2016 at 20:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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