/* This is a code fragment used to update a Moore neighbourhood cellular automaton.
 * It is called for every cell in the grid with n, e, s, w, ne, nw, se, sw, c set up,
 * and returns the new value.
 * I pack two 16-bit values into one Java int for performance reasons.
 */

      // Normal usage
         mo = 
               new MooreOperation() {
                  int tfu;
                  int tfv;
                  int frp2;
               
                  void init() {
                     t.tfu_max = -1;
                     t.tfv_max = -1;
                     t.tfu_min = 0x10000;
                     t.tfv_min = 0x10000;
                  
                     frp2 = (flow_rate + 2);
                  }
               
               
               // U = LIQUID, V = GROUND.
               
                  int process() {
                  // does everything twice - a pity...
                     int hne, hse, hnw, hsw, hn, hs, he, hw, hc;
                     int dne, dse, dnw, dsw, dn, ds, de, dw, dc;
                     int sum_ne, sum_se, sum_nw, sum_sw, sum_n, sum_s, sum_e, sum_w, sum_c;
                     int rne, rse, rnw, rsw, rn, rs, re, rw;
                  
                  // get heights...
                     hn  = n >>> 16;
                     hs  = s >>> 16;
                     he  = e >>> 16;
                     hw  = w >>> 16;
                     hc  = c >>> 16;
                     hne = ne >>> 16;
                     hnw = nw >>> 16;
                     hse = se >>> 16;
                     hsw = sw >>> 16;
                  
                  // get densities...
                     dn  = n & 0xFFFF;
                     ds  = s & 0xFFFF;
                     de  = e & 0xFFFF;
                     dw  = w & 0xFFFF;
                     dc  = c & 0xFFFF;
                     dne = ne & 0xFFFF;
                     dnw = nw & 0xFFFF;
                     dse = se & 0xFFFF;
                     dsw = sw & 0xFFFF;
                  
                  // flow:
                  // in proportion...
                  // make index variable...
                     re  = (((he  - hc) * de ) >> flow_rate);
                     rw  = (((hw  - hc) * dw ) >> flow_rate);
                     rn  = (((hn  - hc) * dn ) >> flow_rate);
                     rs  = (((hs  - hc) * ds ) >> flow_rate);
                     rne =  ((((hne - hc) * dne) >> frp2)); //  * 11) >> 11);
                     rse =  ((((hse - hc) * dse) >> frp2)); // * 11) >> 11);
                     rnw =  ((((hnw - hc) * dnw) >> frp2)); //* 11) >> 11);
                     rsw =  ((((hsw - hc) * dsw) >> frp2)); // * 11) >> 11);
                  
                     int max_liquid_available = dc >> 3;
                  
                     if (re > (de >> 3)) {
                        re = de >> 3;
                     }
                  
                     if (-re > (max_liquid_available)) {
                        re = -max_liquid_available;
                     }
                  
                     if (rw > (dw >> 3)) {
                        rw = dw >> 3;
                     }
                  
                     if (-rw > (max_liquid_available)) {
                        rw = -max_liquid_available;
                     }
                  
                     if (rn > (dn >> 3)) {
                        rn = dn >> 3;
                     }
                  
                     if (-rn > (max_liquid_available)) {
                        rn = -max_liquid_available;
                     }
                  
                     if (rs > (ds >> 3)) {
                        rs = ds >> 3;
                     }
                  
                     if (-rs > (max_liquid_available)) {
                        rs = -max_liquid_available;
                     }
                  
                     if (rne > (dne >> 3)) {
                        rne = dne >> 3;
                     }
                  
                     if (-rne > (max_liquid_available)) {
                        rne = -max_liquid_available;
                     }
                  
                     if (rse > (dse >> 3)) {
                        rse = dse >> 3;
                     }
                  
                     if (-rse > (max_liquid_available)) {
                        rse = -max_liquid_available;
                     }
                  
                     if (rnw > (dnw >> 3)) {
                        rnw = dnw >> 3;
                     }
                  
                     if (-rnw > (max_liquid_available)) {
                        rnw = -max_liquid_available;
                     }
                  
                     if (rsw > (dsw >> 3)) {
                        rsw = dsw >> 3;
                     }
                  
                     if (-rsw > (max_liquid_available)) {
                        rsw = -max_liquid_available;
                     }
                  
                  // rain...
                     tfu = (((dc << 3) + rn + rs + re + rw + rne + rse + rnw + rsw) >> 3) - seep_rate;
                     if (hc > upper_threshold) {
                        tfu += t.rnd.nextInt(add_rate); // rain on high ground...
                     }
                  
                     if (hc < lower_threshold) {
                        tfu -= 0x4000; // seep into low ground...
                     }
                  
                     tfu = (tfu < 0) ? 0 : ((tfu > 0xFFFF) ? 0xFFFF : tfu);
                  
                     tfv = (((hc * 52) + (hn * 51) + (hs * 51) + (he * 51) + (hw * 51)) >> 8) //  + hne + hnw + hse + hsw) >> 3) // ground diffusion
                        //tfv = ((hn + hs + he + hw + hne + hnw + hse + hsw) >> 3) // Moore ground diffusion...
                        + ground_rising; // ground rising up 
                  
                     tfv -= // etching_intensity
                           (  ((rnw > 0) ? rnw : -rnw) +
                              ((rne > 0) ? rne : -rne) +
                              ((rsw > 0) ? rsw : -rsw) +
                              ((rse > 0) ? rse : -rse) +
                              ((rn > 0)  ? rn  : -rn ) +
                              ((rs > 0)  ? rs  : -rs ) +
                              ((re > 0)  ? re  : -re ) +
                              ((rw > 0)  ? rw  : -rw)) >> log_resistance;
                  
                  // maximum and minimum check...
                  
                     tfv = (tfv < 0) ? 0 : ((tfv > 0xFFFF) ? 0xFFFF : tfv);
                  
                     t.tfu_max = (tfu > t.tfu_max) ? tfu : t.tfu_max;
                     t.tfu_min = (tfu < t.tfu_min) ? tfu : t.tfu_min;
                     t.tfv_max = (tfv > t.tfv_max) ? tfv : t.tfv_max;
                     t.tfv_min = (tfv < t.tfv_min) ? tfv : t.tfv_min;
                  
                     return tfu | (tfv << 16);
                  }
               };
