-
Notifications
You must be signed in to change notification settings - Fork 3
/
TreeView.pas
355 lines (331 loc) · 9.39 KB
/
TreeView.pas
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// Окно визуализации дерева поиска: это и для отладки и просто для любопытства
{$R+}
unit TreeView;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, ExtCtrls;
type
TTreeWnd = class(TForm)
procedure FormPaint(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormResize(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
procedure DrawTree;
procedure BuildTree;
end;
var
TreeWnd: TTreeWnd;
implementation
uses gamedata,main,AI,Apus.MyServis;
const
COL_WIDTH = 90;
{$R *.dfm}
type
TColumn=record
items,pos:array of integer;
procedure Clear;
procedure Add(v:integer);
end;
var
// индексы эл-тов дерева в data [столбец,строка]
treeData:array of TColumn;
selIdx:array[0..30] of integer; // индексы цепочки выбранных эл-тов (в data)
saveGameover:integer;
procedure InitTree;
begin
SetLength(treeData,2);
treeData[0].Clear;
treeData[0].Add(curBoardIdx);
selIdx[0]:=curBoardIdx;
end;
procedure TTreeWnd.BuildTree;
var
d,idx,parent:integer;
begin
parent:=curBoardIdx;
for d:=1 to high(treeData) do begin
treeData[d].Clear;
idx:=data[parent].firstChild;
while idx>0 do begin
treeData[d].Add(idx);
if selidx[d]=idx then parent:=idx;
idx:=data[idx].nextSibling;
end;
end;
end;
procedure UpdateTreePos(clientHeight:integer);
var
i,c,d,yPos,vAdd:integer;
begin
ypos:=clientHeight div 2;
treeData[0].pos[0]:=yPos;
for d:=1 to high(treeData) do
with treeData[d] do begin // слой d:
c:=high(items);
if c<0 then break; // пустой уровень
for i:=0 to c do
pos[i]:=ypos-(c*18) div 2+i*18;
vAdd:=0;
if pos[0]<10 then inc(vAdd,10-pos[0]);
if pos[c]>clientHeight-10 then dec(vAdd,pos[c]-(clientHeight-10));
for i:=0 to c do
inc(pos[i],vAdd);
// центр для след слоя
for i:=0 to c do
if items[i]=selidx[d] then
ypos:=pos[i];
end;
end;
procedure DrawTreeLines(canvas:TCanvas);
var
i,j,d,y,yn:integer;
begin
for d:=1 to high(treeData) do begin
if length(treeData[d].items)=0 then exit;
// поиск предка в предыдущем уровне
for i:=0 to high(treeData[d-1].items) do
if treeData[d-1].items[i]=selidx[d-1] then
with treeData[d] do begin
yn:=0;
for j:=0 to high(items) do begin
if items[j]=selIdx[d] then begin
canvas.Pen.Width:=2;
yn:=pos[j];
end else
canvas.Pen.Width:=1;
canvas.moveto(25+d*COL_WIDTH-COL_WIDTH div 2,pos[j]);
canvas.lineto(25+d*COL_WIDTH-COL_WIDTH div 2+10,pos[j]);
end;
canvas.Pen.Width:=1;
// вертикальная линия
canvas.moveto(25+d*COL_WIDTH-COL_WIDTH div 2,pos[0]);
canvas.lineto(25+d*COL_WIDTH-COL_WIDTH div 2,pos[j-1]);
canvas.Pen.Width:=2;
y:=treeData[d-1].pos[i];
if yn>0 then begin
canvas.moveto(25+d*COL_WIDTH-COL_WIDTH div 2,y);
canvas.lineto(25+d*COL_WIDTH-COL_WIDTH div 2,yn);
end;
// горизонтальная линия
canvas.moveto(25+d*COL_WIDTH-COL_WIDTH div 2-15,y);
canvas.lineto(25+d*COL_WIDTH-COL_WIDTH div 2,y);
break;
end;
end;
end;
procedure DrawTreeNodes(canvas:TCanvas);
var
i,j,d,idx,dbInd,cx,cy,x:integer;
st,st2,st3:string;
val:single;
cell1,cell2:byte;
hash:int64;
ch:char;
begin
for d:=0 to high(treeData) do
with treeData[d] do begin
if length(items)=0 then exit;
// выбор решающего варианта для подсветки
if d>0 then begin
idx:=items[0];
j:=0; // здесь будет решающий
if data[idx].whiteTurn xor playerWhite then val:=10000 else val:=-10000;
for i:=0 to high(items) do begin
if data[idx].whiteTurn xor playerWhite then begin
if data[items[i]].rate<val then begin val:=data[items[i]].rate; j:=i; end;
end else begin
if data[items[i]].rate>val then begin val:=data[items[i]].rate; j:=i; end;
end;
end;
end;
for i:=0 to high(items) do begin
if selidx[d]=items[i] then // выбранный элемент
canvas.Pen.Width:=2
else begin
canvas.Pen.Width:=1;
//if data[items[i]].flags and movVerified=0 then canvas.brush.color:=$E0E0E0
canvas.brush.color:=$E0C0C0;
end;
if i=j then
canvas.brush.color:=$D4F0D4 // элемент с наилучшей оценкой
else
// фон обычного элемента
if not data[items[i]].whiteTurn then
canvas.brush.color:=$F8F8F8
else
canvas.brush.color:=$D8D8D8;
canvas.font.color:=canvas.pen.color;
cx:=25+d*COL_WIDTH;
cy:=pos[i];
if d>0 then begin
canvas.RoundRect(cx-COL_WIDTH div 2+6,cy-7,cx+COL_WIDTH div 2-6,cy+8,5,5);
if data[items[i]].firstChild>0 then begin
x:=cx+COL_WIDTH div 2-9;
canvas.MoveTo(x,cy-6);
canvas.LineTo(x,cy+7);
end;
if data[items[i]].HasFlag(movDB) then begin
x:=cx+COL_WIDTH div 2-7;
canvas.brush.color:=$80E0F0;
canvas.Ellipse(x-5,cy-6,x+5,cy+7);
end;
end else
canvas.RoundRect(cx-22,cy-12,cx+32,cy+12,7,7);
idx:=items[i];
if d>0 then begin
cell1:=data[idx].lastTurnFrom;
cell2:=data[idx].lastTurnTo;
if data[idx].flags and movBeat>0 then begin // ход со взятием
ch:=':';
canvas.Font.Color:=$B0;
end else
ch:='-';
if data[idx].flags and movCheck>0 then begin // шах
st2:='+';
canvas.Font.Color:=$A000B0;
end else
st2:='';
st3:=FloatToStrF(data[idx].rate,ffFixed,4,2);
if abs(data[idx].rate)>210 then
st3:=FloatToStrF(data[idx].rate,ffFixed,4,0);
st:=NameCell(cell1 and $F,cell1 shr 4)+ch+NameCell(cell2 and $F,cell2 shr 4)+st2+
' '+st3;
end else
st:=' Root';
canvas.brush.Style:=bsClear;
canvas.TextOut(cx-canvas.TextWidth(st) div 2,cy-7,st);
canvas.brush.Style:=bsSolid;
end;
end;
end;
procedure TTreeWnd.DrawTree;
begin
with Canvas do begin
brush.Color:=$F0F0F0;
fillrect(clientrect);
// 1. вычислим положения эл-тов
UpdateTreePos(clientHeight);
// 2. нарисуем линии
pen.Color:=$606060;
DrawTreeLines(canvas);
// 3. нарисуем эл-ты
font.Size:=8;
font.Name:='Arial';
DrawTreeNodes(canvas);
end;
end;
procedure TTreeWnd.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MainForm.displayBoard:=curBoardIdx;
MainForm.DrawBoard(sender);
gameState:=saveGameover;
PauseAfterThisStage(false);
ResumeAI;
end;
procedure TTreeWnd.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure SelectItem(n:integer);
var
col,row:integer;
begin
for col:=1 to high(treeData) do
with treeData[col] do
for row:=0 to high(items) do
if items[row]=n then begin
selIdx[col]:=n;
selIdx[col+1]:=-1;
SetLength(treeData,col+2);
mainForm.displayBoard:=n;
BuildTree;
mainForm.DrawBoard(sender);
Invalidate;
MainForm.Estimate(true);
exit;
end;
end;
var
n:integer;
begin
if key=VK_ESCAPE then Close;
if key=VK_UP then begin
n:=MainForm.displayBoard;
n:=data[n].prevSibling;
if n>0 then SelectItem(n);
end else
if key=VK_DOWN then begin
n:=MainForm.displayBoard;
n:=data[n].nextSibling;
if n>0 then SelectItem(n);
end else
if key=VK_LEFT then begin
n:=MainForm.displayBoard;
n:=data[n].parent;
if (n>0) and (n<>curBoardIdx) then SelectItem(n);
end;
end;
procedure TTreeWnd.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
i,col,v,idx:integer;
begin
col:=(x+10) div COL_WIDTH;
if col>high(treeData) then exit;
with treeData[col] do
for i:=0 to high(items) do
if (y>=pos[i]-8) and (y<=pos[i]+8) then begin
idx:=items[i];
selidx[col]:=idx;
selIdx[col+1]:=-1;
mainForm.displayBoard:=idx;
if Button=mbRight then begin
v:=items[i];
ShowMessage(Format('ID:%d, q=%d',[v,round(data[v].quality)]),'Node info');
end;
SetLength(treeData,col+2);
BuildTree;
mainForm.DrawBoard(sender);
break;
end;
Invalidate;
MainForm.Estimate(true);
end;
procedure TTreeWnd.FormPaint(Sender: TObject);
begin
DrawTree;
end;
procedure TTreeWnd.FormResize(Sender: TObject);
begin
DrawTree;
end;
procedure TTreeWnd.FormShow(Sender: TObject);
begin
InitTree;
BuildTree;
saveGameover:=gameState;
gameState:=4;
end;
{ TColumn }
procedure TColumn.Add(v:integer);
var
n:integer;
begin
n:=length(items);
SetLength(items,n+1);
SetLength(pos,n+1);
items[n]:=v;
pos[n]:=0;
end;
procedure TColumn.Clear;
begin
SetLength(items,0);
SetLength(pos,0);
end;
end.