Subversion Repositories wimsdev

Rev

Rev 3653 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3653 schaersvoo 1
/*                                                                                                            
2
Copyright 2004-2006 David P. Little                                                                            
3
license:                                                                                                      
4
Unless otherwise stated, the above applets were written by David Little.                                      
5
They may be used without permission from the author for home and/or educational (non-profit) purposes only.    
6
Any other use must be approved by the author.                                                                  
7
 
8
Modified for wims interactive usage with permission of the author.                                            
9
 
10
J.M. Evers                                                                                                    
11
*/
12
import java.util.*;
13
import java.awt.*;
14
import java.awt.event.*;
15
import java.awt.image.*;
16
import java.awt.geom.*;
17
import javax.swing.*;
18
 
19
public class PlinkoBoard extends JPanel implements Runnable, KeyListener, MouseListener, MouseMotionListener{
20
 
21
        double COUNT;                                   // number of balls that have been dropped
22
        double TOTAL;                                   // total of bins
23
        double TOTAL_SQUARES;                   // total of bins
24
 
25
        long[] HIST;                                    // number of balls in each bin;
26
        float MAX;                                              // maximum number of balls in a single bin
27
        double[][][] PINS;                                      // coordinates of pins (including one at the base of each bin)
28
        double DIST;                                    // vertical distance between pins
29
        double BALL_RAD;                                // radius of ball
30
        int PIN_RAD;                                    // radius of pin
31
        int BINS;                                               // total number of bins
32
        int W;                                                  // width of board
33
        int H;                                                  // height of board
34
        PlinkoBall FIRST_BALL;                  // represents beginning of doubly linked list of plinko balls
35
        int BALL_COUNT;
36
        int BOTTOM_MARGIN = 5;
37
 
38
        // used in calculating confidence intervals
39
        int LEFT;
40
        int RIGHT;
41
        double PERCENT;
42
        int CURRENT_BIN = 0;
43
        int showstats=0;
44
        static double[][] DYS;
45
        // jm.evers: defining a few things
46
        int maximum_balls;String start_number="0";int incr=1;
4033 bpr 47
        int BIN_HEIGHT;                         // height of bins ****
3653 schaersvoo 48
 
49
        static Color[] COLORS = { Color.red, Color.magenta, Color.orange, Color.yellow, Color.green, Color.blue, Color.cyan };
50
        /*  new Color(.45f,.40f,.86f), new Color(.36f,.53f,.95f),
51
            new Color(.38f,.84f,.67f), new Color(.37f,.74f,.44f), new Color(.49f,.51f,.36f), new Color(.90f,.90f,.35f),
52
            new Color(.99f,.75f,.34f), new Color(.85f,.27f,.42f), new Color(.73f,.34f,.76f), new Color(.51f,.33f,.82f),
53
            new Color(.41f,.46f,.91f), new Color(.36f,.73f,.79f), new Color(.38f,.79f,.56f), new Color(.44f,.60f,.37f),
54
            new Color(.70f,.71f,.35f), new Color(.99f,.91f,.34f), new Color(.99f,.58f,.34f), new Color(.94f,.38f,.34f),
55
            new Color(.86f,.33f,.68f), new Color(.35f,.09f,.73f), new Color(.09f,.13f,.80f), new Color(.09f,.38f,.35f),
56
            new Color(.18f,.55f,.13f), new Color(.55f,.74f,.11f), new Color(.99f,.92f,.09f), new Color(.99f,.69f,.09f),
57
            new Color(.99f,.46f,.09f), new Color(.96f,.25f,.11f), new Color(.93f,.09f,.12f), new Color(.42f,.09f,.69f),
58
            new Color(.27f,.09f,.78f), new Color(.09f,.29f,.51f), new Color(.09f,.46f,.20f), new Color(.36f,.64f,.12f),
59
            new Color(.73f,.83f,.10f), new Color(.99f,.80f,.09f), new Color(.99f,.57f,.09f), new Color(.98f,.31f,.10f),
60
            new Color(.94f,.12f,.11f), new Color(.16f,.10f,.06f), new Color(.36f,.24f,.14f), new Color(.55f,.38f,.21f),
61
            new Color(.75f,.52f,.29f), new Color(.80f,.78f,.76f), new Color(.55f,.50f,.45f),  new Color(.24f,.22f,.20f),
62
            new Color(.76f,.76f,.80f), new Color(.45f,.45f,.55f), new Color(.20f,.20f,.24f)};*/
63
 
64
        //BufferedImage[] IMAGES;
65
    Image[] IMAGES;
66
    Thread thread;
67
    boolean active;    
68
    Image background;
69
    Image image;
70
    Graphics2D graphics;
71
    Plinko plinko;
72
 
73
    public PlinkoBoard( Plinko plinko ){
74
        super();
75
        this.plinko = plinko;
76
        setup();
77
        newHist();
78
 
79
        FIRST_BALL = null;
80
        BALL_COUNT = 0;
81
        active = false;
82
 
83
        DYS = new double[12][];
84
 
85
        for ( double i=0.0; i<12.0; i++ ){
86
            DYS[(int)i] = new double[ (int)i ];
87
            for ( double j=0.0; j<i; j++ ){
88
                DYS[(int)i][(int)j] = PlinkoBall.A*j*j/(i*i) + PlinkoBall.B*j/i;
89
            }
90
        }
91
 
92
        addKeyListener( this );
93
        addMouseListener( this );
94
        // jm.evers: if the applet is in an wims exercise...read appletparam and start buckets_number with 1 instead of 0
95
        maximum_balls=(int)plinko.total_balls - 1;
4033 bpr 96
        BIN_HEIGHT=(int)plinko.bin_height ;
3653 schaersvoo 97
        if(plinko.wims_exercise == false){ showstats = 1;}else{ start_number="1"; incr=2; }
98
    }
99
 
100
    public void setup(){
101
                W = getWidth();
102
                H = getHeight();
103
 
104
                BINS = ((Integer)plinko.bins.getValue()).intValue();
105
                CURRENT_BIN = BINS/2;
106
                LEFT = BINS+1;
107
                RIGHT = BINS;
108
                PERCENT = 0;
109
 
4033 bpr 110
                if ( H-BIN_HEIGHT-BOTTOM_MARGIN<W/2 ){
111
                        DIST = (double)(H-BIN_HEIGHT-BOTTOM_MARGIN)/BINS;
3653 schaersvoo 112
                } else {
113
                        DIST = (double)(W-10)/(2*BINS);
114
                }
115
 
116
                PIN_RAD = (int)DIST/9 + 1;
117
                BALL_RAD = Math.max(2*DIST/7,2.0)+1;
118
 
119
                // create images of colored balls
120
                IMAGES = new Image[ COLORS.length ];
121
                Graphics2D g;
122
                int red;
123
                int green;
124
                int blue;
125
                for ( int i=0; i<COLORS.length; i++ ){
126
                        IMAGES[i] = getBall( BALL_RAD, COLORS[i] );
127
                        /*
128
                        IMAGES[i] = new BufferedImage( (int)(2*BALL_RAD+2), (int)(2*BALL_RAD+2), BufferedImage.TYPE_INT_ARGB);
129
                        g = (Graphics2D)(IMAGES[i].getGraphics());
130
                        g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
131
                        g.setBackground( new Color(0,0,0,255) );
132
 
133
                        red = COLORS[i].getRed();
134
                        green = COLORS[i].getGreen();
135
                        blue = COLORS[i].getBlue();
136
 
137
                        for ( float k=0; k<1; k=k+(float)(1/BALL_RAD) ){
138
                                g.setColor( new Color(red + (int)(k*k*(255-red)),green + (int)(k*k*(255-green)),blue + (int)(k*k*(255-blue))) );
139
                                g.fill( new Ellipse2D.Double( k*k*BALL_RAD/2, k*k*BALL_RAD/2, 2*(BALL_RAD-k*k*BALL_RAD), 2*(BALL_RAD-k*k*BALL_RAD) ) );
140
                        }
141
                        */
142
                }
143
 
144
 
145
                PINS = new double[BINS][][];
146
                for (int i=0; i<BINS; i++){
147
                        PINS[i] = new double[i+1][2];
148
                        for (int j=0; j<=i; j++){
149
                                //PINS[i][j] = new Point((int)(DIST*(2*j-i)+W/2),(int)(DIST*(i+1)));
150
                                PINS[i][j][0] = DIST*(2*j-i)+W/2;
151
                                PINS[i][j][1] = DIST*(i+1);
152
                        }
153
                }              
154
 
155
                // pins at the base of each bin
156
                for (int i=0; i<BINS; i++){
157
                        //PINS[BINS-1][i] = new Point((int)(DIST*(2*i-BINS+1)+W/2),(int)(H-30-BALL_RAD));
158
                        PINS[BINS-1][i][0] = DIST*(2*i-BINS+1)+W/2;
159
                        PINS[BINS-1][i][1] = H-30-BALL_RAD;
160
                }
161
        }
162
 
163
 
164
        public static Image getBall( double R, Color color ){
165
                BufferedImage image = new BufferedImage( (int)(2*R+2), (int)(2*R+2), BufferedImage.TYPE_INT_ARGB);
166
 
167
                int red;
168
                int grn;
169
                int blu;
170
                double[] n = new double[3];
171
                double[] e = new double[3];
172
                double[] l = {-5,5,10};
173
                double ll = Math.sqrt(150);
174
                double F;
175
                double G;
176
 
177
                for ( int i=0; i<(int)(2*R+2); i++ ){
178
                        for ( int j=0; j<(int)(2*R+2); j++ ){
179
                                if ( (R-i)*(R-i) + (R-j)*(R-j) <= (R-1)*(R-1) ){               
180
                                        // vector normal to sphere
181
                                        n[0] = (i - R)/R;
182
                                        n[1] = (R - j)/R;
183
                                        n[2] = Math.sqrt(1 - n[0]*n[0] - n[1]*n[1]);
184
 
185
                                        F = (n[0]*l[0] + n[1]*l[1] + n[2]*l[2])/Math.sqrt(l[0]*l[0] + l[1]*l[1] + l[2]*l[2]);
186
                                        F = (1+F)/2;
187
                                        G = Math.pow(F,20.0);
188
 
189
                                        red = (int)(color.getRed()*(F-G) + G*255);
190
                                        grn = (int)(color.getGreen()*(F-G) + G*255);
191
                                        blu = (int)(color.getBlue()*(F-G) + G*255);
192
 
193
                                        image.setRGB(i,j, (255<<24) + (red<<16) + (grn<<8) + blu );
194
                                } else if ( (R-i)*(R-i) + (R-j)*(R-j) <= (R+1)*(R+1) ){
195
                                        red = 0;
196
                                        grn = 0;
197
                                        blu = 0;
198
 
199
                                        for ( double di = -0.33; di<0.5; di+=0.33 ){
200
                                                for ( double dj = -0.33; dj<0.5; dj+=0.33 ){
201
 
202
                                                        if ( (R-(i+di))*(R-(i+di)) + (R-(j+dj))*(R-(j+dj)) <= R*R ){
203
                                                                n[0] = (i + dj - R)/R;
204
                                                                n[1] = (R - (j+dj))/R;
205
                                                                n[2] = Math.sqrt(1 - n[0]*n[0] - n[1]*n[1]);
206
 
207
                                                                F = (n[0]*l[0] + n[1]*l[1] + n[2]*l[2])/ll;
208
                                                                F = (1+F)/2;
209
                                                                G = Math.pow(F,20.0);
210
                                                        } else {
211
                                                                F = 1;
212
                                                                G = 1;
213
                                                        }
214
                                                        red += (int)(color.getRed()*(F-G) + G*255);
215
                                                        grn += (int)(color.getGreen()*(F-G) + G*255);
216
                                                        blu += (int)(color.getBlue()*(F-G) + G*255);
217
 
218
                                                }
219
                                        }
220
 
221
                                        red /= 9;
222
                                        grn /= 9;
223
                                        blu /= 9;
224
 
225
                                        image.setRGB(i,j, ((255-(red+grn+blu)/3)<<24) + (red<<16) + (grn<<8) + blu );
226
                                }
227
                        }
228
                }
229
                return image;
230
        }
231
 
232
 
233
    public void newHist(){
234
                COUNT = 0;
235
                TOTAL = 0;
236
                TOTAL_SQUARES = 0;
237
                MAX = 0;
238
                PERCENT = 0;
239
 
240
                HIST = new long[ BINS ];
241
                for (int i=0; i<BINS; i++){
242
                        HIST[i] = 0;
243
                }
244
    }
245
 
246
    // jm.evers :preparing a data string for javascript: must be of type string: arrays always give trouble on IE...
247
    public String ReadData(){
248
        String reply="";
249
        for(int i=0;i<HIST.length;i++){
250
            if(i != 0){reply=reply+","+HIST[i];}else{reply=""+HIST[0];}
251
        }
252
        return reply;
253
    }
254
 
255
    public void LimitReached(){
256
            plinko.active = true;
257
            FIRST_BALL=null;
258
            plinko.toggleStart();
259
    }
260
 
261
    public void run(){
262
        while ( BALL_COUNT>0 ){
263
            repaint();
264
            try {Thread.sleep(50);} catch (InterruptedException e){}
265
        }
266
        repaint();
267
        active = false;
268
        plinko.active = false;
269
        plinko.bins.setEnabled( true );
270
    }
271
 
272
 
273
    // under construction
274
    public void kill(){
275
                FIRST_BALL = null;
276
                if ( plinko.start.getText().equals(plinko.start_text) ){
277
                        active = false;
278
                        plinko.active = false;
279
                        plinko.bins.setEnabled( true );
280
                }
281
    }
282
 
283
 
284
    public void dropBall( boolean sound ){
285
        BALL_COUNT++;
286
        // jm.evers : I don't know of another/better way to get the system to stop at a given [param] number of balls...
4033 bpr 287
        if(COUNT >= maximum_balls ){LimitReached();}
3653 schaersvoo 288
        if ( FIRST_BALL == null ){
289
            FIRST_BALL = new PlinkoBall();
290
            FIRST_BALL.sound = sound;
291
        } else {
292
            FIRST_BALL.previousBall = new PlinkoBall();
293
            FIRST_BALL.previousBall.sound = sound;
294
            FIRST_BALL.previousBall.nextBall = FIRST_BALL;
295
            FIRST_BALL = FIRST_BALL.previousBall;
296
        }
297
 
298
        try { Thread.sleep(0);} catch (InterruptedException e){}
299
 
300
        if ( !active ){
301
            active = true;
302
            thread = new Thread(this);
303
            thread.start();
304
        }
305
    }
306
 
307
    public void paintComponent( Graphics g ){
308
                // have a copy of the background on which to draw
309
                W = getWidth();
310
                H = getHeight();
311
 
312
                if ( background == null || background.getWidth(this) != W || background.getHeight(this) != H || image == null || image.getWidth(this) != W || image.getHeight(this) != H ){
313
                        setup();
314
                        background = createImage( W, H );
315
                        drawBackground(W,H);
316
                        image = createImage( W, H );
317
                        graphics = (Graphics2D) image.getGraphics();
318
                        graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
319
                        graphics.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
320
                }
321
 
322
                graphics.drawImage( background, 0, 0, this );
323
 
324
                // run through all active balls and draw them on the image
325
                PlinkoBall ball = FIRST_BALL;
326
                while ( ball != null ){
327
                        graphics.drawImage( IMAGES[ball.spaz], (int)(ball.X - BALL_RAD),  (int)(ball.Y - 2*BALL_RAD - PIN_RAD + 1), this );
328
                        //if ( ball.t == ball.C && ball.ROW < BINS-2 ) Plinko.click.play();
329
                        //try {
330
                                increment( ball );
331
                        //} catch ( NullPointerException npe ) {
332
                        //}
333
                        ball = ball.nextBall;
334
                }
335
                drawHist( graphics );
336
        //      if(showstats==1){
337
                    drawStats( graphics );
338
        //      }
339
                g.drawImage(image,0,0,this);
340
    }
341
 
342
    // under construction
343
    public void drawNormal(){
344
    }
345
 
346
 
347
    public void increment( PlinkoBall ball ){
348
                // if ball has landed on pin, reset t to 0 and pick a direction
349
                if ( ball.t == ball.C && ball.ROW < BINS-2 ){
350
                        ball.ROW++;
351
                        ball.COL += ball.DIR;
352
                        ball.t = 0;
353
                        ball.DIR = 0;
354
 
355
                        // pick a new direction
356
 
357
                        // jm.evers: reading controls or applet param...plinko.chance is parameter
358
                        if(plinko.wims_exercise == false){
359
                            if ( Math.random() < ((Double)plinko.prob.getValue()).doubleValue() ) ball.DIR = 1;
360
                        }
361
                        else
362
                        {
363
                            if ( Math.random() <  plinko.chance ){ ball.DIR = 1;}
364
                        }
365
 
366
                        // update speed
367
                        ball.C = 11-((Integer)plinko.rate.getValue()).intValue();
368
 
369
                        if ( ball.sound ) Plinko.ping.play();
370
                }
371
 
372
                double dx = (double)(DIST*ball.t*(2*ball.DIR - 1))/(double)(ball.C);
373
 
374
                if ( ball.ROW < 0 ){
375
                        // ball falling onto top pin
376
                        ball.X = PINS[0][0][0];
377
                        dx = Math.abs(dx);
378
                        ball.Y = PINS[0][0][1] - DIST + DIST*ball.t*ball.t/(ball.C*ball.C);
379
                } else if ( ball.ROW < BINS-2 ) {
380
                        ball.X = PINS[ball.ROW][ball.COL][0] + dx;
381
                        dx = Math.abs(dx);
382
                        ball.Y = PINS[ball.ROW][ball.COL][1] - DIST*DYS[ball.C][ball.t];
383
                } else {
384
                        // ball falling into bin
385
                        // dx = DIST*ball.t*(2*ball.DIR - 1)/10.0;
386
                        ball.X = PINS[ball.ROW][ball.COL][0] + dx;
387
                        if ( dx>0 ){
388
                                ball.X = Math.min(ball.X,PINS[ball.ROW][ball.COL][0] + 2*DIST - BALL_RAD );
389
                        } else {
390
                                ball.X = Math.max(ball.X,PINS[ball.ROW][ball.COL][0] - 2*DIST + BALL_RAD + 1);
391
                        }
392
                        dx = Math.abs(dx);
393
                        ball.Y = PINS[ball.ROW][ball.COL][1]  - dx*(ball.A*dx/DIST+ball.B);
394
                }
395
 
396
                ball.t++;
397
 
398
                if ( ball.Y > H - BOTTOM_MARGIN - PIN_RAD ){
399
                        if ( ball.previousBall != null && ball.nextBall != null){
400
                                ball.previousBall.nextBall = ball.nextBall;
401
                                ball.nextBall.previousBall = ball.previousBall;
402
                        } else if ( ball.previousBall != null && ball.nextBall == null ) {
403
                                ball.previousBall.nextBall = null;
404
                        } else if ( ball.previousBall == null && ball.nextBall != null ) {
405
                                ball.nextBall.previousBall = null;
406
                                FIRST_BALL = ball.nextBall;
407
                        } else  {
408
                                FIRST_BALL = null;
409
                                plinko.bins.setEnabled( true );
410
                        }
411
 
412
                        BALL_COUNT--;
413
                        updateHist(ball.COL+ball.DIR);
414
                        if ( ball.sound ) Plinko.click.play();
415
                }
416
    }
417
 
418
 
419
    public void updateHist( int i ){
420
                HIST[i]++;
421
                COUNT++;
422
                TOTAL += i;
423
                TOTAL_SQUARES += i*i;
424
                if ( HIST[i] > MAX) MAX = HIST[i];
425
                if ( i>= LEFT && i <= RIGHT ){
426
                        PERCENT++;
427
                }
428
    }
429
 
430
 
431
    public void drawStats(Graphics g){
432
    //jm.evers : if in a wims_exercise we show a limited amount of statistical data...
433
        if(showstats == 1){
434
            plinko.count.setText(plinko.label_count+ (int)COUNT);
435
            plinko.current_bin.setText(plinko.label_bin + CURRENT_BIN);
436
            plinko.current_bin_count.setText(plinko.label_bin_count + HIST[CURRENT_BIN]);
437
            if(COUNT > 0.0D){
438
                double d = TOTAL / COUNT;
439
                plinko.mean.setText(plinko.label_mean + (float)d);
440
                plinko.variance.setText(plinko.label_variance + (float)(TOTAL_SQUARES / COUNT - d * d));
441
                plinko.current_bin_prob.setText(plinko.label_bin_probability + (float)((double)(int)((double)(0x186a0L * HIST[CURRENT_BIN]) / COUNT) / 1000D) + "%");
442
                if(LEFT < BINS){
443
                    if(LEFT == RIGHT){
444
                        plinko.confidence.setText(plinko.label_confidence + (float)((double)(int)((100000D * PERCENT) / COUNT) / 1000D) + plinko.some_text + LEFT + ".");
445
                    }
446
                    else
447
                    {
4033 bpr 448
                        plinko.confidence.setText(plinko.label_confidence + (float)((double)(int)((100000D * PERCENT) / COUNT) / 1000D) + plinko.some_text2 + LEFT + plinko.through + RIGHT + ".");
3653 schaersvoo 449
                    }
450
                }
451
                else
452
                {
453
                    plinko.confidence.setText(plinko.label_confidence );
454
                }
455
            }
456
            else
457
            {
458
                plinko.mean.setText(plinko.label_mean );
459
                plinko.variance.setText(plinko.label_variance);
460
                plinko.current_bin_prob.setText(plinko.label_bin_probability);
461
                plinko.confidence.setText(plinko.label_confidence);
462
            }
463
        }
464
        else
465
        {
466
        // just the total COUNT and "balls per active bin" 
467
            plinko.count.setText(plinko.label_count+ (int)COUNT);
468
            plinko.current_bin.setText(plinko.label_bin + (CURRENT_BIN+1));
469
            plinko.current_bin_count.setText(plinko.label_bin_count + HIST[CURRENT_BIN]);
470
        }
471
    }
472
 
473
 
474
    public void drawHist( Graphics2D g ){
475
                long h;
476
                double x0;
477
                double x1;
478
                String str;
479
                W = getWidth();
480
                H = getHeight();
481
                Rectangle2D rect;
482
 
483
                for (int i=0; i<BINS; i++){
484
                        if ( i==0 ){
485
                                x0 = PINS[BINS-1][0][0]-DIST;
486
                                x1 = PINS[BINS-2][0][0];
487
                        } else if ( i==BINS-1 ){
488
                                x0 = PINS[BINS-2][BINS-2][0];
489
                                x1 = PINS[BINS-1][BINS-1][0]+DIST;
490
                        } else {
491
                                x0 = PINS[BINS-2][i-1][0];
492
                                x1 = PINS[BINS-2][i][0];
493
                        }
494
 
495
                        //Draw bar
496
                        h = HIST[i];
4033 bpr 497
                        if (MAX>BIN_HEIGHT) h=(int)(BIN_HEIGHT*1.0*h/MAX);
3653 schaersvoo 498
                        g.setColor( new Color(255,0,0,175) );
499
                        if ( i >= LEFT && i <= RIGHT ) g.setColor( new Color(0,255,0,175) );
500
                        rect = new Rectangle2D.Double(x0,H-h-BOTTOM_MARGIN,x1-x0,h);
501
                        g.fill( rect );
502
                        g.setColor(Color.black);
503
                        g.setStroke( new BasicStroke(1.0f) );
504
                        g.draw( rect );
505
                }
506
 
507
                // draw line under current bin
508
                g.setColor( Color.black );
509
                g.setStroke( new BasicStroke(3.0f) );
510
                g.draw( new Line2D.Double(PINS[BINS-1][CURRENT_BIN][0]-DIST,H-BOTTOM_MARGIN+3,PINS[BINS-1][CURRENT_BIN][0]+DIST,H-BOTTOM_MARGIN+3) );
511
    }
512
 
513
 
514
    public void drawBackground(){
515
                drawBackground( getWidth(), getHeight() );
516
    }
517
 
518
 
519
    public void drawBackground( int W, int H ){
520
                double[] p;
521
 
522
                Graphics2D backgroundgraphics = (Graphics2D) background.getGraphics();
523
                backgroundgraphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
524
                backgroundgraphics.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
525
                backgroundgraphics.setColor(Color.white);
526
                backgroundgraphics.fillRect( 0, 0, W, H );
527
                backgroundgraphics.setColor(Color.black);
528
 
529
                Image img = getBall( PIN_RAD, Color.black );
530
 
531
                // draw pins
532
                for (int i=0; i<BINS-1; i++){
533
                        for (int j=0;j<=i;j++){
534
                        p = PINS[i][j];
535
                        //backgroundgraphics.fill( new Ellipse2D.Double(p[0]-PIN_RAD,p[1]-PIN_RAD,2*PIN_RAD,2*PIN_RAD) );
536
                        backgroundgraphics.drawImage(img, (int)(p[0]-PIN_RAD),(int)(p[1]-PIN_RAD),this );
537
                        }
538
                }
539
 
540
                String s;
4033 bpr 541
                backgroundgraphics.setFont( new Font("Helvetica",Font.BOLD,Math.min((int)(4*DIST)/3,BIN_HEIGHT/2)) );
3653 schaersvoo 542
                FontMetrics fm = backgroundgraphics.getFontMetrics();
543
                // draw lines and numbers
544
                p = PINS[BINS-1][0];
4033 bpr 545
                backgroundgraphics.draw( new Line2D.Double( p[0]-DIST,H-BIN_HEIGHT-BOTTOM_MARGIN,p[0]-DIST,H-BOTTOM_MARGIN) );
3653 schaersvoo 546
                backgroundgraphics.setColor( Color.darkGray );
4033 bpr 547
                backgroundgraphics.drawString(start_number,(int)(p[0] - fm.stringWidth("0")/2), H-BIN_HEIGHT-BOTTOM_MARGIN+Math.min((int)(4*DIST)/3, BIN_HEIGHT/2) );
3653 schaersvoo 548
                for (int i=0; i<BINS-1; i++){
549
                        p = PINS[BINS-2][i];
550
                        s = ""+(i+incr);
551
                        backgroundgraphics.setColor( Color.darkGray );
4033 bpr 552
                        backgroundgraphics.drawString(s,(int)(p[0] + DIST - fm.stringWidth(s)/2),H-BIN_HEIGHT-BOTTOM_MARGIN+Math.min((int)(4*DIST)/3,BIN_HEIGHT/2));
3653 schaersvoo 553
                        backgroundgraphics.setColor( Color.black );
4033 bpr 554
                        backgroundgraphics.draw( new Line2D.Double( p[0],H-BIN_HEIGHT-BOTTOM_MARGIN,p[0],H-BOTTOM_MARGIN) );
3653 schaersvoo 555
                }
556
                p = PINS[BINS-1][BINS-1];
4033 bpr 557
                backgroundgraphics.draw( new Line2D.Double(p[0]+DIST,H-BIN_HEIGHT-BOTTOM_MARGIN,p[0]+DIST,H-BOTTOM_MARGIN) );
3653 schaersvoo 558
                backgroundgraphics.draw( new Line2D.Double(0,H-BOTTOM_MARGIN,W,H-BOTTOM_MARGIN) );
559
                repaint();
560
    }
561
 
562
 
563
    public void keyTyped( KeyEvent ke ){
564
    }
565
 
566
 
567
    public void keyPressed( KeyEvent ke ){
568
                int code = ke.getKeyCode();
569
                char key = ke.getKeyChar();
570
 
571
                if ( key >= '0' && key <= '4' ){
572
                        int x = key - '0';
573
                        int n = 1;
574
                        for (int i=0; i<x; i++ ){
575
                                n *= 10;
576
                        }/*
577
                        plinko.countdown = n;
578
                        if ( !plinko.active ){
579
                                plinko.start();
580
                                plinko.bins.setEnabled( false );
581
                                plinko.thread = new Thread(plinko);
582
                                plinko.thread.start();
583
                                //start.setText("Stop");
584
                        }*/
585
                        for (int i=0; i<n; i++){
586
                                dropBall( n == 1 );
587
                        }
588
                } else if ( code == 37 ){  // left arrow
589
                        CURRENT_BIN--;
590
                        if ( CURRENT_BIN<0 ) CURRENT_BIN = BINS - 1;
591
                        updatePercent();
592
                        repaint();
593
                } else if ( code == 39 ){  // right arrow
594
                        CURRENT_BIN++;
595
                        if ( CURRENT_BIN>BINS-1 ) CURRENT_BIN = 0;
596
                        updatePercent();
597
                        repaint();
598
                } else if ( code == KeyEvent.VK_ENTER ){ // return or enter
599
                } else if ( key == ' ' ){
600
                        plinko.toggleStart();
601
                } else if (key==20){ //control t - toggle erasing
602
                } else if (key==3){ //control c - clear screen
603
                } else if (key==24){ //control x - kill all threads
604
                }
605
    }
606
 
607
 
608
    public void keyReleased( KeyEvent ke ){}
609
 
610
    public void mouseReleased( MouseEvent me ){}
611
 
612
    public void mouseEntered( MouseEvent me ){}
613
 
614
    public void mouseExited( MouseEvent me ){}
615
 
616
    public void updatePercent(){
617
        double mean = (BINS-1)*((Double)plinko.prob.getValue()).doubleValue();
618
        if ( CURRENT_BIN <= mean ){
619
            LEFT = CURRENT_BIN;
620
            RIGHT = (int)(2*mean) - LEFT;
621
        } else {
622
            RIGHT = CURRENT_BIN;
623
            LEFT = (int)(2*mean) - RIGHT;
624
        }
625
        LEFT = Math.max( LEFT, 0 );
626
        RIGHT = Math.min( RIGHT, BINS-1 );
627
        PERCENT = 0;
628
        for ( int i=LEFT; i<=RIGHT; i++ ){
629
            PERCENT += HIST[i];
630
        }
631
    }
632
 
633
 
634
    public void mouseClicked( MouseEvent me ){
635
        requestFocus();
636
        Point p = me.getPoint();
637
        int bin;
4033 bpr 638
        if ( p.x + DIST> PINS[BINS-1][0][0] && p.x-DIST < PINS[BINS-1][BINS-1][0] && p.y> H-BIN_HEIGHT-BOTTOM_MARGIN && p.y<H-BOTTOM_MARGIN){
3653 schaersvoo 639
            bin = 0;
640
            while ( bin<BINS-1 ){
641
                if ( p.x + DIST < PINS[BINS-1][bin+1][0] ) break;
642
                bin++;
643
            }
644
            CURRENT_BIN = bin;
645
            updatePercent();
646
            repaint();
647
        }                      
648
    }
649
 
650
 
651
    public void mousePressed( MouseEvent me ){}
652
 
653
    public void mouseDragged( MouseEvent me ){}
654
 
655
    public void mouseMoved( MouseEvent me ){}
656
}
657