-
Notifications
You must be signed in to change notification settings - Fork 3
/
Seed7 2048.sd7
190 lines (181 loc) · 6.14 KB
/
Seed7 2048.sd7
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
179
180
181
182
183
184
185
186
187
188
189
190
$ include "seed7_05.s7i";
include "console.s7i";
include "keybd.s7i";
const integer: boardLength is 4;
const integer: boardSize is boardLength * boardLength;
const integer: target is 2048;
const type: stateType is new struct
var integer: fieldsOccupied is 0;
var integer: largestNumber is 0;
var integer: score is 0;
var array array integer: board is boardLength times boardLength times 0;
end struct;
const proc: addTile (inout stateType: state) is func
local
var integer: row is 0;
var integer: col is 0;
var integer: field is 2;
begin
if state.fieldsOccupied < boardSize then
repeat
col := rand(1, boardLength);
row := rand(1, boardLength);
until state.board[row][col] = 0;
if rand(1, 10) = 10 then
field := 4;
end if;
state.board[row][col] := field;
incr(state.fieldsOccupied);
state.largestNumber := max(field, state.largestNumber);
end if;
end func;
const proc: showBoard (in stateType: state) is func
local
var integer: row is 0;
var integer: field is 0;
begin
writeln("┌────┬────┬────┬────┐");
for key row range state.board do
for field range state.board[row] do
if field = 0 then
write("│ ");
else
write("│" <& field lpad (5 + length(str(field))) div 2 rpad 4);
end if;
end for;
writeln("│");
if row < maxIdx(state.board) then
writeln("├────┼────┼────┼────┤");
end if;
end for;
writeln("└────┴────┴────┴────┘");
end func;
const func boolean: doMove (inout stateType: state, in integer: startRow,
in integer: startCol, in integer: deltaRow, in integer: deltaCol, in boolean: doMerge) is func
result
var boolean: boardChanged is FALSE;
local
const set of integer: boardRange is {1 .. boardLength};
var integer: row is 1;
var integer: col is 1;
var integer: nextRow is 0;
var integer: nextCol is 0;
begin
row := startRow;
col := startCol;
while row in boardRange and col in boardRange do
while row in boardRange and col in boardRange do
nextRow := row + deltaRow;
nextCol := col + deltaCol;
if state.board[row][col] = 0 and
nextRow in boardRange and nextCol in boardRange and
state.board[nextRow][nextCol] <> 0 then
boardChanged := TRUE;
state.board[row][col] := state.board[nextRow][nextCol];
state.board[nextRow][nextCol] := 0;
if row - deltaRow in boardRange and col - deltaCol in boardRange then
nextRow := row - deltaRow;
nextCol := col - deltaCol;
end if;
end if;
row := nextRow;
col := nextCol;
end while;
if doMerge then
if deltaRow <> 0 then
row := startRow;
elsif deltaCol <> 0 then
col := startCol;
end if;
while row in boardRange and col in boardRange do
nextRow := row + deltaRow;
nextCol := col + deltaCol;
if state.board[row][col] <> 0 and
nextRow in boardRange and nextCol in boardRange and
state.board[nextRow][nextCol] = state.board[row][col] then
boardChanged := TRUE;
state.board[row][col] *:= 2;
state.largestNumber := max(state.board[row][col], state.largestNumber);
state.score +:= state.board[row][col];
state.board[nextRow][nextCol] := 0;
decr(state.fieldsOccupied);
end if;
row := nextRow;
col := nextCol;
end while;
end if;
if deltaRow = 0 then
incr(row);
col := startCol;
elsif deltaCol = 0 then
incr(col);
row := startRow;
end if;
end while;
if doMerge and boardChanged then
ignore(doMove(state, startRow, startCol, deltaRow, deltaCol, FALSE));
end if;
end func;
const func boolean: canMove (in stateType: state) is func
result
var boolean: canMove is FALSE;
local
var integer: row is 0;
var integer: col is 0;
begin
for row range 1 to boardLength until canMove do
for col range 1 to boardLength until canMove do
canMove := state.board[row][col] = 0 or
(row < boardLength and state.board[row][col] = state.board[succ(row)][col]) or
(col < boardLength and state.board[row][col] = state.board[row][succ(col)]);
end for;
end for;
end func;
const proc: main is func
local
var stateType: state is stateType.value;
var integer: highscore is 0;
var char: command is ' ';
var boolean: quit is FALSE;
var boolean: moveOkay is FALSE;
begin
OUT := open(CONSOLE);
addTile(state);
repeat
setPos(STD_CONSOLE, 1, 1);
showBoard(state);
highscore := max(highscore, state.score);
writeln("Score = " <& state.score <& " Highscore = " <& highscore);
if canMove(state) and state.largestNumber < target then
writeln("Press arrow keys to move, R to Restart, Q to Quit");
elsif state.largestNumber >= target then
writeln("You win! Press R to Restart, Q to Quit ");
else
writeln("Game over! Press R to Restart, Q to Quit ");
end if;
repeat
moveOkay := FALSE;
command := getc(KEYBOARD);
case command of
when {'r', 'R'}:
state := stateType.value;
clear(STD_CONSOLE);
moveOkay := TRUE;
when {'q', 'Q'}:
moveOkay := TRUE;
quit := TRUE;
when {KEY_LEFT}:
moveOkay := doMove(state, 1, 1, 0, 1, TRUE);
when {KEY_RIGHT}:
moveOkay := doMove(state, 1, boardLength, 0, -1, TRUE);
when {KEY_UP}:
moveOkay := doMove(state, 1, 1, 1, 0, TRUE);
when {KEY_DOWN}:
moveOkay := doMove(state, boardLength, 1, -1, 0, TRUE);
end case;
if moveOkay and not quit then
addTile(state);
end if;
until moveOkay;
until quit;
end func;