Skip to content

Commit

Permalink
Haskell implementation. Cabalized, too.
Browse files Browse the repository at this point in the history
  • Loading branch information
arirahikkala committed Sep 19, 2011
1 parent 2a11839 commit b7a458a
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
2 changes: 2 additions & 0 deletions haskell/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
52 changes: 52 additions & 0 deletions haskell/SimpleRL.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-- SimpleRL.cabal auto-generated by cabal init. For additional
-- options, see
-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.
-- The name of the package.
Name: SimpleRL

-- The package version. See the Haskell package versioning policy
-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
-- standards guiding when and how versions should be incremented.
Version: 0.1

-- A short (one-line) description of the package.
Synopsis: A simple roguelike

-- A longer description of the package.
-- Description:

-- The package author(s).
Author: Ari Rahikkala

-- An email address to which users can send suggestions, bug reports,
-- and patches.
Maintainer: ari.rahikkala@gmail.com

-- A copyright notice.
-- Copyright:

Category: Game

Build-type: Simple

-- Extra files to be distributed with the package, such as examples or
-- a README.
-- Extra-source-files:

-- Constraint on the version of Cabal needed to build this package.
Cabal-version: >=1.2


Executable SimpleRL
-- .hs or .lhs file containing the Main module.
Main-is: SimpleRL.hs

-- Packages needed in order to build this package.
Build-depends: base < 5, array == 0.*, hscurses == 1.*

-- Modules not exported by this package.
-- Other-modules:

-- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
-- Build-tools:

60 changes: 60 additions & 0 deletions haskell/SimpleRL.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module Main where

import UI.HSCurses.Curses
import Data.Array.IArray

type Coord = (Int, Int)

gameMap :: Array Coord Char
gameMap =
let xs = ["#### ####",
"# #### #",
"# #",
"## ##",
" # # ",
" # # ",
"## ##",
"# #",
"# #### #",
"#### ####"] in
listArray ((0, 0), (length (head xs) - 1, length xs - 1)) $ concat xs

-- note: Curses uses (y, x) addressing, going against all good sense, and the
-- first thing any self-respecting roguelike developer should do is write a
-- translation layer that returns sanity
-- also, Haskell's Char represent Unicode characters in an abstract manner;
-- passing through Enum probably isn't the cleanest way to convert them into
-- characters as understood by Curses, but it'll work within the 7-bit ASCII
-- range
renderAt :: Coord -> Char -> IO ()
renderAt (x, y) c =
mvAddCh y x (toEnum $ fromEnum c)

moveIfOk f c
| gameMap ! f c /= ' ' = c
| otherwise = f c

-- gameLoop takes the player's position as its only argument. In a more complex
-- roguelike, it would take a more complex /game state/ as its argument, or
-- equivalently be a computation in a state monad containing the game state.
gameLoop :: Coord -> IO ()
gameLoop playerPosition = do
mapM_ (\c -> renderAt c $ if c == playerPosition then '@' else gameMap ! c)
$ range $ bounds gameMap
refresh
key <- getCh
case key of
KeyLeft -> gameLoop $ moveIfOk (\(x, y) -> (x - 1, y)) playerPosition
KeyRight -> gameLoop $ moveIfOk (\(x, y) -> (x + 1, y)) playerPosition
KeyDown -> gameLoop $ moveIfOk (\(x, y) -> (x, y + 1)) playerPosition
KeyUp -> gameLoop $ moveIfOk (\(x, y) -> (x, y - 1)) playerPosition
KeyChar 'q' -> return ()
_ -> gameLoop playerPosition

main = do
scr <- initScr
keypad scr True
echo False
cursSet CursorInvisible
gameLoop (5, 5)
endWin

0 comments on commit b7a458a

Please sign in to comment.