My 1988 Commodore Amiga 2000 Is Still Functioning by James Pate Williams, Jr.

On Friday September 8, 2023, I setup my thirty-five-year-old personal computer which is a Commodore Amiga 2000. My father bought the computer for me on Saturday, April 30, 1988. It still works although the Commodore 1084 RGB color display has a non-functional power button. My remedy for the problem was to Scotch tape the power button in the “On” position. I have an Amiga BASIC by Microsoft manual and software, a Modula-2 compiler, Motorola MC68000 macro-assembly language software, and a Pecan UCSD Pascal compiler. The Amiga was the first multimedia personal computer. In May 1988 I created two Amiga BASIC programs: a keyboard emulator and a primitive computer-generated music program that used three types of noise namely Brownian, fractal, and white noise. I used the computer extensively in the years 1988 to 1994. In December 1994 my mother and older sister purchased a mom-and-pop store Microsoft-Intel personal computer.

Numerical Two-Dimensional Quadrature (Integration) by James Pate Williams, Jr.

Back in 2022 I performed some numerical experiments using the two-dimensional quadrature methods: Simpson’s Rule and Monte Carlo. I implemented both sequential and multitasking techniques. The integration algorithms were applied to electron-electron repulsion integrals and a two-dimensional exponential function. The two-dimensional exponential function has an exact value of pi divided by 4. The multitasking speed-up is about two-fold in the Simpson’s Rule case and almost three-fold in the Monte Carlo case.

Scale Model Construction Suggestions by James Pate Williams, Jr.

  1. After opening the box and making sure all pieces are on their numbered tree (sprue), read and study all the instructions.
  2. I like to paint the pieces while the part is on its tree.
  3. Make notes by grouping the pieces by color.
  4. I like to use acrylic paints nowadays (way back when I used enamel and enamel aerosol spray cans). Acrylic paint is easy to clean up and cures (completely dries) faster than enamel paint.
  5. Do subassemblies according to the instructions. Sometimes it is good to look ahead and make sure the assembly is facile.
  6. Do not wait until the model is finished to apply decals.
  7. Not everyone will have the artistic talent  to create a museum worthy model. Be satisfied with your current modeling ability. Happy scale modeling!

I took up plastic scale modeling again in about 2017 at the age of around 64. Here is a list of my models and some notes about their construction. All of my relatively modern models are by Revell:

  1. USS Arizona – To accurately build the hull tape off the armor belt and apply black paint. This model was painted with Testors enamel paint.
  2. USAAF B-17G Flying Fortress heavy bomber 1:48 scale. Use rubber bands and clothes pins to make sure the fuselage halves seal nicely.
  3. USN or USMC Vought F4U Corsair 1:48 scale. Be careful with the undercarriage. The landing gear is especially tricky to get correct.
  4. USAF Fairchild Republic A-10 Thunderbolt II “Warthog” 1:48 scale. I have not applied the plethora of decals. Please counterweights in the nose so the tricycle landing gear is accurate.
  5. McDonnell Douglas USMC or USN F/A-18 Hornet. Tricky landing gear assembly.
  6. Kriegsmarine Bismarck 1:350 scale. Many very small parts.
  7. Lockheed SR-71 Blackbird 1:48 scale. Lots of rather small decals. You can build different “Articles” (CIA lingo for the A-12 Archangel [Oxcart, Cygnus] and SR-71). The red no step decals are especially tricky to apply. Uses a lot of black paint.
  8. Apollo 11 Saturn V with the command module and lunar excursion module (LEM) 1:144 scale. Comes with three to scale engineers.
  9. USAAF Northup P-61 Black Widow 1:48 scale. The model comes in black plastic, so I did not paint the exterior. The radar in the nose is hard to get correctly seated.
  10. North American B-25J Mitchell medium bomber 1:48 scale. I am still working on this model.

If you have plenty of cash and patience, you can use spray paint. I prefer the somewhat inexpensive brush painting.

Battle of Thermopylae by James Pate Williams, Jr.

Battle of Thermopylae – World History Encyclopedia

“The Greek forces included 300 Spartans and their helots with 2,120 Arcadians, 1,000 Lokrians, 1,000 Phokians, 700 Thespians, 400 Corinthians, 400 Thebans, 200 men from Phleious, and 80 Mycenaeans.” The Persians led by Xerxes I were myriad.

There have been at least two large scale motion pictures made about the battle namely “The 300 Spartans (1962)” and the “300 (2006)”. I have seen both movies, but I prefer the 1962 version due to attempted adherence to Herodotus’ version of the history. The ending of the 1962 movie has a small remaining contingent of Spartans led by King Leonidas I dropping their shields in a mass suicide by a barrage of Persian arrows (“the sky was black with arrows”). “Oh stranger, tell the Spartans that we lie here obedient to their word.” The mantra of the Spartans was to come home to Sparta carrying their shields or to come home being carried dead on their shields. The 300 Spartans – Wikipedia

Latest Revell Model Build by James Pate Williams, Jr.

A few days ago, I finished my Revell 1:144 scale Apollo 11 and Saturn V plastic model. The kit had 82 parts and I used every one of the pieces. I deviated from the original paint scheme since the original black and white pattern is too reminiscent of Wehner von Braun’s World War II terror weapon, the V-2 also known as Retaliation Weapon 2. The V-2 was the first liquid propelled ballistic missile. It used ethanol as the fuel and liquid oxygen as the oxidizing agent.

https://en.wikipedia.org/wiki/V-2_rocket

The Saturn V used high-grade kerosene as the propellant and liquid oxygen as the oxidizing chemical.

https://en.wikipedia.org/wiki/Apollo_11

Here are some temporary photographs of my build.

https://share.icloud.com/photos/004LghGpS0wlijbfyqJv4GY6Q

Education

LaGrange College (1971 – 1972, 1976 – 79, BA Chemistry, GPA 3.08)

LaGrange College (1990 – 1994, BS Computer Science, GPA 4.00)

Georgia Institute of Technology (1980 – 1983, No Degree, GPA 2.79)

Auburn University (1998 – 2000, Master of Software Engineering, GPA 3.880)

Auburn University (2000 – 2005, Doctor of Philosophy, Computer Science, GPA 3.871)

New Knight’s Tour Application by James Pate Williams, Jr.

I created a new Win32 desktop C/C++ application to solve the Knight’s Tour. The app is limited to a six-by-six chessboard with any desired starting column and row. The user can choose between two algorithms to solve an instance of the problem, namely chronological backtracking and Warnsdorff method. A complete circuit or tour is found by both algorithms in between 30 and 40 seconds for backtracking and 2 to 3 seconds for the Warnsdorff method. The starting row is 3 and starting column 4 for to find a cyclic solution.

n-Body Solar System Software by James Pate Williams, Jr.

I have solved two planetary models of our solar system. The first was by approximating the Taylor series expansion for a n-body gravitational system. The approximate equations are given below:

The second computation used a fifth order Runge-Kutta method to solve the system of 3n second order non-linear ordinary differential equations. See the code below:

using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace nBodyProblem
{
    public struct Vector3
    {
        public double x, y, z;
    }

    class nBodyTaylorSeries
    {
        private double G = 6.67384e-11;    // gravitational constant
        private int n;                     // number of masses
        private List<double> Mass;         // masses
        private List<Vector3> X0;          // initial positions
        private List<Vector3> V0;          // initial velocities

        public nBodyTaylorSeries(
            int n,
            List<double> Mass,
            List<Vector3> X0,
            List<Vector3> V0)
        {
            this.n = n;
            this.Mass = Mass;
            this.X0 = X0;
            this.V0 = V0;
        }

        private double Distance(Vector3 u, Vector3 v)
        {
            // Euclidean distance
            double uvxs = Math.Pow(u.x - v.x, 2);
            double uvys = Math.Pow(u.y - v.y, 2);
            double uvzs = Math.Pow(u.z - v.z, 2);

            return Math.Sqrt(uvxs + uvys + uvzs);
        }

        private Vector3 D2(
            int i,
            List<Vector3> X)
        {
            // second derivative at t0

            double sumX = 0, sumY = 0, sumZ = 0;
            Vector3 d2 = new Vector3();

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 3);
                    double m = Mass[k];

                    sumX += m * (X[k].x - X[i].x) / d;
                    sumY += m * (X[k].y - X[i].y) / d;
                    sumZ += m * (X[k].z - X[i].z) / d;
                }
            }

            d2.x = G * sumX;
            d2.y = G * sumY;
            d2.z = G * sumZ;
            return d2;
        }

        private Vector3 D3(
            int i,
            List<Vector3> X,
            List<Vector3> V)
        {
            // third derivative at t0

            double sumX1 = 0, sumY1 = 0, sumZ1 = 0;
            double sumX2 = 0, sumY2 = 0, sumZ2 = 0;
            Vector3 d3 = new Vector3();

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 3);
                    double m = Mass[k];

                    sumX1 += m * (V[k].x - V[i].x) / d;
                    sumY1 += m * (V[k].y - V[i].y) / d;
                    sumZ1 += m * (V[k].z - V[i].z) / d;
                }
            }

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 5);
                    double m = Mass[k];

                    sumX2 += m * (X[k].x - X[i].x) * (V[k].x - V[i].x) / d;
                    sumY2 += m * (X[k].y - X[i].y) * (V[k].y - V[i].y) / d;
                    sumZ2 += m * (X[k].z - X[i].z) * (V[k].z - V[i].z) / d;
                }
            }

            d3.x = G * (sumX1 - 1.5 * sumX2);
            d3.y = G * (sumY1 - 1.5 * sumY2);
            d3.z = G * (sumZ1 - 1.5 * sumZ2);
            return d3;
        }

        private Vector3 D4(
            int i,
            List<Vector3> X,
            List<Vector3> V,
            List<Vector3> A)
        {
            // fourth derivative at t0

            double sumX1 = 0, sumY1 = 0, sumZ1 = 0;
            double sumX2 = 0, sumY2 = 0, sumZ2 = 0;
            double sumX3 = 0, sumY3 = 0, sumZ3 = 0;
            double sumX4 = 0, sumY4 = 0, sumZ4 = 0;
            Vector3 d4 = new Vector3();

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 3);
                    double m = Mass[k];

                    sumX1 += m * (A[k].x - A[i].x) / d;
                    sumY1 += m * (A[k].y - A[i].y) / d;
                    sumZ1 += m * (A[k].z - A[i].z) / d;
                }
            }

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 5);
                    double m = Mass[k];

                    sumX2 += m * (X[k].x - X[i].x) * (A[k].x - A[i].x) / d;
                    sumY2 += m * (X[k].y - X[i].y) * (A[k].y - A[i].y) / d;
                    sumZ2 += m * (X[k].z - X[i].z) * (A[k].z - A[i].z) / d;
                }
            }

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 5);
                    double m = Mass[k];

                    sumX3 += m * Math.Pow(V[k].x - V[i].x, 2) / d;
                    sumY3 += m * Math.Pow(V[k].y - V[i].y, 2) / d;
                    sumZ3 += m * Math.Pow(V[k].z - V[i].z, 2) / d;
                }
            }

            for (int k = 0; k < n; k++)
            {
                if (k != i)
                {
                    double d = Math.Pow(Distance(X[k], X[i]), 7);
                    double m = Mass[k];

                    sumX4 += m * (X[k].x - X[i].x) * Math.Pow(V[k].x - V[i].x, 2) / d;
                    sumY4 += m * (X[k].y - X[i].y) * Math.Pow(V[k].y - V[i].y, 2) / d;
                    sumZ4 += m * (X[k].z - X[i].z) * Math.Pow(V[k].z - V[i].z, 2) / d;
                }
            }

            d4.x = G * (sumX1 - 1.5 * sumX2 - 3 * sumX3 + 15 * sumX4 / 4);
            d4.y = G * (sumY1 - 1.5 * sumY2 - 3 * sumY3 + 15 * sumY4 / 4);
            d4.z = G * (sumZ1 - 1.5 * sumZ2 - 3 * sumZ3 + 15 * sumZ4 / 4);
            return d4;
        }

        public Vector3 Position(
            int day0,
            int day1,
            int i,
            BackgroundWorker worker,
            DoWorkEventArgs e)
        {
            double t0 = day0 * 24 * 3600;
            double t1 = day1 * 24 * 3600;
            double delta = 60, t = t0;
            List<Vector3> Q0 = new List<Vector3>();
            List<Vector3> R0 = new List<Vector3>();

            for (int j = 0; j < n; j++)
            {
                Q0.Add(X0[j]);
                R0.Add(V0[j]);
            }

            while (t <= t1)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    t = t1 + delta;
                }

                else
                {
                    List<Vector3> Q1 = new List<Vector3>();
                    List<Vector3> R1 = new List<Vector3>();
                    List<Vector3> d2 = new List<Vector3>();
                    List<Vector3> d3 = new List<Vector3>();
                    List<Vector3> d4 = new List<Vector3>();

                    for (int j = 0; j < n; j++)
                    {
                        // update derivatives
                        d2.Add(D2(j, Q0));
                        d3.Add(D3(j, Q0, R0));
                        Q1.Add(new Vector3());
                        R1.Add(new Vector3());
                    }

                    for (int j = 0; j < n; j++)
                        d4.Add(D4(i, Q0, R0, d2));

                    for (int j = 0; j < n; j++)
                    {
                        double m = Mass[j];
                        Vector3 Qj = new Vector3();
                        // update positions
                        Qj.x = Q0[j].x + delta * (R0[j].x + (delta * (d2[j].x / 2 + delta * (d3[j].x / 6 + delta * d4[j].x / 24)) / m));
                        Qj.y = Q0[j].y + delta * (R0[j].y + (delta * (d2[j].y / 2 + delta * (d3[j].y / 6 + delta * d4[j].y / 24)) / m));
                        Qj.z = Q0[j].z + delta * (R0[j].z + (delta * (d2[j].z / 2 + delta * (d3[j].z / 6 + delta * d4[j].z / 24)) / m));
                        Q1[j] = Qj;
                    }

                    for (int j = 0; j < n; j++)
                    {
                        double m = Mass[j];
                        Vector3 Rj = new Vector3();
                        // update velocities
                        Rj.x = R0[j].x + delta * (d2[j].x + delta * (d3[j].x / 2 + delta * d4[j].x / 6)) / m;
                        Rj.y = R0[j].y + delta * (d2[j].y + delta * (d3[j].y / 2 + delta * d4[j].y / 6)) / m;
                        Rj.z = R0[j].z + delta * (d2[j].z + delta * (d3[j].z / 2 + delta * d4[j].z / 6)) / m;
                        R1[j] = Rj;
                    }

                    for (int j = 0; j < n; j++)
                    {
                        Q0[j] = Q1[j];
                        R0[j] = R1[j];
                    }

                    t += delta;

                    int percentProgress = (int)(100 * t / t1);

                    worker.ReportProgress(percentProgress);
                }
            }

            // update positions and velocities
            X0 = new List<Vector3>();
            V0 = new List<Vector3>();

            for (int j = 0; j < n; j++)
            {
                X0.Add(Q0[j]);
                V0.Add(R0[j]);
            }

            return Q0[i];
        }
    }
}

using System;
using System.Collections.Generic;

namespace nBodyProblem
{
    public struct Vector3
    {
        public double x, y, z;
    }

    class RK3N
    {
        // function rk3n from "A Numerical Library in C for
        // Scientists and Engineers" by J.T. Lau PhD p. 465
        private void rk3n(ref double x, double a, double b,
            double[] y, double[] ya, double[] z, double[] za,
            Func<int, int, double, double[], double> fxyj,
            double[] e, double[] d, bool fi, int n)
        {
            bool first, last=false, reject, test, ta, tb;
            int j, jj;
            double xl, h, hmin, ind, hl=0, absh, fhm, discry, discrz, toly, tolz, mu, mu1=0, fhy, fhz;

            double[] yl = new double[n + 1];
            double[] zl = new double[n + 1];
            double[] k0 = new double[n + 1];
            double[] k1 = new double[n + 1];
            double[] k2 = new double[n + 1];
            double[] k3 = new double[n + 1];
            double[] k4 = new double[n + 1];
            double[] k5 = new double[n + 1];
            double[] ee = new double[4 * n + 1];

            if (fi)
            {
                d[3] = a;
                for (jj = 1; jj <= n; jj++)
                {
                    d[jj + 3] = ya[jj];
                    d[n + jj + 3] = za[jj];
                }
            }
            d[1] = 0.0;
            xl = d[3];
            for (jj = 1; jj <= n; jj++)
            {
                yl[jj] = d[jj + 3];
                zl[jj] = d[n + jj + 3];
            }
            if (fi) d[2] = b - d[3];
            absh = h = Math.Abs(d[2]);
            if (b - xl < 0.0) h = -h;
            ind = Math.Abs(b - xl);
            hmin = ind * e[1] + e[2];
            for (jj = 2; jj <= 2 * n; jj++)
            {
                hl = ind * e[2 * jj - 1] + e[2 * jj];
                if (hl < hmin) hmin = hl;
            }
            for (jj = 1; jj <= 4 * n; jj++) ee[jj] = e[jj] / ind;
            first = reject = true;
            test = true;
            if (fi)
            {
                last = true;
                test = false;
            }
            while (true)
            {
                if (test)
                {
                    absh = Math.Abs(h);
                    if (absh < hmin)
                    {
                        h = (h > 0.0) ? hmin : -hmin;
                        absh = hmin;
                    }
                    ta = (h >= b - xl);
                    tb = (h >= 0.0);
                    if ((ta && tb) || (!(ta || tb)))
                    {
                        d[2] = h;
                        last = true;
                        h = b - xl;
                        absh = Math.Abs(h);
                    }
                    else
                        last = false;
                }
                test = true;
                if (reject)
                {
                    x = xl;
                    for (jj = 1; jj <= n; jj++) y[jj] = yl[jj];
                    for (j = 1; j <= n; j++) k0[j] = fxyj(n, j, x, y) * h;
                }
                else
                {
                    fhy = h / hl;
                    for (jj = 1; jj <= n; jj++) k0[jj] = k5[jj] * fhy;
                }
                x = xl + 0.276393202250021 * h;
                for (jj = 1; jj <= n; jj++)
                    y[jj] = yl[jj] + (zl[jj] * 0.276393202250021 +
                                    k0[jj] * 0.038196601125011) * h;
                for (j = 1; j <= n; j++) k1[j] = fxyj(n, j, x, y) * h;
                x = xl + 0.723606797749979 * h;
                for (jj = 1; jj <= n; jj++)
                    y[jj] = yl[jj] + (zl[jj] * 0.723606797749979 +
                                    k1[jj] * 0.261803398874989) * h;
                for (j = 1; j <= n; j++) k2[j] = fxyj(n, j, x, y) * h;
                x = xl + h * 0.5;
                for (jj = 1; jj <= n; jj++)
                    y[jj] = yl[jj] + (zl[jj] * 0.5 + k0[jj] * 0.046875 + k1[jj] *
                            0.079824155839840 - k2[jj] * 0.001699155839840) * h;
                for (j = 1; j <= n; j++) k4[j] = fxyj(n, j, x, y) * h;
                x = (last ? b : xl + h);
                for (jj = 1; jj <= n; jj++)
                    y[jj] = yl[jj] + (zl[jj] + k0[jj] * 0.309016994374947 +
                                    k2[jj] * 0.190983005625053) * h;
                for (j = 1; j <= n; j++) k3[j] = fxyj(n, j, x, y) * h;
                for (jj = 1; jj <= n; jj++)
                    y[jj] = yl[jj] + (zl[jj] + k0[jj] * 0.083333333333333 + k1[jj] *
                            0.301502832395825 + k2[jj] * 0.115163834270842) * h;
                for (j = 1; j <= n; j++) k5[j] = fxyj(n, j, x, y) * h;
                reject =false;
                fhm = 0.0;
                for (jj = 1; jj <= n; jj++)
                {
                    discry = Math.Abs((-k0[jj] * 0.5 + k1[jj] * 1.809016994374947 +
                                k2[jj] * 0.690983005625053 - k4[jj] * 2.0) * h);
                    discrz = Math.Abs((k0[jj] - k3[jj]) * 2.0 - (k1[jj] + k2[jj]) * 10.0 +
                                k4[jj] * 16.0 + k5[jj] * 4.0);
                    toly = absh * (Math.Abs(zl[jj]) * ee[2 * jj - 1] + ee[2 * jj]);
                    tolz = Math.Abs(k0[jj]) * ee[2 * (jj + n) - 1] + absh * ee[2 * (jj + n)];
                    reject = ((discry > toly) || (discrz > tolz) || reject);
                    fhy = discry / toly;
                    fhz = discrz / tolz;
                    if (fhz > fhy) fhy = fhz;
                    if (fhy > fhm) fhm = fhy;
                }
                mu = 1.0 / (1.0 + fhm) + 0.45;
                if (reject)
                {
                    if (absh <= hmin)
                    {
                        d[1] += 1.0;
                        for (jj = 1; jj <= n; jj++)
                        {
                            y[jj] = yl[jj];
                            z[jj] = zl[jj];
                        }
                        first = true;
                        if (b == x) break;
                        xl = x;
                        for (jj = 1; jj <= n; jj++)
                        {
                            yl[jj] = y[jj];
                            zl[jj] = z[jj];
                        }
                    }
                    else
                        h *= mu;
                }
                else
                {
                    if (first)
                    {
                        first = false;
                        hl = h;
                        h *= mu;
                    }
                    else
                    {
                        fhy = mu * h / hl + mu - mu1;
                        hl = h;
                        h *= fhy;
                    }
                    mu1 = mu;
                    for (jj = 1; jj <= n; jj++)
                        z[jj] = zl[jj] + (k0[jj] + k3[jj]) * 0.083333333333333 +
                            (k1[jj] + k2[jj]) * 0.416666666666667;
                    if (b == x) break;
                    xl = x;
                    for (jj = 1; jj <= n; jj++)
                    {
                        yl[jj] = y[jj];
                        zl[jj] = z[jj];
                    }
                }
            }
            if (!last) d[2] = h;
            d[3] = x;
            for (jj = 1; jj <= n; jj++)
            {
                d[jj + 3] = y[jj];
                d[n + jj + 3] = z[jj];
            }
        }

        // Euclidean distance
        private double distance(
            double x1,
            double y1,
            double z1,
            double x2,
            double y2,
            double z2)
        {
            double xs = Math.Pow(x1 - x2, 2);
            double ys = Math.Pow(y1 - y2, 2);
            double zs = Math.Pow(z1 - z2, 2);

            return Math.Sqrt(xs + ys + zs);
        }

        // n-body gravitational force
        private double ftxj(int n, int j, double t, double[] x)
        {
            double G = 6.67384e-11; // gravitational constant
            double sum = 0;
            int j3 = j / 3 + 1;
            int m3 = j % 3;

            // remember we are now working with 3n equations
            for (int k = 1; k <= n / 3; k++)
            {
                int k3 = 3 * (k - 1) + 1;

                double d = distance(
                    x[k3],
                    x[k3 + 1],
                    x[k3 + 2],
                    x[j3],
                    x[j3 + 1],
                    x[j3 + 2]);
                double denom = d * d * d;

                if (denom != 0)
                    sum += (x[k3 + m3] - x[j3 + m3]) / denom;
            }

            return G * sum;
        }

        public Vector3 nBody(
            int day0,
            int day1,
            int i,
            int n,
            List<double> Mass,
            ref List<Vector3> X0,
            ref List<Vector3> V0)
        {
            int n3 = 3 * n;                 // 3n equations n (x, y, z)
            double a = day0 * 24 * 3600;    // convert to seconds
            double b = day1 * 24 * 3600;    // convert to seconds
            double x = a;
            double[] y = new double[n3 + 1];
            double[] ya = new double[n3 + 1];
            double[] z = new double[n3 + 1];
            double[] za = new double[n3 + 1];
            double[] e = new double[4 * n3 + 1];
            double[] d = new double[2 * n3 + 4];

            // initialize error constraints
            for (int j = 0; j <= 4 * n3; j++)
                e[j] = 1.0e-12;

            // create a system of 3n equations
            for (int j = 0; j < n; j++)
            {
                int j3 = 3 * j;

                ya[j3 + 1] = X0[j].x;
                ya[j3 + 2] = X0[j].y;
                ya[j3 + 3] = X0[j].z;
                za[j3 + 1] = V0[j].x;
                za[j3 + 2] = V0[j].y;
                za[j3 + 3] = V0[j].z;
            }

            // solve the system of 3n ordinary differential equations
            rk3n(ref x, a, b, y, ya, z, za, ftxj, e, d, true, n3);
            // we return the position of the desired ith body
            Vector3 result = new Vector3();

            int i3 = 3 * i;

            result.x = y[i3 + 1];
            result.y = y[i3 + 2];
            result.z = y[i3 + 3];

            // update the positions and velocities
            // wipe the slates clean
            X0 = new List<Vector3>();
            V0 = new List<Vector3>();

            for (int j = 0; j < n; j++)
            {
                int j3 = 3 * j;
                Vector3 X = new Vector3();  // new position
                Vector3 V = new Vector3();  // new velocity

                X.x = y[j3 + 1];    // 3n position components
                X.y = y[j3 + 2];
                X.z = y[j3 + 3];
                V.x = z[j3 + 1];    // 3n velocity components
                V.y = z[j3 + 2];
                V.z = z[j3 + 3];
                // update vectors
                X0.Add(X);
                V0.Add(V);
            }

            return result;
        }
    }
}

Results will be added at a later date.