The canvas element gives you a rendering surface that you can access with JavaScript. There's many good tutorials on using the canvas element, I read Creating a Breakout Clone to understand what was going on.
Hopefully (assuming that I've put the script in correctly below), you should see a grid below. Clicking and dragging the mouse across the grid changes the state.
The JavaScript code to do this is available here. The idea is that when the user clicks a button on the JavaScript side, we'll package the grid up as a string, send it across to Haskell, get the data transformed, and send it back again. The first line sent from JavaScript contains the size of the grid; it's assumed to be square because that was easiest! The next line contains a complete dump of all the data in the grid.
if ('WebSocket' in window) {
ws = new WebSocket('ws://localhost:9876/');
ws.onopen = function() {
$('#connectionStatus').text('Connection opened');
}
ws.onclose = function() {
$('#connectionStatus').text('Connection closed');
}
ws.onmessage = function(evt) {
updateGrid(evt.data);
drawGrid();
return true;
}
}
$('#step').bind('click', function() { runStep(ws); });
function runStep(ws) {
var cells = '';
var pos = 0;
for (i=0;i<cellCount;++i) {
for (j=0;j<cellCount;++j) {
cells += grid[i][j];
}
}
ws.send(cellCount + '\n' + cells);
}
The first step on the Haskell side is to make something reusable from the code I had last time for the web element. This means exposing it as a module and separating out the logic for handling requests from server them. The complete code is here but the main changes are to make
acceptLoop
function accept an additional argument which handles communication back and forth.
module Web (serverListen, sendFrame, readFrame) where
acceptLoop :: Socket -> (Handle -> IO ()) -> IO a
acceptLoop socket f = forever $ do
(h,_,_) <- accept socket
hPutStr h serverHandshake
hSetBuffering h NoBuffering
forkIO (f h)
With this code we can now write a new web sockets server just by writing a small function to handle the sending and receviing of messages.
listenLoop :: Handle -> IO ()
listenLoop h = do
msg <- readFrame h
sendFrame h msg
listenLoop h
main :: IO ()
main = serverListen 9876 listenLoop
In the next post, I'll look at the game logic in Haskell.