From 304fe7efd12613f4cdeb7157b4bb49fcb779d68c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 15 Mar 2018 19:44:30 +0000 Subject: [PATCH] startrek: integerize There are still some bugs notably the torp/base docking computer is wrong in some cases. --- Applications/games/startrek.c | 345 ++++++++++++++++++++-------------- 1 file changed, 209 insertions(+), 136 deletions(-) diff --git a/Applications/games/startrek.c b/Applications/games/startrek.c index 0862c77b..86b9ac3d 100644 --- a/Applications/games/startrek.c +++ b/Applications/games/startrek.c @@ -134,14 +134,13 @@ static void repair_damage(void); static void find_set_empty_place(uint8_t t); static const char *get_device_name(int n); static void quadrant_name(void); -static int function_d(int i); -static int cint(double d); +static int distance_to(int i); +static int square00(int16_t t); static int cint100(int16_t d); static void compute_vector(void); static void sub1(void); static void sub2(void); static void showfile(char *filename); -static double rnd(void); /* Global Variables */ @@ -180,13 +179,13 @@ static uint16_t t9; /* End of time */ static int z1, z2; /* Temporary Sector Coordinates */ static int z4, z5; /* Temporary quadrant coordinates */ -static double a, c1; /* Used by Library Computer */ +static int16_t a, c1; /* Used by Library Computer */ static int16_t d[9]; /* Damage Array */ static int16_t d4; /* Used for computing damage repair time */ -static double s1, s2; /* Current Sector Position of Enterprise */ +static int16_t s1, s2; /* Current Sector Position of Enterprise, fixed point */ static uint16_t t; /* Current Stardate */ static int16_t w1; /* Warp Factor */ -static double x, y, x1, x2; /* Navigational coordinates */ +static int16_t x, y, x1, x2; /* Navigational coordinates, fixed point */ static char *sC; /* Condition */ @@ -249,14 +248,6 @@ static uint8_t yesno(void) return 0; } -/* We'll turn this fixed point in time */ -static double input_dec(void) -{ - char x[8]; - input(x, 8); - return atof(x); -} - /* Input a value between 0.00 and 9.99 */ static int16_t input_f00(void) { @@ -331,8 +322,6 @@ static uint8_t inoperable(uint8_t u) static void intro(void) { - /* FIXME: consider moving these into files and showfiling them */ - showfile("startrek.intro"); if (yesno()) @@ -360,7 +349,6 @@ static void new_game(void) while (1) { if (s + e <= 10 && (e < 10 || d[7] < 0)) { - /* Could be a showfile FIXME */ showfile("startrek.fatal"); end_of_time(); } @@ -425,8 +413,8 @@ static void initialize(void) q1 = rand8(); q2 = rand8(); - s1 = (double) rand8(); - s2 = (double) rand8(); + s1 = TO_FIXED00(rand8()); + s2 = TO_FIXED00(rand8()); for (i = 1; i <= 8; i++) d[i] = 0; @@ -545,7 +533,7 @@ static void new_quadrant(void) memset(quad, Q_SPACE, 64); /* FIXME: do we need 0.5 shifts ? */ - quad[(int)s1 - 1][(int)s2 - 1] = Q_SHIP; + quad[FROM_FIXED00(s1) - 1][FROM_FIXED00(s2) - 1] = Q_SHIP; if (k3 > 0) { for (i = 1; i <= k3; i++) { @@ -573,17 +561,18 @@ static void course_control(void) { register int i; /* @@@ int c2, c3, q4, q5; */ - double c1; + int16_t c1; + int c2, c3, c4; char sX[4] = "8"; fputs("Course (0-9): ", stdout); - c1 = input_dec(); + c1 = input_f00(); - if (c1 == 9.0) - c1 = 1.0; + if (c1 == 900) + c1 = 100; - if (c1 < 0 || c1 > 9.0) { + if (c1 < 0 || c1 > 900) { printf("Lt. Sulu%s", inc_1); return; } @@ -614,6 +603,7 @@ static void course_control(void) n = cint100(n); /* @@@ note: this is a real round in the original basic */ + /* FIXME: should be s + e - n > 0 iff shield control undamaged */ if (e - n < 0) { printf("Engineering reports:\n" " Insufficient energy available for maneuvering" @@ -632,11 +622,12 @@ static void course_control(void) repair_damage(); /* @@@ z1 = cint(s1); */ - z1 = (int) s1; + z1 = FROM_FIXED00(s1); /* @@@ z2 = cint(s2); */ - z2 = (int) s2; + z2 = FROM_FIXED00(s2); quad[z1-1][z2-1] = Q_SPACE; +#if 0 /* @@@ c2 = cint(c1); */ /* @@@ c3 = c2 + 1; */ @@ -645,6 +636,19 @@ static void course_control(void) x1 = c[1][(int) c1] + (c[1][(int) c1 + 1] - c[1][(int) c1]) * (c1 - (int) c1); x2 = c[2][(int) c1] + (c[2][(int) c1 + 1] - c[2][(int) c1]) * (c1 - (int) c1); +#else + + c2 = FROM_FIXED00(c1); /* Integer part */ +// printf("C2 = %d\n", c2); + c3 = c2 + 1; /* Next integer part */ + c4 = (c1 - TO_FIXED00(c2)); /* Fractional element in fixed point */ + + x1 = 100 * c[1][c2] + (c[1][c3] - c[1][c2]) * c4; + x2 = 100 * c[2][c2] + (c[2][c3] - c[2][c2]) * c4; + +// printf("x1 = %d x2 = %d\n", x1, x2); + +#endif x = s1; y = s2; @@ -659,9 +663,9 @@ static void course_control(void) // i, s1, s2, x1, x2); /* @@@ z1 = cint(s1); */ - z1 = (int) s1; + z1 = FROM_FIXED00(s1); /* @@@ z2 = cint(s2); */ - z2 = (int) s2; + z2 = FROM_FIXED00(s2); /* ?? cint100 ?? */ if (z1 < 1 || z1 >= 9 || z2 < 1 || z2 >= 9) { exceed_quadrant_limits(); @@ -686,9 +690,9 @@ static void complete_maneuver(void) int t8; /* @@@ z1 = cint(s1); */ - z1 = (int) s1; + z1 = FROM_FIXED00(s1); /* @@@ z2 = cint(s2); */ - z2 = (int) s2; + z2 = FROM_FIXED00(s2); quad[z1-1][z2-1] = Q_SHIP; maneuver_energy(); @@ -712,30 +716,36 @@ static void exceed_quadrant_limits(void) int x5 = 0; /* Outside galaxy flag */ /* @@@ x = (8 * (q1 - 1)) + x + (n * x1); */ - x = (8 * q1) + x + (n * x1); + x = (800 * q1) + x + (n * x1); /* @@@ y = (8 * (q2 - 1)) + y + (n * x2); */ - y = (8 * q2) + y + (n * x2); + y = (800 * q2) + y + (n * x2); + +// printf("X %d Y %d\n", x, y); /* @@@ q1 = cint(x / 8.0); */ - q1 = (int) (x / 8.0); + q1 = x / 800; /* Fixed point to int and divide by 8 */ /* @@@ q2 = cint(y / 8.0); */ - q2 = (int) (y / 8.0); + q2 = y / 800; /* Ditto */ + +// printf("Q %d %d\n", q1, q2); /* @@@ s1 = x - ((q1 - 1) * 8); */ - s1 = x - (q1 * 8); + s1 = x - (q1 * 800); /* @@@ s2 = y - ((q2 - 1) * 8); */ - s2 = y - (q2 * 8); + s2 = y - (q2 * 800); + +// printf("S %d %d\n", s1, s2); /* @@@ if (cint(s1) == 0) */ - if ((int) s1 == 0) { + if (s1 < 100) { q1 = q1 - 1; - s1 = s1 + 8.0; + s1 = s1 + 800; } /* @@@ if (cint(s2) == 0) */ - if ((int) s2 == 0) { + if (s2 < 100) { q2 = q2 - 1; - s2 = s2 + 8.0; + s2 = s2 + 800; } /* check if outside galaxy */ @@ -743,25 +753,25 @@ static void exceed_quadrant_limits(void) if (q1 < 1) { x5 = 1; q1 = 1; - s1 = 1.0; + s1 = 100; } if (q1 > 8) { x5 = 1; q1 = 8; - s1 = 8.0; + s1 = 800; } if (q2 < 1) { x5 = 1; q2 = 1; - s2 = 1.0; + s2 = 100; } if (q2 > 8) { x5 = 1; q2 = 8; - s2 = 8.0; + s2 = 800; } if (x5 == 1) { @@ -773,7 +783,7 @@ static void exceed_quadrant_limits(void) "Chief Engineer Scott reports:\n" " Warp Engines shut down at sector %d, " "%d of quadrant %d, %d.\n\n", - (int) s1, (int) s2, q1, q2); + FROM_FIXED00(s1), FROM_FIXED00(s2), q1, q2); } /* else new_quadrant(); @@@ this causes bugs when bouncing off galaxy walls. @@ -847,9 +857,9 @@ static void short_range_scan(void) d0 = 0; /* @@@ for (i = s1 - 1; i <= s1 + 1; i++) */ - for (i = (int) (s1 - 1); i <= (int) (s1 + 1); i++) + for (i = (int) (FROM_FIXED00(s1) - 1); i <= (int) (FROM_FIXED00(s1) + 1); i++) /* @@@ for (j = s2 - 1; j <= s2 + 1; j++) */ - for (j = (int) (s2 - 1); j <= (int) (s2 + 1); j++) + for (j = (int) (FROM_FIXED00(s2) - 1); j <= (int) (FROM_FIXED00(s2) + 1); j++) if (i >= 1 && i <= 8 && j >= 1 && j <= 8) { /* This is dumb - we store the base co-ords! */ if (quad[i-1][j-1] == Q_BASE) { @@ -880,7 +890,7 @@ static void short_range_scan(void) printf(" Quadrant %d, %d\n", q1, q2); if (i == 3) /* @@@ printf(" Sector %d, %d\n", cint(s1), cint(s2)); */ - printf(" Sector %d, %d\n", (int) s1, (int) s2); + printf(" Sector %d, %d\n", FROM_FIXED00(s1), FROM_FIXED00(s2)); if (i == 4) printf(" Photon Torpedoes %d\n", p); if (i == 5) @@ -940,8 +950,9 @@ static void long_range_scan(void) static void phaser_control(void) { register int i; - int iEnergy; - int h1, h; + uint32_t iEnergy; + uint32_t h1; + int h; if (inoperable(4)) return; @@ -972,20 +983,37 @@ static void phaser_control(void) e = e - iEnergy; + /* We can fire up to nearly 3000 points of energy so we do this + bit in 32bit math */ + if (d[8] < 0) /* @@@ iEnergy = iEnergy * rnd(); */ - iEnergy = (int) (iEnergy * rnd()); + iEnergy = iEnergy * get_rand(100); + else + iEnergy *= 100; h1 = iEnergy / k3; +// printf("h1 = %d\n", h1); + for (i = 1; i <= 3; i++) { if (k[i][3] > 0) { - /* @@@ h = (h1 / function_d(0) * (rnd() + 2)); */ - h = (int) (h1 / function_d(0) * (rnd() + 2)); - if (h <= .15 * k[i][3]) { + /* @@@ h = (h1 / distance_to(0) * (rnd() + 2)); */ + /* We are now 32bit with four digits accuracy */ + h = h1 * (get_rand(100) + 200); + /* Takes us down to 2 digit accuracy */ + +// printf("distance_to = %d\n", distance_to(i)); + + h /= distance_to(i); + +// printf("damage base %d\n", h); + + if (h <= 15 * k[i][3]) { /* was 0.15 */ printf("Sensors show no damage to enemy at " "%d, %d\n\n", k[i][1], k[i][2]); } else { + h = FROM_FIXED00(h); k[i][3] = k[i][3] - h; printf("%d unit hit on Klingon at sector " "%d, %d\n", @@ -1016,7 +1044,8 @@ static void photon_torpedoes(void) { /* @@@ int c2, c3, x3, y3, x5; */ int x3, y3; - double c1; + int16_t c1; + int c2, c3, c4; if (p <= 0) { puts("All photon torpedoes expended"); @@ -1028,13 +1057,13 @@ static void photon_torpedoes(void) fputs("Course (0-9): ", stdout); - c1 = input_dec(); + c1 = input_f00(); - if (c1 == 9.0) - c1 = 1.0; + if (c1 == 900) + c1 = 100; /* @@@ if (c1 < 0 || c1 > 9.0) */ - if (c1 < 1.0 || c1 > 9.0) { + if (c1 < 100 || c1 > 900) { printf("Ensign Chekov%s", inc_1); return; } @@ -1042,6 +1071,7 @@ static void photon_torpedoes(void) e = e - 2; p--; +#if 0 /* @@@ c2 = cint(c1); */ /* @@@ c3 = c2 + 1; */ @@ -1050,12 +1080,24 @@ static void photon_torpedoes(void) x1 = c[1][(int) c1] + (c[1][(int) c1 + 1] - c[1][(int) c1]) * (c1 - (int) c1); x2 = c[2][(int) c1] + (c[2][(int) c1 + 1] - c[2][(int) c1]) * (c1 - (int) c1); +#else + + c2 = FROM_FIXED00(c1); /* Integer part */ + c3 = c2 + 1; /* Next integer part */ + c4 = (c1 - TO_FIXED00(c2)); /* Fractional element in fixed point */ + + x1 = 100 * c[1][c2] + (c[1][c3] - c[1][c2]) * c4; + x2 = 100 * c[2][c2] + (c[2][c3] - c[2][c2]) * c4; + +#endif x = s1 + x1; y = s2 + x2; - x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */ - y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */ + /* If the ship is not rounded this is wrong FIXME */ + + x3 = cint100(x); /* @@@ note: this is a true integer round in the MS BASIC version */ + y3 = cint100(y); /* @@@ note: this is a true integer round in the MS BASIC version */ puts("Torpedo Track:"); @@ -1076,8 +1118,8 @@ static void photon_torpedoes(void) x = x + x1; y = y + x2; - x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */ - y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */ + x3 = cint100(x); /* @@@ note: this is a true integer round in the MS BASIC version */ + y3 = cint100(y); /* @@@ note: this is a true integer round in the MS BASIC version */ } puts("Torpedo Missed\n"); @@ -1089,8 +1131,8 @@ static void torpedo_hit(void) { int i, x3, y3; - x3 = cint(x); /* @@@ note: this is a true integer round in the MS BASIC version */ - y3 = cint(y); /* @@@ note: this is a true integer round in the MS BASIC version */ + x3 = cint100(x); /* @@@ note: this is a true integer round in the MS BASIC version */ + y3 = cint100(y); /* @@@ note: this is a true integer round in the MS BASIC version */ switch(quad[x3-1][y3-1]) { case Q_STAR: @@ -1171,6 +1213,7 @@ static void damage_control(void) avoid that round below FIXME */ t = t + (d3 + 5)/10 + 1; } + return; } } @@ -1301,12 +1344,6 @@ static void status_report(void) "Mission must be completed in %d.%d stardates\n", plural, k9, FROM_FIXED(left), left%10); -#if 0 - /* @@@ .1 * cint((t0 + t9 - t) * 10)); */ - /* Force long to avoid overflows: FIXME clean this all up - into fixed point forms */ - .1 * (int) ((t0 + t9 - FROM_FIXED(t)) * 10L)); -#endif if (b9 < 1) { puts("Your stupidity has left you on your own in the galaxy\n" @@ -1338,8 +1375,8 @@ static void torpedo_data(void) for (i = 1; i <= 3; i++) { if (k[i][3] > 0) { - w1 = k[i][1]; - x = k[i][2]; + w1 = TO_FIXED00(k[i][1]); + x = TO_FIXED00(k[i][2]); c1 = s1; a = s2; @@ -1356,14 +1393,15 @@ static void nav_data(void) return; } - w1 = b4; - x = b5; + w1 = TO_FIXED00(b4); + x = TO_FIXED00(b5); c1 = s1; a = s2; compute_vector(); } +/* Q: do we want to support fractional co-ords ? */ static void dirdist_calc(void) { printf("Direction/Distance Calculator\n" @@ -1371,25 +1409,25 @@ static void dirdist_calc(void) "Please enter initial X coordinate: ", q1, q2, /* @@@ cint(s1), cint(s2)); */ - (int) s1, (int) s2); + FROM_FIXED00(s1), FROM_FIXED00(s2)); - c1 = input_int(); - if (c1 < 0) + c1 = TO_FIXED00(input_int()); + if (c1 < 0 || c1 > 900 ) return; fputs("Please enter initial Y coordinate: ", stdout); - a = input_int(); - if (a < 0) + a = TO_FIXED00(input_int()); + if (a < 0 || a > 900) return; fputs("Please enter final X coordinate: ", stdout); - w1 = input_int(); - if (w1 < 0) + w1 = TO_FIXED00(input_int()); + if (w1 < 0 || w1 > 900) return; fputs("Please enter final Y coordinate: ", stdout); - x = input_int(); - if (x < 0) + x = TO_FIXED00(input_int()); + if (x < 0 || x > 900) return; compute_vector(); } @@ -1442,63 +1480,65 @@ static void galaxy_map(void) static void compute_vector(void) { + /* All this is happening in fixed point */ x = x - a; - /* FIXME: until we finish the job */ - a = c1 - (double)w1; + a = c1 - w1; - if (x <= 0.0) { - if (a > 0.0) { - c1 = 3.0; + if (x <= 0) { + if (a > 0) { + c1 = 300; sub2(); return; } else { - c1 = 5.0; + c1 = 500; sub1(); return; } - } else if (a < 0.0) { - c1 = 7.0; + } else if (a < 0) { + c1 = 700; sub2(); return; } else { - c1 = 1.0; + c1 = 100; sub1(); return; } } static const char *dir_1 = " DIRECTION = "; -static const char *dist_1 = " DISTANCE = %4.2f\n\n"; -static const char *f42 = "%4.2f\n"; +static const char *dist_1 = " DISTANCE = %s\n\n"; static void sub1(void) { - x = fabs(x); - a = fabs(a); + uint32_t xl = abs(x); + uint32_t al = abs(a); fputs(dir_1, stdout); - if (a <= x) - printf(f42, c1 + (a / x)); + /* Multiply the top half by 100 as well so that we keep it in fixed00 + format. Our larget value is int 9 (900) so we must do this 32bit */ + if (al <= xl) + printf("%s", print100(c1 + ((al * 100) / xl))); else - printf(f42, c1 + (((a * 2) - x) / a)); + printf("%s", print100(c1 + ((((al * 2) - xl) * 100) / al))); - printf(dist_1, (x > a) ? x : a); + printf(dist_1, print100((xl > al) ? xl : al)); } static void sub2(void) { - x = fabs(x); - a = fabs(a); + uint32_t xl = abs(x); + uint32_t al = abs(a); fputs(dir_1, stdout); - if (a >= x) - printf(f42, c1 + (x / a)); + /* Multiply the top half by 100 to keep in fixed0 */ + if (al >= xl) + printf("%s", print100(c1 + ((xl * 100) / al))); else /* @@@ printf(" DIRECTION = %4.2f\n\n", c1 + (((x * 2) - a) / x)); */ - printf(f42, c1 + (((x * 2) - a) / x)); + printf("%s", print100(c1 + ((((xl * 2) - al) * 100) / x))); /* @@@ printf(" DISTANCE = %4.2f\n", (x > a) ? x : a); */ - printf(dist_1, (x > a) ? x : a); + printf(dist_1, print100((x > a) ? x : a)); } static void ship_destroyed(void) @@ -1531,8 +1571,9 @@ static void won_game(void) /* FIXME: finish integerising this */ if (FROM_FIXED(t) - t0 > 0) - printf("Your efficiency rating is %4.2f\n", 1000 * pow(k7 / (float)(FROM_FIXED(t) - t0), 2)); - + printf("Your efficiency rating is %s\n", + print100(square00(TO_FIXED00(k7)/(FROM_FIXED(t) - t0)))); + // 1000 * pow(k7 / (float)(FROM_FIXED(t) - t0), 2)); end_of_game(); } @@ -1577,7 +1618,8 @@ static const char *dcr_1 = "Damage Control report:"; static void klingons_shoot(void) { - int h, i; + uint32_t h; + uint8_t i; if (k3 <= 0) return; @@ -1589,13 +1631,17 @@ static void klingons_shoot(void) for (i = 1; i <= 3; i++) { if (k[i][3] > 0) { - h = (int) ((k[i][3] / function_d(i)) * (2 + rnd())); - s = s - h; + h = k[i][3] * (200 + get_rand(100)); + h *= 100; /* Ready for division in fixed */ + h /= distance_to(i); + /* Takes us back into FIXED00 */ + s = s - FROM_FIXED00(h); /* @@@ k[i][3] = k[i][3] / (3 + rnd()); */ - k[i][3] = (int) (k[i][3] / (3 + rnd())); + + k[i][3] = (k[i][3] * 100) / (300 + get_rand(100)); printf("%d unit hit on Enterprise from sector " - "%d, %d\n", h, k[i][1], k[i][2]); + "%d, %d\n", FROM_FIXED00(h), k[i][1], k[i][2]); if (s <= 0) { putchar('\n'); @@ -1608,7 +1654,7 @@ static void klingons_shoot(void) /* The check in basic is float and is h/s >.02. We have to use 32bit values here to avoid an overflow FIXME: use a better algorithm perhaps ? */ - uint32_t ratio = TO_FIXED00((uint32_t)h)/s; + uint32_t ratio = ((uint32_t)h)/s; if (get_rand(10) <= 6 || ratio > 2) { r1 = rand8(); /* The original basic code computed h/s in @@ -1654,7 +1700,7 @@ static void repair_damage(void) if (get_rand(10) <= 2) { r1 = rand8(); - if (rnd() < .6) { + if (get_rand(10) < 6) { /* Working in 1/100ths */ d[r1] = d[r1] - (get_rand(500) + 100); //TO_FIXED00((rnd() * 5.0 + 1.0)); @@ -1725,12 +1771,56 @@ static void quadrant_name(void) return; } -static int function_d(int i) +/* An unsigned sqrt is all we need. + + What we are actually doing here is a smart version of calculating n^2 + repeatedly until we find the right one */ +static int16_t isqrt(int16_t i) +{ + uint16_t b = 0x4000, q = 0, r = i, t; +// printf("isqrt %d=", i); + while (b) { + t = q + b; + q >>= 1; + if (r >= t) { + r -= t; + q += b; + } + b >>= 2; + } +// printf("%d\n", q); + return q; +} + +static int square00(int16_t t) +{ +// printf("square00 %d = ", t); + if (t > 181) { + t /= 10; + t *= t; + } else { + t *= t; + t /= 100; + } +// printf("%d\n", t); + return t; +} + +/* Return the distance to an object in x.xx fixed point */ +static int distance_to(int i) { int j; + /* We do the squares in fixed point maths */ + j = square00(TO_FIXED00(k[i][1]) - s1); + j += square00(TO_FIXED00(k[i][2]) - s2); + + /* Find the integer square root */ + j = isqrt(j); + /* Correct back into 0.00 fixed point */ + j *= 10; /* @@@ j = sqrt(pow((k[i][1] - s1), 2) + pow((k[i][2] - s2), 2)); */ - j = (int) sqrt(pow((k[i][1] - s1), 2) + pow((k[i][2] - s2), 2)); +// j = (int) sqrt(pow((k[i][1] - s1), 2) + pow((k[i][2] - s2), 2)); return j; } @@ -1738,15 +1828,6 @@ static int function_d(int i) /* Round off floating point numbers instead of truncating */ -static int cint(double d) -{ - int i; - - i = (int) (d + 0.5); - - return (i); -} - static int cint100(int16_t d) { return (d + 50) / 100; @@ -1773,11 +1854,3 @@ static void showfile(char *filename) fclose(fp); } -static double rnd(void) -{ - double d; - - d = rand() / (double) RAND_MAX; - - return (d); -} -- 2.34.1