
Dung-beetle style development - The feeling you get working on a code base where each change feels like pushing an ever bigger ball of crap.
A phrase I remembered from working with Roly that made me laugh!

data Cell = Off
| On
| Dying
deriving (Eq,Show)
type GameGrid = Array (Int,Int) Cell
type Neighbours = [Cell]
data Game = Game GameGrid Int deriving Show
type is just used to give friendly names to types so I don't forget what they are!cellToChar I'm sure there must be a way of encoding this information so that I don't have to explictly write out each case? I realise I could define Cell as type data Cell = State Char, but that still doesn't feel write as it's only for three specific instances of Char. Anyway!cellToChar :: Cell -> Char
cellToChar Off = '0'
cellToChar On = '1'
cellToChar Dying = '2'
charToCell :: Char -> Cell
charToCell '0' = Off
charToCell '1' = On
charToCell '2' = Dying
charToCell _ = error "Undefined character received"
createGame :: Int -> [Cell] -> Game
createGame x c = Game (listArray ((0,0),(x-1,x-1)) c) x
gridToString :: Game -> String
gridToString (Game g _) = map cellToChar (elems g)
processMessage :: String -> String
processMessage s = map cellToChar newGrid where
[cellSizeStr,original] = lines s
cells = map charToCell original
cellSize = read cellSizeStr :: Int
newGrid = step (createGame cellSize cells)
listenLoop :: Handle -> IO ()
listenLoop h = do
msg <- readFrame h
sendFrame h (processMessage msg)
listenLoop h
main :: IO ()
main = serverListen 9876 listenLoop
rules :: Cell -> Neighbours -> Cell
rules On _ = Dying
rules Off cells | length (filter (/= Off) cells) == 2 = On
| otherwise = Off
rules Dying _ = Off
neighbours by assuming it wraps around. neighbours :: Game -> (Int,Int) -> Neighbours
neighbours (Game c s) (x,y) = [c ! ((x+dx) `mod` s, (y+dy) `mod` s)
| dx <- [-1,0,1], dy <- [-1,0,1], dx /= dy]
step :: Game -> [Cell]
step g@(Game c s) = [ rules (c ! p) (neighbours g p) | p <- coords] where
coords = [(x,y) | x <- [0..(s-1)], y <- [0..(s-1)]]
ffmpeg you can create a video like this (assuming your files are named 001.jpg, 002.jpg and so on).
ffmpeg -r 3 -b 1800 -i %03d.jpg output.mp4
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);
}
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)
listenLoop :: Handle -> IO ()
listenLoop h = do
msg <- readFrame h
sendFrame h msg
listenLoop h
main :: IO ()
main = serverListen 9876 listenLoop
hGetContents and just read off one message at a time. This is doomed to failure because laziness and hanging around on a network socket that's in a semi-closed state just isn't going to work.Control.Monad.when)
listenLoop :: Handle -> IO ()
listenLoop h = do
sendFrame h "hi, remember you can stop this at anytime by pressing quit!"
msg <- readFrame h
putStrLn msg
when (msg /= "quit") (listenLoop h)
readFrame :: Handle -> IO String
readFrame h = readUntil h ""
where
readUntil h str = do
new <- hGetChar h
if (new == chr 0)
then readUntil h ""
else if new == chr 255
then return str
else readUntil h (str ++ [new])
ws object has the appropriate scope!
<body>
<h1>I'm doing something</h1>
<div id="output">
</div>
<div id="connectionStatus">
</div>
<textarea rows="2" cols="80" id="message">
Type whatever you want here, but type quit to close the connection
</textarea>
<br />
<button id="clickMe" onClick="ws.send($('#message').val());">
Click me!
</button>
</body>
/etc/apache2/sites-available/default and make it point to the appropriate place (or copy it and create your own configuration). Apache can be restarted with apache2ctl restart.
import Network
import System.IO
import Control.Concurrent
import Char
serverHandshake =
"HTTP/1.1 101 Web Socket Protocol Handshake\r\n\
\Upgrade: WebSocket\r\n\
\Connection: Upgrade\r\n\
\WebSocket-Origin: http://localhost\r\n\
\WebSocket-Location: ws://localhost:9876/\r\n\
\WebSocket-Protocol: sample\r\n\r\n"
acceptLoop socket = forever $ do
(h,_,_) <- accept socket
hPutStr h serverHandshake
hSetBuffering h NoBuffering
forkIO (listenLoop h)
where
forever a = do a; forever a
main = withSocketsDo $ do
socket <- listenOn (PortNumber 9876)
acceptLoop socket
sClose socket
return ()
listenLoop :: Handle -> IO ()
listenLoop h = do
sendFrame h "hello from haskell"
threadDelay (3 * 1000000)
sendFrame h "it works!"
return ()
sendFrame :: Handle -> String -> IO ()
sendFrame h s = do
hPutChar h (chr 0)
hPutStr h s
hPutChar h (chr 255)
forkIO makes handling the socket on a separate thread trivial, it spawns off a new lightweight thread (lightweight in the sense of being very cheap to create) to handle the IO processing.
<html>
<head>
<title>Web Sockets</title>
<script src="http://www.google.com/jsapi"></script>
<script>
google.load('jquery','1.3.2');
</script>
<script>
$(document).ready(function() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://localhost:9876/");
ws.onopen = function() {
$('#connectionStatus').text('Connection opened');
};
ws.onmessage = function(evt) {
$('#output').append('<p>' + evt.data);
};
ws.onclose = function() {
$('#connectionStatus').text('Connection closed');
};
}
else {
$('#connectionStatus').append('<p>Your browser does not support web sockets</p>');
}
});
</script>
</head>
<body>
<h1>I'm doing something</h1>
<div id="output">
</div>
<div id="connectionStatus">
</div>
</body>
</html>