Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
    
this is far too vague. How are they communicating in the first place? –  george2079 Mar 14 at 14:59
    
That is my question. Is there any system in Mathematica that would allow two notebooks to communicate? @george2079 –  indiaash524 Mar 14 at 15:22
1  
@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" –  Pickett Mar 14 at 22:13
2  
An example using MathLink is provided here for two Raspberry Pis. I think this question is interesting but too broad at the moment. –  bobthechemist Mar 15 at 0:46

1 Answer 1

up vote 27 down vote accepted

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[
      Grid[
        { {"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, 8000@192.168.1.2 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.

share|improve this answer
3  
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. –  Oleksandr R. Mar 26 at 11:32
    
@OleksandrR. Thanks for that very useful information. I have updated my answer to incorporate it. –  WReach Mar 26 at 13:05
    
Should the server side be client side in the line right above chatClient[..]:=? btw +1, very concise guide. –  Silvia Apr 6 at 19:29
    
@Silvia Yes, corrected. Thanks. –  WReach Apr 6 at 20:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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