1 ladder: proc (xp, gn, mycolor);
  2 
  3 /* LADDER - knows the ladders for gogame.
  4 
  5    "If you don't know the ladders, don't play go."
  6 
  7    THVV 7/74 */
  8 
  9 dcl  xp ptr,
 10      gn fixed bin,
 11      mycolor fixed bin;
 12 
 13 %include godata;
 14 
 15 dcl (i1, j1) fixed bin,
 16     (i2, j2) fixed bin,
 17     (v1, v2) fixed bin,
 18     (tv1, tv2) fixed bin,
 19      n fixed bin,
 20      ec fixed bin (35),
 21     (x, y) fixed bin,
 22     (pi, pj) fixed bin,
 23      f fixed bin,
 24      g fixed bin,
 25      xd (-1:1, 0:2) fixed bin,
 26      color fixed bin;
 27 
 28 dcl  rp ptr int static init (null);
 29 
 30 dcl (null, max, min) builtin;
 31 
 32 dcl  hcs_$make_seg entry (char (*), char (*), char (*), fixed bin (5), ptr, fixed bin (35));
 33 dcl  ioa_ entry options (variable);
 34 dcl  loud bit (1) int static init ("0"b);
 35 
 36 dcl  cap entry (ptr);
 37 
 38 dcl  F fixed bin int static options (constant) init (4);
 39 dcl  ate_wt fixed bin int static options (constant) init (10);
 40 dcl  cap_wt fixed bin int static options (constant) init (15);
 41 dcl  def_wt fixed bin int static options (constant) init (5);
 42 dcl  maxdepth fixed bin init (0);
 43 dcl  FAIL fixed bin int static options (constant) init (-1);
 44 dcl  WIN fixed bin int static options (constant) init (1);
 45 
 46 /* ======================================== */
 47 
 48           g = gn;
 49           if rp = null then
 50                call hcs_$make_seg ("", "", "", 1011b, rp, ec);
 51           godatap = rp;
 52           rp -> godata = xp -> godata;
 53           xd = godata.dead;
 54 
 55           i1 = godata.dami1 (g);
 56           j1 = godata.damj1 (g);
 57           i2 = godata.dami2 (g);
 58           j2 = godata.damj2 (g);
 59 
 60           n = godata.np (g);
 61           color = godata.gp_color (g);
 62           if color = mycolor then do;
 63                v1 = defend (g, i1, j1);
 64                v2 = defend (g, i2, j2);
 65                if v1 = 0 then v1 = n * def_wt;
 66                if v2 = 0 then v2 = n * def_wt;
 67           end;
 68           else do;
 69                x = godata.gp_loc (g, 1);
 70                y = godata.gp_loc (g, 2);
 71                v1 = attack (x, y, i1, j1, 1);
 72                v2 = attack (x, y, i2, j2, 1);
 73                if v1 > 0 then v1 = v1 + n * ate_wt;
 74                if v2 > 0 then v2 = v2 + n * ate_wt;
 75           end;
 76 
 77           xp -> godata.vc (i1, j1) = xp -> godata.vc (i1, j1) + v1;
 78           xp -> godata.vc (i2, j2) = xp -> godata.vc (i2, j2) + v2;
 79 
 80           if loud then
 81                call ioa_ ("ladder: ^d ^a; ^a play (^d, ^d)= ^d;  (^d, ^d)= ^d (^d deep)",
 82                n, COLOR (color), COLOR (mycolor),
 83                i1, j1, v1, i2, j2, v2, maxdepth);
 84           return;
 85 
 86 /* -------------------------------------------------------- */
 87 
 88 /* called to see what to do about a group with 1 dame.
 89    we defend the group and see if this
 90    a. kills it
 91    b. saves it
 92    c. leads to a ladder */
 93 
 94 avoid:    entry (xp, gn, mycolor);
 95 
 96           if rp = null then
 97                call hcs_$make_seg ("", "", "", 1011b, rp, ec);
 98           godatap = rp;
 99           rp -> godata = xp -> godata;
100           xd = godata.dead;
101 
102           pi = godata.dami1 (gn);
103           pj = godata.damj1 (gn);
104 
105           v1 = defend (gn, pi, pj);
106           if v1 < 0 then v1 = v1 - cap_wt;                  /* Hype it down for these. */
107           xp -> godata.vi (pi, pj) = xp -> godata.vi (pi, pj) + v1;
108           if v1 < 0 then
109                if loud then call ioa_ ("ladder: avoid (^d,^d) ^d (^d deep)",
110                     pi, pj, v1, maxdepth);
111           return;
112 
113 
114 /* ------------------------------------------------------- */
115 
116 /* Internal procedure to see what happens if we attack group (x, y) at (x1, y1) */
117 
118 attack:   proc (x, y, x1, y1, depth) returns (fixed bin) recursive;
119 
120 dcl (x, y, x1, y1) fixed bin;
121 dcl  depth fixed bin;
122 dcl (a1, b1, a2, b2) fixed bin;
123 dcl  val fixed bin;
124 dcl  C fixed bin;
125 dcl (v1, v2) fixed bin;
126 dcl  delta fixed bin;
127 dcl (x2, y2) fixed bin;
128 dcl (g1, g2) fixed bin;
129 dcl  xxd (-1:1, 0:2) fixed bin;
130 
131 
132                if depth > maxdepth then maxdepth = depth;
133 
134                xxd = godata.dead;
135                C = godata.board (x, y);                     /* Get color of group. */
136                godata.board (x1, y1) = -C;                  /* attack here */
137 
138                call cap (godatap);
139 
140                g1 = godata.grpno (x, y);                    /* Defended group */
141                g2 = godata.grpno (x1, y1);                  /* Attacker */
142 
143                delta = F * (godata.dead (C, 0) - xd (C, 0)) + (godata.dead (C, 1) - xd (C, 1))
144                     -F * (godata.dead (-C, 0) - xd (-C, 0)) - (godata.dead (-C, 1) - xd (-C, 1));
145 
146                if godata.dame (0, g1) = 0 then              /* Attacker kills target group. */
147                     val = max (WIN, delta);                 /* Return positive answer. */
148                else if godata.dead (-C, 0) > xxd (-C, 0) then /* Attacking kills me. ugh */
149                     val = min (FAIL, delta);
150                else if godata.dead (-C, 1) > xxd (-C, 1) then /* Attacking increases my prisoners. ug */
151                     if godata.dame (0, g1) = 1 then val = WIN; /* Case of eye-filling */
152                     else val = min (FAIL, delta);           /* .. no, bad idea. */
153                else if godata.dame (0, g1) = 1 then do;     /* Defender in atari and his turn. can escape? */
154                     x2 = godata.dami1 (g1);                 /* .. let's try. */
155                     y2 = godata.damj1 (g1);                 /* (cap kindly left us a note of where to play) */
156                     godata.board (x2, y2) = C;              /* Defend */
157                     call cap (godatap);                     /* Recalculate groups. */
158                     g1 = grpno (x, y);                      /* .. grpno may have changed. */
159                     g2 = grpno (x1, y1);
160                     delta = F * (godata.dead (C, 0) - xd (C, 0)) + (godata.dead (C, 1) - xd (C, 1))
161                          -F * (godata.dead (-C, 0) - xd (-C, 0)) - (godata.dead (-C, 1) - xd (-C, 1));
162 
163                     if godata.dame (0, g2) = 0 then         /* Defense killed atacker */
164                          val = min (FAIL, delta);
165                     else if godata.dame (0, g1) = 0 then    /* Defense killed self */
166                          val = max (WIN, delta);
167                     else if godata.dame (0, g1) = 1 then    /* Defense left self in atari & it's the wolf's turn */
168                          val = max (WIN, delta);
169                     else if godata.dame (0, g1) = 2 then do; /* True ladder.. attack group recursive and see. */
170                          a1 = godata.dami1 (g1);            /* Note where to play. */
171                          b1 = godata.damj1 (g1);            /* .. must keep these in temps */
172                          a2 = godata.dami2 (g1);            /* .. since recursion tends to affect group nos */
173                          b2 = godata.damj2 (g1);
174                          v1 = attack (x, y, a1, b1, depth+1); /* Crunch */
175                          v2 = attack (x, y, a2, b2, depth+1);
176                          val = max (v1, v2);                /* If either play kills, this situation is a winner */
177                     end;
178                     else val = min (FAIL, delta);           /* Defender escaped.. >2 dame */
179                     godata.board (x2, y2) = 0;              /* Undo the test move. */
180                end;
181                else val = min (FAIL, delta);                /* Even after attack enemy is not forced. */
182                godata.board (x1, y1) = 0;
183                return (val);
184 
185           end attack;
186 
187 /* -------------------------------------------------------- */
188 
189 /* Internal procedure to see if group can be defended. */
190 
191 defend:   proc (gg, xx, yy) returns (fixed bin);
192 
193 dcl (gg, xx, yy) fixed bin;
194 dcl (v1, v2) fixed bin;
195 dcl  val fixed bin;
196 dcl (n, color) fixed bin;
197 dcl (g, a1, a2, b1, b2, x, y) fixed bin;
198 
199                val = 0;                                     /* Returning 0 means group is saveable. */
200                n = godata.np (gg);
201                color = godata.gp_color (gg);
202 
203                godata.board (xx, yy) = color;
204 
205                call cap (godatap);
206                g = godata.grpno (xx, yy);                   /* Must recalculate grp number. */
207                if godata.dead (color, 0) > xd (color, 0) then /* Defending the group killed defending stones */
208                     val = -n * cap_wt;
209                else if godata.dead (-color, 0) > xd (-color, 0) then; /* Defending kills enemy.. assume ok */
210                else if godata.dame (0, g) = 2 then do;      /* Have ladder. Check it out. */
211                     x = godata.gp_loc (g, 1);
212                     y = godata.gp_loc (g, 2);
213                     a1 = godata.dami1 (g);
214                     b1 = godata.damj1 (g);
215                     a2 = godata.dami2 (g);
216                     b2 = godata.damj2 (g);
217                     v1 = attack (x, y, a1, b1, 1);
218                     v2 = attack (x, y, a2, b2, 1);
219 
220                     if max (v1, v2) > 0 then val = -n * cap_wt;
221                     else val = 0;
222                end;
223                else if godata.dame (0, g) < 2 then
224                     val = -n * def_wt;                      /* Defending left grp in atari or worse so DONT */
225                else val = 0;                                /* Group escapes. */
226                godata.board (xx, yy) = 0;
227                return (val);
228 
229           end defend;
230 
231 quietladder: entry;
232           loud = "0"b;
233           return;
234 
235 
236 loudladder: entry;
237 
238           loud = "1"b;
239 
240      end ladder;