Subversion Repositories shark

Rev

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

Rev Author Line No. Line
1665 pj 1
//////////////////////////////////////////////////////////////////
2
// Pong
3
// Written for CS 324, UIUC
4
// Spencer Hoke
5
// James Kim
6
// Tao Luo
7
//
8
// Last Modified: April 29, 2004
9
 
10
#include "pong.h"
11
 
12
///////////////////////////////////////
13
// sets initial values of global variables
14
void setglobals() {
15
    P_MASS = 100;
16
    kp = 30;
17
    kd = 20;                 // > sqrt(4*(XMAX - XMIN)* kp)
18
    AI_VIEWING_RANGE = 250;  // window = YMAX - this
19
 
20
    balllist = NULL;
21
 
22
    num_balls = 0;           // number of balls currently in system
23
    min_balls = 0;           // minimum number of balls in the system
24
    locked = 0;              // 1 if #balls kept constant
25
    ball_spd = 5;            // ballspeed (default = 5)
26
 
27
    p_speed = 10;            // # pixels to move each keypress
28
    p1_length = 150;         // size of the paddles
29
    p2_length = 75;          // size of the paddles
30
 
31
    p1_pos = (XMAX + XMIN - p1_length)/2;  // initialize starting paddle positions
32
    p2_pos = (XMAX + XMIN - p2_length)/2;
33
    p2_target_pos = p2_pos;  // initially no movement
34
 
35
    points1 = 0;             // scores for each side
36
    points2 = 0;
37
}
38
 
39
///////////////////////////////////////
40
// center at (x,y) with radius RAD and color c
41
void draw_ball(int x, int y, int c) {
42
    mutex_lock(&draw_mutex);
43
    grx_disc(x, y, RAD, c);
44
    mutex_unlock(&draw_mutex);
45
}
46
 
47
///////////////////////////////////////
48
// top left corner is (x,y), length is l,
49
// thickness is P_THICKNESS, and color is c
50
void draw_paddle(int x, int y, int l, int c) {
51
    mutex_lock(&draw_mutex);
52
    grx_box(x, y, x + l, y + P_THICKNESS, c);
53
    mutex_unlock(&draw_mutex);
54
}
55
 
56
///////////////////////////////////////
57
// draws a line where the computer's viewing window starts
58
void draw_viewwin(int col) {
59
    mutex_lock(&draw_mutex);
60
    grx_line(XMIN-RAD, AI_VIEWING_RANGE+YMIN, XMAX+RAD, AI_VIEWING_RANGE+YMIN, col);
61
    mutex_unlock(&draw_mutex);
62
}
63
 
64
///////////////////////////////////////
65
void print_scores() {
66
    char st1[15], st2[15];
67
 
68
    sprintf(st1, "Player 1:%6d", points1);
69
    sprintf(st2, "Player 2:%6d", points2);
70
    mutex_lock(&draw_mutex);
71
    grx_text(st1, XMIN-RAD-1, 20, blue, black);
72
    grx_text(st2, XMIN-RAD-1, 30, red, black);
73
    mutex_unlock(&draw_mutex);
74
}
75
 
76
///////////////////////////////////////
77
void print_numballs() {
78
    char st[15];
79
 
80
    sprintf(st, "Num balls:%3d", num_balls);
81
    mutex_lock(&draw_mutex);
82
    grx_text(st, XMAX-100, 20, magenta, black);
83
    mutex_unlock(&draw_mutex);
84
}
85
 
86
///////////////////////////////////////
87
void print_constants() {
88
    char st[15];
89
 
90
    sprintf(st, "kp:%3d, kd:%3d, mass:%4d", kp, kd, P_MASS);
91
    mutex_lock(&draw_mutex);
92
    grx_text(st, XMIN-RAD-1, YMAX+20, magenta, black);
93
    mutex_unlock(&draw_mutex);
94
}
95
 
96
///////////////////////////////////////
97
TASK ball(void *arg) {
98
    int     x, y;             // current position
99
    int     oldx, oldy;       // last position
100
    int     dx, dy;           // delta x, y
101
    int     theta, col;
102
    double  r;                // theta in radians
103
    int     p1len, p2len, p1pos, p2pos;   // temp storage of length and position
104
    int     outx;
105
    int     hitp1, hitp2;        // 1 if ball has hit paddle
106
    int     in1, in2;            // 1 if ball is currently inside paddle (error)
107
    struct  ballinfo myinfo;     // shared x/y/theta
108
 
109
    myinfo.x = x = oldx = XMIN;             // start in middle of the left
110
    myinfo.y = y = oldy = (YMIN+YMAX)/2;
111
    col = rand()%14 + 2;         // color ball
112
 
113
    // insert myinfo into global list
114
    mutex_lock(&list_mutex);
115
    if(balllist != NULL)   // update old first entry in list
116
        balllist->prev = &myinfo;
117
    myinfo.next = balllist;
118
    myinfo.prev = NULL;
119
    balllist = &myinfo;
120
    mutex_unlock(&list_mutex);
121
 
122
    //  starting angle = [ANGMIN,ANGMAX]
123
    theta = rand()%(ANGMAX - ANGMIN) + ANGMIN;
124
    if (rand()%2 == 1) // random starting direction
125
        theta *= -1;
126
    if (theta > 360) theta -= 360;
127
    if (theta < 0) theta += 360;
128
    myinfo.theta = theta;
129
    r = (double)theta * PI / 180.;
130
 
131
    while (1) {
132
        dx = (float)(ball_spd * cos(r));
133
        dy = (float)(ball_spd * sin(r));
134
        x += dx;
135
        y += dy;
136
 
137
        // check boundary conditions
138
        if (y >= YMAX) {  // end task and score point for player 2
139
            points1++;
140
            break;
141
        }
142
        if (y <= YMIN) {  // end task and score point for player 1
143
            points2++;
144
            break;
145
        }
146
 
147
        p1len = p1_length;  // copy globals
148
        p1pos = p1_pos;
149
        p2len = p2_length;
150
        p2pos = p2_pos;
151
 
152
        outx = (x >= XMAX) || (x <= XMIN);
153
        hitp1 = (y <= (YMIN + 2*RAD + P_THICKNESS)) // y is within range of paddle
154
                && (x >= (p1pos - RAD)) && (x <= (p1pos + p1len + RAD)); // x is within range of paddle
155
        hitp2 = (y >= (YMAX - 2*RAD - P_THICKNESS)) // y is within range of paddle
156
                && (x >= (p2pos - RAD)) && (x <= (p2pos + p2len + RAD)); // x is within range of paddle
157
 
158
        // need these in case ball goes in the side of the paddle
159
        in1 = (oldy <= (YMIN + 2*RAD + P_THICKNESS)) // oldy is within range of paddle
160
                && (oldx >= (p1pos - RAD)) && (oldx <= (p1pos + p1len + RAD)); // oldx is within range of paddle
161
        in2 = (oldy >= (YMAX - 2*RAD - P_THICKNESS)) // oldy is within range of paddle
162
                && (oldx >= (p2pos - RAD)) && (oldx <= (p2pos + p2len + RAD)); // oldx is within range of paddle
163
 
164
        if (outx || ((hitp1 || hitp2) && !in1 && !in2)) { // ball needs to bounce
165
            x -= dx;
166
            y -= dy;
167
            if (outx) theta = 180 - theta;                        // bounce off wall
168
            if ((hitp1 || hitp2) && !in1 && !in2) theta = -theta; // bounce off paddle
169
 
170
            if (theta > 360) theta -= 360;
171
            else if (theta < 0) theta += 360;
172
 
173
            r = (double)theta * PI / 180.;
174
            x += (float)(ball_spd * cos(r));
175
            y += (float)(ball_spd * sin(r));
176
        }
177
 
178
        draw_ball(oldx, oldy, black);       // clear old position
179
        draw_ball(x, y, col);               // draw new ball
180
        oldx = x; oldy = y;
181
 
182
        mutex_lock(&list_mutex);      // updates values in list
183
        myinfo.x = x;
184
        myinfo.y = y;
185
        myinfo.theta = theta;
186
        mutex_unlock(&list_mutex);
187
 
188
        task_endcycle();
189
    }
190
 
191
    // remove myinfo from list
192
    mutex_lock(&list_mutex);
193
    if(myinfo.next != NULL)
194
        (myinfo.next)->prev = myinfo.prev;
195
 
196
    if(myinfo.prev != NULL)
197
        (myinfo.prev)->next = myinfo.next;
198
    else
199
        balllist = myinfo.next;
200
    mutex_unlock(&list_mutex);
201
 
202
    draw_ball(oldx, oldy, 0); // clear ball
203
    print_scores();           // update score
204
    num_balls--;              // remove ball from system
205
    if(!locked)
206
        print_numballs();     // update count of balls
207
    return NULL;
208
}
209
 
210
///////////////////////////////////////
211
void addball() {
212
    HARD_TASK_MODEL m;
213
    PID pid;
214
 
215
    hard_task_default_model(m);
216
    hard_task_def_ctrl_jet (m);
217
    hard_task_def_wcet     (m, BALL_WCET);
218
    hard_task_def_mit      (m, BALL_PER);
219
    hard_task_def_group    (m, BALLGROUP);
220
    hard_task_def_usemath  (m);
221
    pid = task_create("ball", ball, &m, NULL);
222
    if (pid == NIL) {
223
        sys_shutdown_message("Could not create task <ball> errno=%d", errno);
224
        sys_abort(errno);
225
    }
226
    task_activate(pid);
227
    num_balls++;
228
    print_numballs();
229
}
230
 
231
///////////////////////////////////////
232
// paddle 1 controller
233
TASK paddle1(void *arg) {
234
    int oldpos, newpos;
235
    int move, oldlength, length;
236
 
237
    oldpos = newpos = p1_pos;
238
    oldlength = -1;            // force draw initially
239
 
240
    while (1) {
241
        length = p1_length;    // need to copy in case they change
242
        move = p1_move;
243
        p1_move -= move;       // update global variable
244
 
245
        // get new position of ball
246
        newpos += move * p_speed;
247
        if(newpos < XMIN) // tried to move too far right
248
            newpos = XMIN;
249
        else if(newpos > (XMAX - length)) // tried to move too far left
250
            newpos = XMAX - length;
251
 
252
        if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle
253
            p1_pos = newpos;  // update global position
254
            draw_paddle(oldpos, YMIN + RAD, oldlength, black);  // clear old paddle
255
            draw_paddle(newpos, YMIN + RAD, length, blue);  // draw new one
256
            oldpos = newpos;
257
            oldlength = length;
258
        }
259
        else
260
            draw_paddle(newpos, YMIN + RAD, length, blue);  // refresh paddle
261
 
262
        task_endcycle();
263
    }
264
}
265
 
266
///////////////////////////////////////
267
// determines target position of paddle 2
268
TASK p2ai(void *arg) {
269
    int     proj;    // projected length to y-value of paddle
270
    int     closestBallY_Location = 0;
271
    int     closestBallX_Location = 0;
272
    int         closestBallY_Angle = 0;
273
    int     closestToPaddle;
274
    int         projectedX_Location = 0;
275
    int     foundBall;
276
    double  r;                  // angle in radians
277
    struct ballinfo *cur;
278
    char st[20];
279
 
280
     while(1) {
281
        if (num_balls != 0) { // if there are balls
282
            //finds the closest ball and its position and angle
283
            closestBallY_Location = AI_VIEWING_RANGE + YMIN;
284
            closestToPaddle = 1000000;       // large default number
285
            foundBall = 0;
286
 
287
            mutex_lock(&list_mutex);
288
            for (cur = balllist; cur != NULL; cur = cur->next) {
289
                if (cur->y > closestBallY_Location         // within window
290
                    && cur->y < (YMAX - RAD - P_THICKNESS) // not past paddle already
291
                    && cur->theta < 180)                   // going toward paddle
292
                {
293
                    r = (double)(cur->theta) * PI / 180.;
294
                    proj = (float)( (YMAX - RAD - P_THICKNESS - cur->y) / sin(r) );  // geometry
295
                    if(proj < closestToPaddle) { // this is the closest one
296
                        foundBall = 1;
297
                        closestBallY_Location = cur->y;
298
                        closestBallX_Location = cur->x;
299
                        closestBallY_Angle = cur->theta;
300
                        closestToPaddle = proj;
301
                    }
302
                }
303
            }
304
            mutex_unlock(&list_mutex);
305
 
306
            //finds where it needs to move to
307
            if (foundBall == 1) {
308
                r = (double)closestBallY_Angle * PI / 180.;
309
                projectedX_Location = (float)( (YMAX - RAD - P_THICKNESS - closestBallY_Location) / tan(r) );  // geometry
310
                projectedX_Location += closestBallX_Location;
311
 
312
                while(projectedX_Location < XMIN || projectedX_Location > XMAX) { // adjust for ball bounces
313
                    if(projectedX_Location < XMIN)
314
                        projectedX_Location = 2*XMIN - projectedX_Location;  // bounce off left side
315
                    if(projectedX_Location > XMAX)
316
                        projectedX_Location = 2*XMAX - projectedX_Location;  // bounce off right side
317
                }
318
 
319
                sprintf(st, "Proj X: %3d", projectedX_Location);
320
                mutex_lock(&draw_mutex);
321
                grx_text(st, XMAX-85, YMAX+20, magenta, black);
322
                mutex_unlock(&draw_mutex);
323
 
324
                p2_target_pos = projectedX_Location - p2_length/2;   // copy into target for p2
325
            }
326
        }
327
 
328
        task_endcycle();
329
    }
330
}
331
 
332
///////////////////////////////////////
333
// paddle 2 controller - applies forces and draws paddle
334
TASK paddle2(void *arg) {
335
    int     oldpos, newpos;
336
    int     positionErrorX, oldlength, length;
337
    int     force = 0, acceleration = 0, velocity = 0;    // paddle movement
338
 
339
    oldpos = newpos = p2_pos;
340
    oldlength = -1;            // force draw initially
341
 
342
    while (1) {
343
        length = p2_length;    // need to copy in case they change
344
        positionErrorX = p2_target_pos - oldpos;
345
 
346
        //Applying force
347
        force = kp * positionErrorX - kd * velocity;
348
        acceleration = force / P_MASS;
349
 
350
        velocity += acceleration;      // new velocity
351
        newpos = oldpos + velocity;    // using new velocity, so incorporates acceleration
352
 
353
        if(newpos < XMIN) // tried to move too far right
354
            newpos = XMIN;
355
        else if(newpos > (XMAX - length)) // tried to move too far left
356
            newpos = XMAX - length;
357
 
358
        if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle
359
            p2_pos = newpos;  // update global position
360
            draw_paddle(oldpos, YMAX - P_THICKNESS - RAD, oldlength, black);  // clear old paddle
361
            draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red);  // draw new one
362
            oldpos = newpos;
363
            oldlength = length;
364
        }
365
        else
366
            draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red);  // refresh paddle
367
 
368
        task_endcycle();
369
    }
370
}
371
 
372
///////////////////////////////////////
373
TASK countmon(void *arg) {
374
    while(1) {
375
        while(num_balls < min_balls)
376
            addball();
377
        task_endcycle();
378
    }
379
}
380
 
381
///////////////////////////////////////
382
int main(int argc, char **argv) {
383
    HARD_TASK_MODEL m;
384
    PID pid;
385
 
386
    char c;
387
    TIME seme;          // used to init the random seed
388
    PI_mutexattr_t a;   // for PI mutex init
389
 
390
    // initialize global variables
391
    setglobals();
392
 
393
    // initialize PI mutexes
394
    PI_mutexattr_default(a);
395
    mutex_init(&draw_mutex, &a);
396
    mutex_init(&list_mutex, &a);
397
 
398
    // Draw initial screen layout and menu
399
    grx_rect(XMIN-RAD-1, YMIN-RAD-1, XMAX+RAD+1, YMAX+RAD+1, yellow);
400
    grx_text("Scores:",             XMIN-RAD-1, 10, magenta, black);
401
 
402
    grx_text("PONG",                       XMENU, YMENU, magenta, black);
403
    grx_text("Create a ball:       SPACE", XMENU, YMENU+15, redorange, black);
404
    grx_text("Quit program:        ESC",   XMENU, YMENU+25, redorange, black);
405
    grx_text("Move top paddle:     z x",   XMENU, YMENU+35, redorange, black);
406
    grx_text("Change top size:     a s",   XMENU, YMENU+45, redorange, black);
407
    grx_text("Change bottom size:  q w",   XMENU, YMENU+55, redorange, black);
408
    grx_text("Keep # Balls Const:  l",     XMENU, YMENU+65, redorange, black);
409
    grx_text("Change ball speed:   1 2",   XMENU, YMENU+75, redorange, black);
410
    grx_text("Change kp:           3 4",   XMENU, YMENU+85, redorange, black);
411
    grx_text("Change kd:           5 6",   XMENU, YMENU+95, redorange, black);
412
    grx_text("Change mass:         7 8",   XMENU, YMENU+105, redorange, black);
413
    grx_text("Change AI window:    9 0",   XMENU, YMENU+115, redorange, black);
414
 
415
    print_scores();
416
    print_numballs();
417
    print_constants();
418
    draw_viewwin(gray);
419
 
420
    // randomize for ball starting angle
421
    seme = sys_gettime(NULL);
422
    srand(seme);
423
 
424
    // set up the paddle tasks
425
    hard_task_default_model(m);
426
    hard_task_def_ctrl_jet (m);
427
    hard_task_def_wcet     (m, P_WCET);
428
    hard_task_def_mit      (m, P_PER);
429
    hard_task_def_group    (m, PGROUP);
430
    hard_task_def_usemath  (m);
431
    pid = task_create("paddle1", paddle1, &m, NULL);
432
    if (pid == NIL) {
433
        sys_shutdown_message("Could not create task <paddle1> errno=%d", errno);
434
        sys_abort(errno);
435
    }
436
 
437
    hard_task_default_model(m);
438
    hard_task_def_ctrl_jet (m);
1667 giacomo 439
    hard_task_def_level    (m,1);
1665 pj 440
    hard_task_def_wcet     (m, P_WCET);
441
    hard_task_def_mit      (m, P_PER);
442
    hard_task_def_group    (m, PGROUP);
443
    hard_task_def_usemath  (m);
444
    pid = task_create("p2ai", p2ai, &m, NULL);
445
    if (pid == NIL) {
446
        sys_shutdown_message("Could not create task <p2ai> errno=%d", errno);
447
        sys_abort(errno);
448
    }
449
 
450
    hard_task_default_model(m);
451
    hard_task_def_ctrl_jet (m);
1667 giacomo 452
    hard_task_def_level    (m,1);
1665 pj 453
    hard_task_def_wcet     (m, P_WCET);
454
    hard_task_def_mit      (m, P_PER);
455
    hard_task_def_group    (m, PGROUP);
456
    hard_task_def_usemath  (m);
457
    pid = task_create("paddle2", paddle2, &m, NULL);
458
    if (pid == NIL) {
459
        sys_shutdown_message("Could not create task <paddle2> errno=%d", errno);
460
        sys_abort(errno);
461
    }
462
    group_activate(PGROUP);
463
 
464
    #ifdef JET_ON
465
        scenario_jetcontrol();
466
        init_jetcontrol();
467
        group_activate(JET_GROUP);
468
    #endif
469
 
470
    hard_task_default_model(m);
471
    hard_task_def_ctrl_jet (m);
1667 giacomo 472
    hard_task_def_level    (m,1);
1665 pj 473
    hard_task_def_wcet     (m, BALL_WCET);
474
    hard_task_def_mit      (m, BALL_PER);
475
    hard_task_def_group    (m, BALLGROUP);
476
    hard_task_def_usemath  (m);
477
    pid = task_create("countmon", countmon, &m, NULL);
478
    if (pid == NIL) {
479
        sys_shutdown_message("Could not create task <countmonitor> errno=%d", errno);
480
        sys_abort(errno);
481
    }
482
    task_activate(pid);
483
 
484
    while(1) { // read in commands ( exit handled in handle_key() )
485
        c = keyb_getch(BLOCK);
486
        switch (c) {
487
            case ESC: // quit program
488
                sys_abort(0);
489
                break;
490
            case ' ': // create a new ball
491
                addball();
492
                if(locked == 1)    // update min # balls if locked
493
                    min_balls++;
494
                break;
495
            case 'z': // move paddle1 left
496
                p1_move--;
497
                break;
498
            case 'x': // move paddle1 right
499
                p1_move++;
500
                break;
501
            case 's': // increase paddle1 length
502
                if (p1_length < (XMAX - XMIN - P_DLENGTH))
503
                    p1_length += P_DLENGTH;
504
                break;
505
            case 'a': // decrease paddle1 length
506
                if (p1_length > (1 + P_DLENGTH))
507
                     p1_length -= P_DLENGTH;
508
                break;
509
            case 'w': // increase paddle2 length
510
                if (p2_length < (XMAX - XMIN - P_DLENGTH))
511
                    p2_length += P_DLENGTH;
512
                break;
513
            case 'q': // decrease paddle2 length
514
                if (p2_length > (1 + P_DLENGTH))
515
                    p2_length -= P_DLENGTH;
516
                break;
517
            case 'l': // lock number of balls
518
                if((locked = !locked)) {
519
                    min_balls = num_balls;
520
                    mutex_lock(&draw_mutex);
521
                    grx_text("   Locked", XMAX-100, 30, redorange, black);
522
                    mutex_unlock(&draw_mutex);
523
                }
524
                else {
525
                    min_balls = 0;
526
                    mutex_lock(&draw_mutex);
527
                    grx_text("         ", XMAX-100, 30, redorange, black);
528
                    mutex_unlock(&draw_mutex);
529
                }
530
                break;
531
            case '1': // decrease ball speed
532
                ball_spd--;
533
                break;
534
            case '2': // increase ball speed
535
                ball_spd++;
536
                break;
537
            case '3': // decrease kp
538
                if(kp > 0)
539
                    kp--;
540
                print_constants();
541
                break;
542
            case '4': // increase kp
543
                kp++;
544
                print_constants();
545
                break;
546
            case '5': // decrease kd
547
                if(kd > 0)
548
                    kd--;
549
                print_constants();
550
                break;
551
            case '6': // increase kd
552
                kd++;
553
                print_constants();
554
                break;
555
            case '7': // decrease mass
556
                if(P_MASS > 5)
557
                    P_MASS -= 5;
558
                print_constants();
559
                break;
560
            case '8': // increase mass
561
                P_MASS += 5;
562
                print_constants();
563
                break;
564
            case '9': // decrease AI window
565
                draw_viewwin(black);    // clear old line
566
                AI_VIEWING_RANGE += 5;
567
                draw_viewwin(gray);     // draw new one
568
                break;
569
            case '0': // increase AI window
570
                draw_viewwin(black);    // clear old line
571
                AI_VIEWING_RANGE -= 5;
572
                draw_viewwin(gray);     // draw new one
573
                break;
574
            default:
575
                break;
576
        }
577
    }
578
 
579
    return 0;
580
}
581