#include <stdio.h>
#include <math.h>
#define pi 3.1415926

#ifdef VECTREX
#define int8_t int
#define int16_t long
#else
#define int8_t char
#define int16_t short int
#endif

// fast integer approximation to atan2(x,y) for 6809 - no divides used.
// x,y in range 0:255U (or possibly -128:127, pending confirmation)

static inline int abs(int i) {
  if (i < 0) return -i;
  return i;
}

static inline int Map (int quadrant, int angle) {     // angle is 0..64
  if (quadrant == 0)     return angle;
  if (quadrant == 1)     return 128 - angle;
  if (quadrant == 2)     return (256 - angle) & 255;
  /*if (quadrant == 3)*/ return 128 + angle;
}

unsigned int8_t angle1 (int8_t x, int8_t y) { // slow linear tests - don't use!
  int quadrant = 0;

  if (x > 0) x = -x; else quadrant |= 2;              // make both negative avoids issue with negating -128
  if (y > 0) y = -y; else quadrant |= 1;
  if (y) {
    if ((int16_t) x * 128L > y * 2L)
      return Map (quadrant, 0); // tan(0.5)*128
    if ((int16_t) x * 128L > y * 5L)
      return Map (quadrant, 1); // tan(1.5)*128
    if ((int16_t) x * 128L > y * 8L)
      return Map (quadrant, 2); // tan(2.5)*128
    if ((int16_t) x * 128L > y * 11L)
      return Map (quadrant, 3); // tan(3.5)*128
    if ((int16_t) x * 128L > y * 14L)
      return Map (quadrant, 4); // tan(4.5)*128
    if ((int16_t) x * 128L > y * 17L)
      return Map (quadrant, 5); // tan(5.5)*128
    if ((int16_t) x * 128L > y * 21L)
      return Map (quadrant, 6); // tan(6.5)*128
    if ((int16_t) x * 128L > y * 24L)
      return Map (quadrant, 7); // tan(7.5)*128
    if ((int16_t) x * 128L > y * 27L)
      return Map (quadrant, 8); // tan(8.5)*128
    if ((int16_t) x * 128L > y * 30L)
      return Map (quadrant, 9); // tan(9.5)*128
    if ((int16_t) x * 128L > y * 34L)
      return Map (quadrant, 10);        // tan(10.5)*128
    if ((int16_t) x * 128L > y * 37L)
      return Map (quadrant, 11);        // tan(11.5)*128
    if ((int16_t) x * 128L > y * 41L)
      return Map (quadrant, 12);        // tan(12.5)*128
    if ((int16_t) x * 128L > y * 44L)
      return Map (quadrant, 13);        // tan(13.5)*128
    if ((int16_t) x * 128L > y * 48L)
      return Map (quadrant, 14);        // tan(14.5)*128
    if ((int16_t) x * 128L > y * 51L)
      return Map (quadrant, 15);        // tan(15.5)*128
    if ((int16_t) x * 128L > y * 55L)
      return Map (quadrant, 16);        // tan(16.5)*128
    if ((int16_t) x * 128L > y * 59L)
      return Map (quadrant, 17);        // tan(17.5)*128
    if ((int16_t) x * 128L > y * 62L)
      return Map (quadrant, 18);        // tan(18.5)*128
    if ((int16_t) x * 128L > y * 66L)
      return Map (quadrant, 19);        // tan(19.5)*128
    if ((int16_t) x * 128L > y * 70L)
      return Map (quadrant, 20);        // tan(20.5)*128
    if ((int16_t) x * 128L > y * 75L)
      return Map (quadrant, 21);        // tan(21.5)*128
    if ((int16_t) x * 128L > y * 79L)
      return Map (quadrant, 22);        // tan(22.5)*128
    if ((int16_t) x * 128L > y * 83L)
      return Map (quadrant, 23);        // tan(23.5)*128
    if ((int16_t) x * 128L > y * 88L)
      return Map (quadrant, 24);        // tan(24.5)*128
    if ((int16_t) x * 128L > y * 93L)
      return Map (quadrant, 25);        // tan(25.5)*128
    if ((int16_t) x * 128L > y * 97L)
      return Map (quadrant, 26);        // tan(26.5)*128
    if ((int16_t) x * 128L > y * 102L)
      return Map (quadrant, 27);        // tan(27.5)*128
    if ((int16_t) x * 128L > y * 108L)
      return Map (quadrant, 28);        // tan(28.5)*128
    if ((int16_t) x * 128L > y * 113L)
      return Map (quadrant, 29);        // tan(29.5)*128
    if ((int16_t) x * 128L > y * 119L)
      return Map (quadrant, 30);        // tan(30.5)*128
    if ((int16_t) x * 128L > y * 125L)
      return Map (quadrant, 31);        // tan(31.5)*128
    if ((int16_t) x * 128L > y * 131L)
      return Map (quadrant, 32);        // tan(32.5)*128
    if ((int16_t) x * 128L > y * 138L)
      return Map (quadrant, 33);        // tan(33.5)*128
    if ((int16_t) x * 128L > y * 145L)
      return Map (quadrant, 34);        // tan(34.5)*128
    if ((int16_t) x * 128L > y * 152L)
      return Map (quadrant, 35);        // tan(35.5)*128
    if ((int16_t) x * 128L > y * 160L)
      return Map (quadrant, 36);        // tan(36.5)*128
    if ((int16_t) x * 128L > y * 168L)
      return Map (quadrant, 37);        // tan(37.5)*128
    if ((int16_t) x * 128L > y * 177L)
      return Map (quadrant, 38);        // tan(38.5)*128
    if ((int16_t) x * 128L > y * 187L)
      return Map (quadrant, 39);        // tan(39.5)*128
    if ((int16_t) x * 128L > y * 197L)
      return Map (quadrant, 40);        // tan(40.5)*128
    if ((int16_t) x * 128L > y * 208L)
      return Map (quadrant, 41);        // tan(41.5)*128
    if ((int16_t) x * 128L > y * 220L)
      return Map (quadrant, 42);        // tan(42.5)*128
    if ((int16_t) x * 128L > y * 233L)
      return Map (quadrant, 43);        // tan(43.5)*128
    if ((int16_t) x * 128L > y * 247L)
      return Map (quadrant, 44);        // tan(44.5)*128
    if ((int16_t) x * 64L > y * 131L)
      return Map (quadrant, 45);        // tan(45.5)*64
    if ((int16_t) x * 64L > y * 140L)
      return Map (quadrant, 46);        // tan(46.5)*64
    if ((int16_t) x * 64L > y * 149L)
      return Map (quadrant, 47);        // tan(47.5)*64
    if ((int16_t) x * 64L > y * 160L)
      return Map (quadrant, 48);        // tan(48.5)*64
    if ((int16_t) x * 64L > y * 172L)
      return Map (quadrant, 49);        // tan(49.5)*64
    if ((int16_t) x * 64L > y * 186L)
      return Map (quadrant, 50);        // tan(50.5)*64
    if ((int16_t) x * 64L > y * 202L)
      return Map (quadrant, 51);        // tan(51.5)*64
    if ((int16_t) x * 64L > y * 221L)
      return Map (quadrant, 52);        // tan(52.5)*64
    if ((int16_t) x * 64L > y * 243L)
      return Map (quadrant, 53);        // tan(53.5)*64
    if ((int16_t) x * 32L > y * 135L)
      return Map (quadrant, 54);        // tan(54.5)*32
    if ((int16_t) x * 32L > y * 151L)
      return Map (quadrant, 55);        // tan(55.5)*32
    if ((int16_t) x * 32L > y * 172L)
      return Map (quadrant, 56);        // tan(56.5)*32
    if ((int16_t) x * 32L > y * 199L)
      return Map (quadrant, 57);        // tan(57.5)*32
    if ((int16_t) x * 32L > y * 236L)
      return Map (quadrant, 58);        // tan(58.5)*32
    if ((int16_t) x * 16L > y * 144L)
      return Map (quadrant, 59);        // tan(59.5)*16
    if ((int16_t) x * 16L > y * 186L)
      return Map (quadrant, 60);        // tan(60.5)*16
    if ((int16_t) x * 8L > y * 130L)
      return Map (quadrant, 61);        // tan(61.5)*8
    if ((int16_t) x * 8L > y * 217L)
      return Map (quadrant, 62);        // tan(62.5)*8
    if ((int16_t) x * 2L > y * 163L)
      return Map (quadrant, 63);        // tan(63.5)*2
    else
      return Map (quadrant, 64);        // tan(64.0)
  }
  if (x < 0) return 192;
  if (x) return 64;
  return 0; // Map (quadrant, 64);
}

unsigned int8_t angle2 (int8_t x, int8_t y) { // Much faster binary search...
  int quadrant = 0;

  if (x > 0) x = -x; else quadrant |= 2;              // make both negative avoids issue with negating -128
  if (y > 0) y = -y; else quadrant |= 1;
  if (y) {
    if ((int16_t) x * 128L <= y * 131L) {
      if ((int16_t) x * 64L <= y * 160L) {
        if ((int16_t) x * 32L <= y * 172L) {
          if ((int16_t) x * 16L <= y * 186L) {
            if ((int16_t) x * 8L <= y * 217L) {
              if ((int16_t) x * 2L <= y * 163L)
                return Map (quadrant, 64);      // tan(64.5)*2
              else
                return Map (quadrant, 63);      // tan(63.5)*2
            } else {
              if ((int16_t) x * 8L <= y * 130L)
                return Map (quadrant, 62);      // tan(62.5)*8
              else
                return Map (quadrant, 61);      // tan(61.5)*8
            }
          } else {
            if ((int16_t) x * 32L <= y * 236L) {
              if ((int16_t) x * 16L <= y * 144L)
                return Map (quadrant, 60);      // tan(60.5)*16
              else
                return Map (quadrant, 59);      // tan(59.5)*16
            } else {
              if ((int16_t) x * 32L <= y * 199L)
                return Map (quadrant, 58);      // tan(58.5)*32
              else
                return Map (quadrant, 57);      // tan(57.5)*32
            }
          }
        } else {
          if ((int16_t) x * 64L <= y * 221L) {
            if ((int16_t) x * 32L <= y * 135L) {
              if ((int16_t) x * 32L <= y * 151L)
                return Map (quadrant, 56);      // tan(56.5)*32
              else
                return Map (quadrant, 55);      // tan(55.5)*32
            } else {
              if ((int16_t) x * 64L <= y * 243L)
                return Map (quadrant, 54);      // tan(54.5)*64
              else
                return Map (quadrant, 53);      // tan(53.5)*64
            }
          } else {
            if ((int16_t) x * 64L <= y * 186L) {
              if ((int16_t) x * 64L <= y * 202L)
                return Map (quadrant, 52);      // tan(52.5)*64
              else
                return Map (quadrant, 51);      // tan(51.5)*64
            } else {
              if ((int16_t) x * 64L <= y * 172L)
                return Map (quadrant, 50);      // tan(50.5)*64
              else
                return Map (quadrant, 49);      // tan(49.5)*64
            }
          }
        }
      } else {
        if ((int16_t) x * 128L <= y * 197L) {
          if ((int16_t) x * 128L <= y * 247L) {
            if ((int16_t) x * 64L <= y * 140L) {
              if ((int16_t) x * 64L <= y * 149L)
                return Map (quadrant, 48);      // tan(48.5)*64
              else
                return Map (quadrant, 47);      // tan(47.5)*64
            } else {
              if ((int16_t) x * 64L <= y * 131L)
                return Map (quadrant, 46);      // tan(46.5)*64
              else
                return Map (quadrant, 45);      // tan(45.5)*64
            }
          } else {
            if ((int16_t) x * 128L <= y * 220L) {
              if ((int16_t) x * 128L <= y * 233L)
                return Map (quadrant, 44);      // tan(44.5)*128
              else
                return Map (quadrant, 43);      // tan(43.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 208L)
                return Map (quadrant, 42);      // tan(42.5)*128
              else
                return Map (quadrant, 41);      // tan(41.5)*128
            }
          }
        } else {
          if ((int16_t) x * 128L <= y * 160L) {
            if ((int16_t) x * 128L <= y * 177L) {
              if ((int16_t) x * 128L <= y * 187L)
                return Map (quadrant, 40);      // tan(40.5)*128
              else
                return Map (quadrant, 39);      // tan(39.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 168L)
                return Map (quadrant, 38);      // tan(38.5)*128
              else
                return Map (quadrant, 37);      // tan(37.5)*128
            }
          } else {
            if ((int16_t) x * 128L <= y * 145L) {
              if ((int16_t) x * 128L <= y * 152L)
                return Map (quadrant, 36);      // tan(36.5)*128
              else
                return Map (quadrant, 35);      // tan(35.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 138L)
                return Map (quadrant, 34);      // tan(34.5)*128
              else
                return Map (quadrant, 33);      // tan(33.5)*128
            }
          }
        }
      }
    } else {
      if ((int16_t) x * 128L <= y * 55L) {
        if ((int16_t) x * 128L <= y * 88L) {
          if ((int16_t) x * 128L <= y * 108L) {
            if ((int16_t) x * 128L <= y * 119L) {
              if ((int16_t) x * 128L <= y * 125L)
                return Map (quadrant, 32);      // tan(32.5)*128
              else
                return Map (quadrant, 31);      // tan(31.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 113L)
                return Map (quadrant, 30);      // tan(30.5)*128
              else
                return Map (quadrant, 29);      // tan(29.5)*128
            }
          } else {
            if ((int16_t) x * 128L <= y * 97L) {
              if ((int16_t) x * 128L <= y * 102L)
                return Map (quadrant, 28);      // tan(28.5)*128
              else
                return Map (quadrant, 27);      // tan(27.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 93L)
                return Map (quadrant, 26);      // tan(26.5)*128
              else
                return Map (quadrant, 25);      // tan(25.5)*128
            }
          }
        } else {
          if ((int16_t) x * 128L <= y * 70L) {
            if ((int16_t) x * 128L <= y * 79L) {
              if ((int16_t) x * 128L <= y * 83L)
                return Map (quadrant, 24);      // tan(24.5)*128
              else
                return Map (quadrant, 23);      // tan(23.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 75L)
                return Map (quadrant, 22);      // tan(22.5)*128
              else
                return Map (quadrant, 21);      // tan(21.5)*128
            }
          } else {
            if ((int16_t) x * 128L <= y * 62L) {
              if ((int16_t) x * 128L <= y * 66L)
                return Map (quadrant, 20);      // tan(20.5)*128
              else
                return Map (quadrant, 19);      // tan(19.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 59L)
                return Map (quadrant, 18);      // tan(18.5)*128
              else
                return Map (quadrant, 17);      // tan(17.5)*128
            }
          }
        }
      } else {
        if ((int16_t) x * 128L <= y * 27L) {
          if ((int16_t) x * 128L <= y * 41L) {
            if ((int16_t) x * 128L <= y * 48L) {
              if ((int16_t) x * 128L <= y * 51L)
                return Map (quadrant, 16);      // tan(16.5)*128
              else
                return Map (quadrant, 15);      // tan(15.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 44L)
                return Map (quadrant, 14);      // tan(14.5)*128
              else
                return Map (quadrant, 13);      // tan(13.5)*128
            }
          } else {
            if ((int16_t) x * 128L <= y * 34L) {
              if ((int16_t) x * 128L <= y * 37L)
                return Map (quadrant, 12);      // tan(12.5)*128
              else
                return Map (quadrant, 11);      // tan(11.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 30L)
                return Map (quadrant, 10);      // tan(10.5)*128
              else
                return Map (quadrant, 9);       // tan(9.5)*128
            }
          }
        } else {
          if ((int16_t) x * 128L <= y * 14L) {
            if ((int16_t) x * 128L <= y * 21L) {
              if ((int16_t) x * 128L <= y * 24L)
                return Map (quadrant, 8);       // tan(8.5)*128
              else
                return Map (quadrant, 7);       // tan(7.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 17L)
                return Map (quadrant, 6);       // tan(6.5)*128
              else
                return Map (quadrant, 5);       // tan(5.5)*128
            }
          } else {
            if ((int16_t) x * 128L <= y * 8L) {
              if ((int16_t) x * 128L <= y * 11L)
                return Map (quadrant, 4);       // tan(4.5)*128
              else
                return Map (quadrant, 3);       // tan(3.5)*128
            } else {
              if ((int16_t) x * 128L <= y * 5L) {
                return Map (quadrant, 2);       // tan(2.5)*128 hi==lo
              } else {
                if ((int16_t) x * 128L <= y * 2L)
                  return Map (quadrant, 1);     // tan(1.5)*128
                else
                  return Map (quadrant, 0);     // tan(0.5)*128
              }
            }
          }
        }
      }
    }
  }
  if (x < 0) return 192;
  if (x) return 64;
  return 0; // Map (quadrant, 64);
}

int main (int argc, char **argv) {
  int x, y;

  for (x = -128; x < 128; x++) {
    for (y = -128; y < 128; y++) {
      // we allow difference of 1 from atan2 result due to difference in rounding - I think ours is more accurate - in any case, accurate enough for a video game...
      if ((angle1 (x, y) != angle2 (x, y)) || ((char)abs(angle2(x,y) - (char)(255&(int)round((atan2(x,y) * 256) / (2.0 * pi))))>1))
        fprintf (stdout, "x%d y%d a1:%d a2:%d atan: %3.2f\n", x, y, angle1 (x, y), angle2 (x, y), (atan2(x,y) * 256) / (2.0 * pi) + (atan2(x,y)<0 ? 256:0));
    }
  }

}
