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                                                             /* this here is my group & has two dame */
 64                                                             /* the question is can oppon kill it via ladder? */
 65                                                             /* if he can then an adequate defense must be found */
 66                x = godata.gp_loc (g, 1);
 67                y = godata.gp_loc (g, 2);
 68                v1 = attack (x, y, i1, j1, 1);               /* >0 if he kills */
 69                v2 = attack (x, y, i2, j2, 1);               /* >0 if he kills */
 70                if v1 >0 | v2 > 0 then do;                   /* oppon can kill via ladder */
 71                                                             /* see if either play by me will save */
 72                     v1 = defend (godata.grpno (x, y), i1, j1); /* 0 => he cannot kill */
 73                     v2 = defend (godata.grpno (x, y), i2, j2); /* 0 => he cannot kill */
 74                     if v1 = 0 then v1 = n * cap_wt;         /* prevent sure capture */
 75                     if v2 = 0 then v2 = n * cap_wt;         /* prevent sure capture */
 76                end;
 77                else do;                                     /* threat is not fatal */
 78                     v1 = defend (godata.grpno (x, y), i1, j1); /* see if safe to add stone */
 79                     v2 = defend (godata.grpno (x, y), i2, j2); /* = 0 implies safe */
 80                     if v1 = 0 then v1 = n * def_wt;         /* leak out is plausible */
 81                     if v2 = 0 then v2 = n * def_wt;         /* leak out is plausible */
 82                                                             /* crummy attempts will get neg values from defend */
 83                end;
 84           end;
 85           else do;
 86                x = godata.gp_loc (g, 1);
 87                y = godata.gp_loc (g, 2);
 88                v1 = attack (x, y, i1, j1, 1);
 89                v2 = attack (x, y, i2, j2, 1);
 90                if v1 > 0 then v1 = v1 + n * ate_wt;
 91                if v2 > 0 then v2 = v2 + n * ate_wt;
 92           end;
 93 
 94           xp -> godata.vc (i1, j1) = xp -> godata.vc (i1, j1) + v1;
 95           xp -> godata.vc (i2, j2) = xp -> godata.vc (i2, j2) + v2;
 96 
 97           if loud then
 98                call ioa_ ("ladder: ^d ^a; ^a play (^d, ^d)= ^d;  (^d, ^d)= ^d (^d deep)",
 99                n, COLOR (color), COLOR (mycolor),
100                i1, j1, v1, i2, j2, v2, maxdepth);
101           return;
102 
103 /* -------------------------------------------------------- */
104 
105 /* called to see what to do about a group with 1 dame.
106    we defend the group and see if this
107    a. kills it
108    b. saves it
109    c. leads to a ladder */
110 
111 avoid:    entry (xp, gn, mycolor);
112 
113           if rp = null then
114                call hcs_$make_seg ("", "", "", 1011b, rp, ec);
115           godatap = rp;
116           rp -> godata = xp -> godata;
117           xd = godata.dead;
118 
119           pi = godata.dami1 (gn);
120           pj = godata.damj1 (gn);
121 
122           v1 = defend (gn, pi, pj);
123           if v1 < 0 then v1 = v1 - cap_wt;                  /* Hype it down for these */
124           xp -> godata.vi (pi, pj) = xp -> godata.vi (pi, pj) + v1;
125           if v1 < 0 then
126                if loud then call ioa_ ("ladder: avoid (^d,^d) ^d (^d deep)",
127                     pi, pj, v1, maxdepth);
128           return;
129 
130 
131 /* ------------------------------------------------------- */
132 
133 /* Internal procedure to see what happens if we attack group (x, y) at (x1, y1) */
134 
135 attack:   proc (x, y, x1, y1, depth) returns (fixed bin) recursive;
136 
137 dcl (x, y, x1, y1) fixed bin;
138 dcl  depth fixed bin;
139 dcl (a1, b1, a2, b2) fixed bin;
140 dcl  val fixed bin;
141 dcl  C fixed bin;
142 dcl (v1, v2) fixed bin;
143 dcl  delta fixed bin;
144 dcl (x2, y2) fixed bin;
145 dcl (g1, g2) fixed bin;
146 dcl  xxd (-1:1, 0:2) fixed bin;
147 
148 
149                if depth > maxdepth then maxdepth = depth;
150 
151                xxd = godata.dead;
152                C = godata.board (x, y);                     /* Get color of group. */
153                godata.board (x1, y1) = -C;                  /* attack here */
154 
155                call cap (godatap);
156 
157                g1 = godata.grpno (x, y);                    /* Defended group */
158                g2 = godata.grpno (x1, y1);                  /* Attacker */
159 
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, g1) = 0 then              /* Attacker kills target group. */
164                     val = max (WIN, delta);                 /* Return positive answer. */
165                else if godata.dead (-C, 0) > xxd (-C, 0) then /* Attacking kills me. ugh */
166                     val = min (FAIL, delta);
167                else if godata.dead (-C, 1) > xxd (-C, 1) then /* Attacking increases my prisoners. ug */
168                     if godata.dame (0, g1) = 1 then val = WIN; /* Case of eye-filling */
169                     else val = min (FAIL, delta);           /* .. no, bad idea. */
170                else if godata.dame (0, g1) = 1 then do;     /* Defender in atari and his turn. can escape? */
171                     x2 = godata.dami1 (g1);                 /* .. let's try. */
172                     y2 = godata.damj1 (g1);                 /* (cap kindly left us a note of where to play) */
173                     godata.board (x2, y2) = C;              /* Defend */
174                     call cap (godatap);                     /* Recalculate groups. */
175                     g1 = grpno (x, y);                      /* .. grpno may have changed. */
176                     g2 = grpno (x1, y1);
177                     delta = F * (godata.dead (C, 0) - xd (C, 0)) + (godata.dead (C, 1) - xd (C, 1))
178                          -F * (godata.dead (-C, 0) - xd (-C, 0)) - (godata.dead (-C, 1) - xd (-C, 1));
179 
180                     if godata.dame (0, g2) = 0 then         /* Defense killed atacker */
181                          val = min (FAIL, delta);
182                     else if godata.dame (0, g1) = 0 then    /* Defense killed self */
183                          val = max (WIN, delta);
184                     else if godata.dame (0, g1) = 1 then    /* Defense left self in atari & it's the wolf's turn */
185                          val = max (WIN, delta);
186                     else if godata.dame (0, g1) = 2 then do; /* True ladder.. attack group recursive and see. */
187                          a1 = godata.dami1 (g1);            /* Note where to play. */
188                          b1 = godata.damj1 (g1);            /* .. must keep these in temps */
189                          a2 = godata.dami2 (g1);            /* .. since recursion tends to affect group nos */
190                          b2 = godata.damj2 (g1);
191                          v1 = attack (x, y, a1, b1, depth+1); /* Crunch */
192                          v2 = attack (x, y, a2, b2, depth+1);
193                          val = max (v1, v2);                /* If either play kills, this situation is a winner */
194                     end;
195                     else val = min (FAIL, delta);           /* Defender escaped.. >2 dame */
196                     godata.board (x2, y2) = 0;              /* Undo the test move. */
197                end;
198                else val = min (FAIL, delta);                /* Even after attack enemy is not forced. */
199                godata.dead = xxd;                           /* rem: i think you want to restore this */
200                godata.board (x1, y1) = 0;
201                return (val);
202 
203           end attack;
204 
205 /* -------------------------------------------------------- */
206 
207 /* Internal procedure to see if group can be defended. */
208 
209 defend:   proc (gg, xx, yy) returns (fixed bin);
210 
211 dcl (gg, xx, yy) fixed bin;
212 dcl (v1, v2) fixed bin;
213 dcl  val fixed bin;
214 dcl (n, color) fixed bin;
215 dcl (g, a1, a2, b1, b2, x, y) fixed bin;
216 
217                val = 0;                                     /* Returning 0 means group is saveable. */
218                n = godata.np (gg);
219                color = godata.gp_color (gg);
220 
221                godata.board (xx, yy) = color;
222 
223                call cap (godatap);
224                g = godata.grpno (xx, yy);                   /* Must recalculate grp number. */
225                if godata.dead (color, 0) > xd (color, 0) then /* Defending the group killed defending stones */
226                     val = -n * cap_wt;
227                else if godata.dead (-color, 0) > xd (-color, 0) then; /* Defending kills enemy.. assume ok */
228                else if godata.dame (0, g) = 2 then do;      /* Have ladder. Check it out. */
229                     x = godata.gp_loc (g, 1);
230                     y = godata.gp_loc (g, 2);
231                     a1 = godata.dami1 (g);
232                     b1 = godata.damj1 (g);
233                     a2 = godata.dami2 (g);
234                     b2 = godata.damj2 (g);
235                     v1 = attack (x, y, a1, b1, 1);
236                     v2 = attack (x, y, a2, b2, 1);
237 
238                     if max (v1, v2) > 0 then val = -n * cap_wt;
239                     else val = 0;
240                end;
241                else if godata.dame (0, g) < 2 then
242                     val = -n * def_wt;                      /* Defending left grp in atari or worse so DONT */
243                else val = 0;                                /* Group escapes. */
244                godata.board (xx, yy) = 0;
245                return (val);
246 
247           end defend;
248 
249 quietladder: entry;
250           loud = "0"b;
251           return;
252 
253 
254 loudladder: entry;
255 
256           loud = "1"b;
257 
258      end ladder;