Skip to content

Commit 1fed06e

Browse files
committed
Initial commit
Basic backend (without rotation) implemented. testsuite not completed yet.
1 parent 115ade6 commit 1fed06e

12 files changed

+310
-19
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.stack-work

LICENSE

+26-17
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
1-
MIT License
1+
Copyright Author name here (c) 2017
22

3-
Copyright (c) 2017 Fabian Geiselhart
3+
All rights reserved.
44

5-
Permission is hereby granted, free of charge, to any person obtaining a copy
6-
of this software and associated documentation files (the "Software"), to deal
7-
in the Software without restriction, including without limitation the rights
8-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9-
copies of the Software, and to permit persons to whom the Software is
10-
furnished to do so, subject to the following conditions:
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
117

12-
The above copyright notice and this permission notice shall be included in all
13-
copies or substantial portions of the Software.
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
1410

15-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Author name here nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
# Tetris
2-
(WIP) A SRS compatible version of Tetris. Written in Haskell.
1+
# tetris-hs

Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

app/Main.hs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module Main where
2+
3+
main :: IO ()
4+
main = do
5+
putStrLn "lol"

src/Tetris.hs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
module Tetris
2+
( newPiece
3+
, placePiece
4+
, shiftPieceDown
5+
, shiftPieceUp
6+
, shiftPieceRight
7+
, shiftPieceLeft
8+
)where
9+
10+
import Data.Matrix
11+
import System.Random
12+
import Tetris.Piece
13+
import Tetris.Color
14+
import Tetris.Field
15+
16+
{-| Place a new Piece on the field |-}
17+
newPiece :: Field -> IO (Either (Field, Fail) Field)
18+
newPiece f = do
19+
p <- randomIO :: IO Piece
20+
return (placePiece p f)
21+
22+
{-| place a piece on the field. Only for testing purposes |-}
23+
placePiece :: Piece -> Field -> Either (Field, Fail) Field
24+
placePiece p f =
25+
if isLost f
26+
then Left $ (f, GameLost)
27+
else Right $ Field (top <-> bottom) p (snd i) (fieldPoints f)
28+
where
29+
i = initial p
30+
old = fieldMatrix f
31+
top = extendTo Black 4 (ncols $ old) (fst i)
32+
bottom = submatrix 5 (nrows $ old) 1 (ncols $ old) old
33+
34+
{-| Check if game is lost |-}
35+
isLost :: Field -> Bool
36+
isLost f = any (/= Black) row
37+
where row = getRow 5 mat
38+
mat = fieldMatrix f
39+
40+
{-| Higher order shift function |-}
41+
shiftPiece :: (Int -> Int) -> (Int -> Int) -> Field -> Either (Field, Fail) Field
42+
shiftPiece rf cf f = if any (==True) $ map check l
43+
then Left (f, ShiftImpossible)
44+
else Right $ Field (modify m l)
45+
p
46+
(map (\(r,c) -> ((rf r), (cf c))) l)
47+
(fieldPoints f)
48+
where m = fieldMatrix f
49+
l = fieldPieceCoordinates f
50+
p = fieldPieceType f
51+
check (r,c) = getElem (rf r) (cf c) m /= Black
52+
modify mat [] = mat
53+
modify mat ((r,c):xs) = modify (setElem (color p) (r,c) mat) xs
54+
55+
{-| Shift piece down |-}
56+
shiftPieceDown :: Field -> Either (Field, Fail) Field
57+
shiftPieceDown = shiftPiece (subtract 1) id
58+
59+
{-| Shift piece left |-}
60+
shiftPieceLeft :: Field -> Either (Field, Fail) Field
61+
shiftPieceLeft = shiftPiece id (subtract 1)
62+
63+
{-| Shift piece right |-}
64+
shiftPieceRight :: Field -> Either (Field, Fail) Field
65+
shiftPieceRight = shiftPiece id (+1)
66+
67+
{-| Shift piece upwards. Only for testing purposes |-}
68+
shiftPieceUp :: Field -> Either (Field, Fail) Field
69+
shiftPieceUp = shiftPiece (+1) id
70+
71+
{-| Drop Piece to bottom |-}
72+
dropPiece :: Field -> Either (Field, Fail) Field
73+
dropPiece = undefined
74+
75+
{-| Rotate Piece couter-clockwise |-}
76+
rotatePieceCCW :: Field -> Either (Field, Fail) Field
77+
rotatePieceCCW = undefined
78+
79+
{-| Rotate Piece clockwise |-}
80+
rotatePieceCW :: Field -> Either (Field, Fail) Field
81+
rotatePieceCW = undefined

src/Tetris/Color.hs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module Tetris.Color
2+
(Color(..)
3+
) where
4+
5+
data Color = Red | Blue | Orange | Yellow | Magenta | Cyan | Green | Black
6+
deriving (Eq)
7+
8+
instance Show Color where
9+
show x =
10+
case x of
11+
Red -> "R"
12+
Blue -> "Blue"
13+
Orange -> "O"
14+
Yellow -> "Y"
15+
Magenta -> "M"
16+
Cyan -> "C"
17+
Green -> "G"
18+
Black -> "B"

src/Tetris/Field.hs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module Tetris.Field
2+
( Field(..)
3+
, Fail(..)
4+
, createField
5+
) where
6+
7+
import Data.Matrix
8+
import Tetris.Piece
9+
import Tetris.Color
10+
11+
data Fail = RotationImpossible
12+
| DropImpossible
13+
| ShiftImpossible
14+
| GameLost
15+
| Nothing
16+
deriving (Eq)
17+
18+
data Field = Field {
19+
fieldMatrix :: Matrix Color
20+
, fieldPieceType :: Piece
21+
, fieldPieceCoordinates :: [(Int, Int)]
22+
, fieldPoints :: Integer
23+
} deriving (Eq)
24+
25+
{-| Create a empty (all black) Field with 4 additional rows (b/c SRS)|-}
26+
createField :: Int -> Int -> Field
27+
createField x y = Field (matrix (x+4) y (\_ -> Black)) Empty [(-1,-1)] 0
28+

src/Tetris/Piece.hs

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module Tetris.Piece
2+
( Piece(..)
3+
, initial
4+
, color
5+
) where
6+
7+
import System.Random
8+
import Data.Matrix
9+
import Tetris.Color
10+
11+
data Piece = I | J | L | O | S | T | Z | Empty
12+
deriving (Show, Eq) -- TODO: Delete Show
13+
14+
color :: Piece -> Color
15+
color x = case x of
16+
I -> Red
17+
J -> Blue
18+
L -> Orange
19+
O -> Yellow
20+
S -> Magenta
21+
T -> Cyan
22+
Z -> Green
23+
Empty -> Black
24+
25+
26+
initial :: Piece -> (Matrix Color, [(Int, Int)])
27+
initial x = case x of
28+
I -> (fromLists [[Black,Black,Black,Black],
29+
[Red ,Red ,Red ,Red ],
30+
[Black,Black,Black,Black],
31+
[Black,Black,Black,Black]],
32+
[(2,1), (2,2), (2,3), (2,4)])
33+
J -> (fromLists [[Blue,Black,Black],
34+
[Blue,Blue,Blue],
35+
[Black,Black,Black]],
36+
[(1,1),(2,1),(2,2),(2,3)])
37+
L -> (fromLists [[Black,Black,Orange],
38+
[Orange,Orange,Orange],
39+
[Black,Black,Black]],
40+
[(1,3),(2,1),(2,2),(2,3)])
41+
O -> (fromLists [[Black,Yellow,Yellow,Black],
42+
[Black,Yellow,Yellow,Black],
43+
[Black,Black,Black,Black]],
44+
[(1,2),(1,3),(2,2),(3,2)])
45+
S -> (fromLists [[Black,Magenta,Magenta],
46+
[Magenta,Magenta,Black],
47+
[Black,Black,Black]],
48+
[(1,2),(1,3),(2,1),(2,2)])
49+
T -> (fromLists [[Black,Cyan,Black],
50+
[Cyan,Cyan,Cyan],
51+
[Black,Black,Black]],
52+
[(1,2),(2,1),(2,2),(2,3)])
53+
Z -> (fromLists [[Green,Green,Black],
54+
[Black,Green,Green],
55+
[Black,Black,Black]],
56+
[(1,1),(1,2),(2,2),(2,3)])
57+
Empty -> (fromLists [[Black]], [(-1,-1)])
58+
59+
instance Random Piece where
60+
randomR (lo,hi) g = -- TODO: randomR completely broken
61+
case (fst rnd) `rem` 7 of
62+
0 -> (I, snd rnd)
63+
1 -> (J, snd rnd)
64+
2 -> (L, snd rnd)
65+
3 -> (O, snd rnd)
66+
4 -> (S, snd rnd)
67+
5 -> (T, snd rnd)
68+
6 -> (Z, snd rnd)
69+
where rnd = next g
70+
71+
random = randomR (I,Z)

stack.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
flags: {}
2+
packages:
3+
- .
4+
extra-deps: []
5+
resolver: lts-9.9

test/Spec.hs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Test.QuickCheck
2+
import Tetris.Field
3+
import Tetris.Color
4+
5+
instance Arbitrary Field where
6+
arbitrary = do
7+
points <- elements [1..]
8+
rows <- elements [1..]
9+
columns <- elements [1..]
10+
piece <- choose (I,Z)
11+
pieceCoordinates
12+
13+
reversableActionProp :: (Field -> Either (Field, Fail) Field)
14+
-> (Field -> Either (Field, Fail) Field)
15+
-> Field
16+
-> Bool
17+
reversableActionProp f f' field = undefined
18+
where test = do
19+
f1 <- f field
20+
f2 <- f' field
21+
return ((f f2) == (f' f1))
22+
23+
main :: IO ()
24+
main = do
25+
putStr "Up / Down shifting: "
26+
quickCheck (reversableActionProp shiftPieceUp shiftPieceDown)
27+
28+
putStr "Left / Right shifting: "
29+
quickCheck (reversableActionProp shiftPieceLeft shiftPieceRight)

tetris.cabal

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: tetris
2+
version: 0.1.0.0
3+
license: BSD3
4+
license-file: LICENSE
5+
author: f4814n
6+
category: Terminal
7+
build-type: Simple
8+
extra-source-files: README.md
9+
cabal-version: >=1.10
10+
11+
library
12+
hs-source-dirs: src
13+
exposed-modules: Tetris
14+
, Tetris.Field
15+
, Tetris.Color
16+
, Tetris.Piece
17+
build-depends: base >= 4.7 && < 5
18+
, matrix
19+
, random
20+
ghc-options: -threaded -Wall
21+
default-language: Haskell2010
22+
23+
executable tetris-exe
24+
hs-source-dirs: app
25+
main-is: Main.hs
26+
ghc-options: -threaded -with-rtsopts=-N -Wall
27+
build-depends: base
28+
, tetris
29+
default-language: Haskell2010
30+
31+
test-suite tetris-test
32+
type: exitcode-stdio-1.0
33+
hs-source-dirs: test
34+
main-is: Spec.hs
35+
build-depends: base
36+
, tetris
37+
, QuickCheck
38+
ghc-options: -threaded -rtsopts -with-rtsopts=-N
39+
default-language: Haskell2010
40+
41+
source-repository head
42+
type: git
43+
location: https://github.com/FabianGeiselhart/Tetris

0 commit comments

Comments
 (0)