summaryrefslogtreecommitdiffstats
path: root/libksirtet/base/gtetris.h
blob: 48aefb9df07674a0a4a8c4b2acecf81aafc5c9d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/****************************************************************************
**
** Definition of GenericTetris, a generic class for implementing Tetris.
**
** Author   : Eirik Eng
** Created  : 940126
** Modified by Nicolas Hadacek
**
** Copyright (C) 1994 by Eirik Eng. All rights reserved.
**
**---------------------------------------------------------------------------
**
** The GenericTetris class is an abstract class that can be used to implement
** the well known game of Tetris. It is totally independent of any hardware
** platform or user interface mechanism. It has no notion of time, so you
** have to supply the timer ticks (or heartbeat) of the game. Apart from
** that this is a complete Tetris implementation.
**
** In the following it is assumed that the reader is familiar with the game
** of Tetris.
**
** The class operates on a grid of squares (referred to as the "board" below),
** where each of the different types of pieces in Tetris covers 4 squares. The
** width and height of the board can be specified in the constructor (default
** is 10x22). The coordinate (0,0) is at the TOP LEFT corner. The class
** assumes that it has total control over the board and uses this to optimize
** drawing of the board. If you need to update parts of the board
** (e.g. if you are using a window system), use the updateBoard() function.
**
** An implementation of the game must subclass from TetrisBoard and must
** implement these abstract functions:
**
**     virtual void drawSquare(int x,int y,int value)
**
**        This function is called when a square needs to be drawn
**        on the Tetris board. A value of 0 means that the square
**        should be erased. Values of 1 to 7 indicate the different
**        types of pieces. (Thus a minimal implementation can
**        draw 0 in one way and 1-7 in a second way). The x and y
**        values are coordinates on the Tetris board (see above).
**
**    virtual void gameOver()
**
**        This function is called when it is impossible to put a new
**        piece at the top of the board.
**
** To get a working minimal implementation of Tetris the following functions
** must be called from the user interface:
**
**     void startGame()
**
**         Clears the board and starts a new game.
**
**    void moveLeft()
**    void moveRight()
**    void rotateLeft()
**    void rotateRight()
**
**        The standard Tetris controls for moving and rotating the
**        falling pieces.
**
**    void dropDown();
**
**        Another Tetris control, drops the falling piece and calls the
**        virtual function pieceDropped(), whose default implementation is
**        to create a new block which appears at the top of the board.
**
**    void oneLineDown();
**
**        This is where you supply the timer ticks, or heartbeat, of the
**        game. This function moves the current falling piece one line down
**        on the board, or, if that cannot be done, calls the virtual
**        function pieceDropped() (see dropDown() above). The time between
**        each call to this function directly affects the difficulty of the
**        game. If you want to pause the game, simply block calls to the
**        user control functions above and stop calling this function (you
**        might want to call hideBoard() also).
**
** And that's it! There are several other public functions you can call
** and virtual functions you can overload to modify or extend the game.
**
** Do whatever you want with this code (i.e. the files gtetris.h,
** gtetris.cpp, tpiece.h and tpiece.cpp). It is basically a weekend hack
** and it would bring joy to my heart if anyone in any way would find
** it useful.
**
** Nostalgia, comments and/or praise can be sent to: Eirik.Eng@troll.no
**
****************************************************************************/

#ifndef GTETRIS_H
#define GTETRIS_H

#include <qpoint.h>

#include <krandomsequence.h>
#include <kgrid2d.h>

#include <kdemacros.h>

class Piece;
class BlockInfo;
class Block;

struct GTInitData {
    int  seed;
    uint initLevel;
};

class KDE_EXPORT GenericTetris
{
 public:
    GenericTetris(uint width, uint height, bool withPieces, bool graphic);
    virtual ~GenericTetris();
    virtual void copy(const GenericTetris &);

    void setBlockInfo(BlockInfo *main, BlockInfo *next);
    virtual void start(const GTInitData &);

    uint moveLeft(int steps = 1)  { return moveTo(KGrid2D::Coord(-steps, 0)); }
    uint moveRight(int steps = 1) { return moveTo(KGrid2D::Coord(steps, 0)); }
    bool rotateLeft()             { return rotate(true); }
    bool rotateRight()            { return rotate(false); }
    virtual void oneLineDown();
    virtual void dropDown();

    KRandomSequence &randomSequence() { return _random; }
    uint score() const          { return _score; }
    uint level() const          { return _level; }
    uint nbClearLines() const   { return _nbClearLines; }
    uint nbRemoved() const      { return _nbRemoved; }
    bool graphic() const        { return _graphic; }
    uint firstClearLine() const { return _matrix.height() - _nbClearLines; }
    const KGrid2D::Coord &currentPos() const { return _currentPos; }
    const Piece *nextPiece() const    { return _nextPiece; }
    const Piece *currentPiece() const { return _currentPiece; }
    const KGrid2D::Square<Block *> &matrix() const { return _matrix; }

 protected:
    Piece           *_nextPiece, *_currentPiece;
 
    virtual void pieceDropped(uint /*dropHeight*/) {}
    virtual bool newPiece(); // return false if cannot place new piece
    virtual void gluePiece();
    virtual void computeInfos();

    virtual void updateRemoved(uint newNbRemoved) { _nbRemoved = newNbRemoved;}
    virtual void updateScore(uint newScore)       { _score = newScore; }
    virtual void updateLevel(uint newLevel)       { _level = newLevel; }

    void setBlock(const KGrid2D::Coord &, Block *);
    virtual void removeBlock(const KGrid2D::Coord &);
    void moveBlock(const KGrid2D::Coord &src, const KGrid2D::Coord &dest);

    virtual void updateNextPiece()   {}
    virtual void updatePieceConfig() {}
    void bumpCurrentPiece(int dec);
    void partialMoveBlock(const KGrid2D::Coord &, const QPoint &dec);

 private:
    QPoint toPoint(const KGrid2D::Coord &) const;
    uint moveTo(const KGrid2D::Coord &dec);
    bool rotate(bool left);
    void clear();
    bool canPosition(const KGrid2D::Coord &newPos, const Piece *newPiece) const;

    GenericTetris(const GenericTetris &); // disabled

    uint             _score, _level, _nbRemoved;
    uint             _nbClearLines, _initLevel;
    KGrid2D::Coord    _currentPos;
    BlockInfo       *_main;
    bool             _graphic;
    KGrid2D::Square<Block *> _matrix;
    KRandomSequence  _random;
};

#endif