@@ -33,6 +33,9 @@ import Algorithm, {
33
33
} from './Algorithm.js' ;
34
34
import { act } from '../anim/AnimationMain' ;
35
35
36
+ const INFO_MSG_X = 25 ;
37
+ const INFO_MSG_Y = 15 ;
38
+
36
39
const FIRST_PRINT_POS_X = 50 ;
37
40
const PRINT_VERTICAL_GAP = 20 ;
38
41
const PRINT_MAX = 990 ;
@@ -74,12 +77,16 @@ export default class BTree extends Algorithm {
74
77
this . cmd ( act . createLabel , this . messageID , '' , MESSAGE_X , MESSAGE_Y , 0 ) ;
75
78
this . moveLabel1ID = this . nextIndex ++ ;
76
79
this . moveLabel2ID = this . nextIndex ++ ;
80
+ this . infoLabelID = this . nextIndex ++ ;
81
+ this . cmd ( act . createLabel , this . infoLabelID , '' , INFO_MSG_X , INFO_MSG_Y , 0 ) ;
77
82
78
83
this . animationManager . startNewAnimation ( this . commands ) ;
79
84
this . animationManager . skipForward ( ) ;
80
85
this . animationManager . clearHistory ( ) ;
81
86
this . commands = [ ] ;
82
87
88
+ this . resetIndex = 4 ;
89
+
83
90
this . first_print_pos_y = h - 3 * PRINT_VERTICAL_GAP ;
84
91
85
92
this . xPosOfNextLabel = 100 ;
@@ -135,11 +142,11 @@ export default class BTree extends Algorithm {
135
142
this . findButton . onclick = this . findCallback . bind ( this ) ;
136
143
this . controls . push ( this . findButton ) ;
137
144
138
- addDivisorToAlgorithmBar ( ) ;
145
+ // addDivisorToAlgorithmBar();
139
146
140
- this . printButton = addControlToAlgorithmBar ( 'Button' , 'Print' ) ;
141
- this . printButton . onclick = this . printCallback . bind ( this ) ;
142
- this . controls . push ( this . printButton ) ;
147
+ // this.printButton = addControlToAlgorithmBar('Button', 'Print');
148
+ // this.printButton.onclick = this.printCallback.bind(this);
149
+ // this.controls.push(this.printButton);
143
150
144
151
addDivisorToAlgorithmBar ( ) ;
145
152
@@ -156,9 +163,9 @@ export default class BTree extends Algorithm {
156
163
this . controls . push ( this . clearButton ) ;
157
164
158
165
addDivisorToAlgorithmBar ( ) ;
159
- addLabelToAlgorithmBar ( 'Promote with ' ) ;
166
+ addLabelToAlgorithmBar ( 'Promote' ) ;
160
167
const splitIndexButtonList = addRadioButtonGroupToAlgorithmBar (
161
- [ 'second data ' , 'third data ' ] ,
168
+ [ 'second' , 'third' ] ,
162
169
'Split Index' ,
163
170
) ;
164
171
@@ -183,10 +190,180 @@ export default class BTree extends Algorithm {
183
190
this . succButton . onclick = this . succCallback . bind ( this ) ;
184
191
this . succButton . checked = true ;
185
192
this . predSucc = 'succ' ;
193
+
194
+ addDivisorToAlgorithmBar ( ) ;
195
+
196
+ const verticalGroup3 = addGroupToAlgorithmBar ( false ) ;
197
+ addLabelToAlgorithmBar (
198
+ '| separated list of nodes with comma separated keys (e.g. "1,3|0|2|4")' ,
199
+ verticalGroup3 ,
200
+ ) ;
201
+
202
+ const horizontalGroup = addGroupToAlgorithmBar ( true , verticalGroup3 ) ;
203
+
204
+ this . buildTreeField = addControlToAlgorithmBar ( 'Text' , '' , horizontalGroup ) ;
205
+ this . buildTreeField . onkeydown = this . returnSubmit (
206
+ this . buildTreeField ,
207
+ this . buildTreeCallback . bind ( this ) ,
208
+ 30 ,
209
+ false ,
210
+ true ,
211
+ ) ;
212
+ this . controls . push ( this . buildTreeField ) ;
213
+
214
+ this . buildTreeButton = addControlToAlgorithmBar ( 'Button' , 'Build Tree' , horizontalGroup ) ;
215
+ this . buildTreeButton . onclick = this . buildTreeCallback . bind ( this ) ;
216
+ this . controls . push ( this . buildTreeButton ) ;
217
+ }
218
+
219
+ buildTreeCallback ( ) {
220
+ const insertedValue = this . buildTreeField . value ;
221
+ this . implementAction ( this . clearTree . bind ( this ) ) ;
222
+ this . insertField . value = '' ;
223
+ this . implementAction ( this . buildTree . bind ( this ) , insertedValue ) ;
224
+ }
225
+
226
+ buildTree ( insertedValue ) {
227
+ this . commands = [ ] ;
228
+ this . cmd ( act . setText , this . infoLabelID , '' ) ;
229
+
230
+ const nodes = insertedValue . split ( '|' ) . map ( n => n . split ( ',' ) . map ( q => parseInt ( q ) ) ) ;
231
+
232
+ this . treeRoot = new BTreeNode ( this . nextIndex ++ , this . starting_x , STARTING_Y ) ;
233
+ this . cmd (
234
+ act . createBTreeNode ,
235
+ this . treeRoot . graphicID ,
236
+ WIDTH_PER_ELEM ,
237
+ NODE_HEIGHT ,
238
+ 1 ,
239
+ this . starting_x ,
240
+ STARTING_Y ,
241
+ BACKGROUND_COLOR ,
242
+ FOREGROUND_COLOR ,
243
+ ) ;
244
+ this . treeRoot . keys = nodes [ 0 ] ;
245
+ this . treeRoot . numKeys = nodes [ 0 ] . length ;
246
+ this . treeRoot . children = [ ] ;
247
+ this . cmd ( act . setText , this . treeRoot . graphicID , nodes [ 0 ] . join ( ' ' ) , 0 ) ;
248
+ this . cmd ( act . setNumElements , this . treeRoot . graphicID , nodes [ 0 ] . length ) ;
249
+ this . resizeTree ( ) ;
250
+ for ( let i = 0 ; i < nodes [ 0 ] . length ; i ++ ) {
251
+ this . cmd ( act . setText , this . treeRoot . graphicID , nodes [ 0 ] [ i ] , i ) ;
252
+ this . treeRoot . numKeys = nodes [ 0 ] . length ;
253
+ }
254
+
255
+ for ( let i = 1 ; i < nodes . length ; i ++ ) {
256
+ const newNode = new BTreeNode ( this . nextIndex ++ , this . starting_x , STARTING_Y ) ;
257
+ newNode . keys = nodes [ i ] ;
258
+ newNode . numKeys = nodes [ i ] . length ;
259
+ newNode . children = [ ] ;
260
+ this . buildTreeRecurse ( this . treeRoot , nodes [ i ] [ 0 ] , newNode ) ;
261
+ }
262
+
263
+ const problem = this . treeHasProblem ( this . treeRoot ) ;
264
+ if ( problem ) {
265
+ this . commands = [ ] ;
266
+ this . cmd ( act . setText , this . infoLabelID , problem ) ;
267
+ this . reset ( ) ;
268
+ this . shake ( this . buildTreeButton ) ;
269
+ return this . commands ;
270
+ }
271
+
272
+ this . cmd ( act . setText , this . messageID , '' ) ;
273
+
274
+ return this . commands ;
275
+ }
276
+
277
+ treeHasProblem ( node ) {
278
+ if ( node == null ) {
279
+ return '' ;
280
+ }
281
+ if ( node . numKeys > this . max_keys ) {
282
+ return `Nodes can have at most ${ this . max_keys } keys` ;
283
+ }
284
+ for ( let i = 0 ; i < node . numKeys - 1 ; i ++ ) {
285
+ if ( node . keys [ i ] >= node . keys [ i + 1 ] ) {
286
+ return `Tree must respect order property within nodes. ${ node . keys [ i ] } >= ${
287
+ node . keys [ i + 1 ]
288
+ } `;
289
+ }
290
+ }
291
+ if ( node . isLeaf ) {
292
+ return '' ;
293
+ }
294
+ if ( node . numKeys !== node . children . length - 1 ) {
295
+ return `Node with ${ node . numKeys } keys must have ${
296
+ node . numKeys + 1
297
+ } children if not a leaf`;
298
+ }
299
+ for ( let i = 0 ; i < node . numKeys ; i ++ ) {
300
+ const key = node . keys [ i ] ;
301
+ const c1 = node . children [ i ] ;
302
+ const c2 = node . children [ i + 1 ] ;
303
+ for ( const k of c1 . keys ) {
304
+ if ( k >= key ) return `Tree must respect order property. ${ k } >= ${ key } ` ;
305
+ }
306
+ for ( const k of c2 . keys ) {
307
+ if ( k <= key ) return `Tree must respect order property. ${ k } <= ${ key } ` ;
308
+ }
309
+ }
310
+
311
+ for ( const child of node . children ) {
312
+ const childProblem = this . treeHasProblem ( child ) ;
313
+ if ( childProblem ) return childProblem ;
314
+ }
315
+ return '' ;
316
+ }
317
+
318
+ // ex 2,9,13|1|5,6,7|11,12|14,16
319
+ buildTreeRecurse ( node , val , nodeToAdd ) {
320
+ let index = 0 ;
321
+ while ( index < node . numKeys && node . keys [ index ] < val ) {
322
+ index ++ ;
323
+ }
324
+ const nextNode = node . children [ index ] ;
325
+ if ( nextNode == null ) {
326
+ node . isLeaf = false ;
327
+ node . children . push ( nodeToAdd ) ;
328
+ nodeToAdd . y = node . y + 100 ;
329
+ nodeToAdd . x = node . x + ( index - 1.5 ) * 150 ;
330
+ nodeToAdd . parent = node ;
331
+
332
+ this . cmd (
333
+ act . createBTreeNode ,
334
+ nodeToAdd . graphicID ,
335
+ WIDTH_PER_ELEM ,
336
+ NODE_HEIGHT ,
337
+ 1 ,
338
+ nodeToAdd . x ,
339
+ nodeToAdd . y ,
340
+ BACKGROUND_COLOR ,
341
+ FOREGROUND_COLOR ,
342
+ ) ;
343
+
344
+ this . cmd ( act . setNumElements , nodeToAdd . graphicID , nodeToAdd . keys . length ) ;
345
+ this . resizeTree ( ) ;
346
+ for ( let i = 0 ; i < nodeToAdd . keys . length ; i ++ ) {
347
+ this . cmd ( act . setText , nodeToAdd . graphicID , nodeToAdd . keys [ i ] , i ) ;
348
+ }
349
+
350
+ this . cmd (
351
+ act . connect ,
352
+ node . graphicID ,
353
+ nodeToAdd . graphicID ,
354
+ FOREGROUND_COLOR ,
355
+ 0 , // Curve
356
+ 0 , // Directed
357
+ '' , // Label
358
+ index ,
359
+ ) ;
360
+ } else {
361
+ this . buildTreeRecurse ( nextNode , val , nodeToAdd ) ;
362
+ }
186
363
}
187
364
188
365
reset ( ) {
189
- this . nextIndex = 3 ;
366
+ this . nextIndex = this . resetIndex ;
190
367
this . max_degree = 4 ;
191
368
this . max_keys = 3 ;
192
369
this . min_keys = 1 ;
@@ -387,14 +564,17 @@ export default class BTree extends Algorithm {
387
564
this . commands = [ ] ;
388
565
this . deleteTree ( this . treeRoot ) ;
389
566
this . treeRoot = null ;
390
- this . nextIndex = 3 ;
567
+ this . nextIndex = this . resetIndex ;
391
568
return this . commands ;
392
569
}
393
570
394
571
deleteTree ( tree ) {
395
572
if ( tree != null ) {
396
573
if ( ! tree . isLeaf ) {
397
574
for ( let i = 0 ; i <= tree . numKeys ; i ++ ) {
575
+ if ( ! tree . children [ i ] ) {
576
+ continue ;
577
+ }
398
578
this . cmd ( act . disconnect , tree . graphicID , tree . children [ i ] . graphicID ) ;
399
579
this . deleteTree ( tree . children [ i ] ) ;
400
580
}
@@ -407,7 +587,7 @@ export default class BTree extends Algorithm {
407
587
this . commands = [ ] ;
408
588
this . deleteTree ( this . treeRoot ) ;
409
589
this . treeRoot = null ;
410
- this . nextIndex = 3 ;
590
+ this . nextIndex = this . resetIndex ;
411
591
const newDegree = degree ;
412
592
this . ignoreInputs = true ;
413
593
this . maxDegreeRadioButtons [ newDegree - MIN_MAX_DEGREE ] . checked = true ;
0 commit comments