+/*----- Optimizations -----------------------------------------------------*/
+
+/* --- @elite-galaxylist SEED@ --- *
+ *
+ * Returns a SEED/X/Y list for the worlds in galaxy SEED.
+ */
+
+static int cmd_galaxylist(ClientData cd, Tcl_Interp *ti,
+ int objc, Tcl_Obj *const *objv)
+{
+ world *w, ww;
+ worldinfo wi;
+ int i;
+ Tcl_Obj *o;
+
+ if (objc != 2)
+ return (err(ti, "usage: elite-galaxylist SEED"));
+ if ((w = world_get(ti, objv[1])) == 0)
+ return (TCL_ERROR);
+ ww = *w;
+ o = Tcl_NewListObj(0, 0);
+ for (i = 0; i < 256; i++) {
+ getworldinfo(&wi, &ww);
+ Tcl_ListObjAppendElement(ti, o, world_new(&ww));
+ Tcl_ListObjAppendElement(ti, o, Tcl_NewIntObj(wi.x * 4));
+ Tcl_ListObjAppendElement(ti, o, Tcl_NewIntObj(wi.y * 2));
+ waggle(&ww, &ww); waggle(&ww, &ww); waggle(&ww, &ww); waggle(&ww, &ww);
+ }
+ Tcl_SetObjResult(ti, o);
+ return (TCL_OK);
+}
+
+/* --- @elite-distance X Y XX YY@ --- *
+ *
+ * Returns the distance between two points.
+ */
+
+static int cmd_distance(ClientData cd, Tcl_Interp *ti,
+ int objc, Tcl_Obj *const *objv)
+{
+ long x, y, xx, yy;
+ long d;
+
+ if (objc != 5)
+ return (err(ti, "usage: elite-distance X Y XX YY"));
+ if (Tcl_GetLongFromObj(ti, objv[1], &x) != TCL_OK ||
+ Tcl_GetLongFromObj(ti, objv[2], &y) != TCL_OK ||
+ Tcl_GetLongFromObj(ti, objv[3], &xx) != TCL_OK ||
+ Tcl_GetLongFromObj(ti, objv[4], &yy) != TCL_OK)
+ return (TCL_ERROR);
+ xx = xx >= x ? xx - x : x - xx; xx >>= 2; xx *= xx;
+ yy = yy >= y ? yy - y : y - yy; yy >>= 2; yy *= yy;
+ d = sqrt(xx + yy); d <<= 2;
+ Tcl_SetObjResult(ti, Tcl_NewLongObj(d));
+ return (TCL_OK);
+}
+
+/* --- @elite-adjacency ADJ LIST [DIST]@ --- *
+ *
+ * Construct an adjacency table from a world list.
+ */
+
+static int cmd_adjacency(ClientData cd, Tcl_Interp *ti,
+ int objc, Tcl_Obj *const *objv)
+{
+ int oc;
+ Tcl_Obj **ov;
+ size_t i, j;
+ long x, y, xx, yy, d;
+ Tcl_Obj *a;
+ char *s, *ss;
+ Tcl_HashTable done;
+ long dd = 70;
+ int rc = TCL_ERROR;
+ int dummy;
+ Tcl_Obj *o;
+
+ if (objc < 3 || objc > 4)
+ return (err(ti, "usage: elite-adjacency ADJ LIST [DIST]"));
+ a = objv[1];
+ if (Tcl_ListObjGetElements(ti, objv[2], &oc, &ov) != TCL_OK)
+ return (TCL_ERROR);
+ if (oc % 3 != 0)
+ return (err(ti, "world array not a multiple of three in size"));
+ if (objc >= 4 && Tcl_GetLongFromObj(ti, objv[3], &dd) != TCL_OK)
+ return (TCL_ERROR);
+
+ Tcl_InitHashTable(&done, TCL_ONE_WORD_KEYS);
+ Tcl_UnsetVar(ti, Tcl_GetString(a), 0);
+ o = Tcl_NewObj();
+ Tcl_IncrRefCount(o);
+ for (i = 0; i < oc; i += 3) {
+ s = Tcl_GetString(ov[i]);
+ if (Tcl_ObjSetVar2(ti, a, ov[i], o, TCL_LEAVE_ERR_MSG) == 0)
+ goto done;
+ }
+ for (i = 0; i < oc; i += 3) {
+ s = Tcl_GetString(ov[i]);
+ Tcl_CreateHashEntry(&done, s, &dummy);
+ if (Tcl_GetLongFromObj(ti, ov[i + 1], &x) != TCL_OK ||
+ Tcl_GetLongFromObj(ti, ov[i + 2], &y) != TCL_OK)
+ goto done;
+ for (j = 0; j < oc; j += 3) {
+ ss = Tcl_GetString(ov[j]);
+ if (Tcl_FindHashEntry(&done, ss))
+ continue;
+ if (Tcl_GetLongFromObj(ti, ov[j + 1], &xx) != TCL_OK ||
+ Tcl_GetLongFromObj(ti, ov[j + 2], &yy) != TCL_OK)
+ goto done;
+ xx = xx >= x ? xx - x : x - xx; xx >>= 2; xx *= xx;
+ yy = yy >= y ? yy - y : y - yy; yy >>= 2; yy *= yy;
+ d = sqrt(xx + yy); d <<= 2;
+ if (d <= dd) {
+ if (Tcl_ObjSetVar2(ti, a, ov[i], ov[j],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0 ||
+ Tcl_ObjSetVar2(ti, a, ov[i], ov[j + 1],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0 ||
+ Tcl_ObjSetVar2(ti, a, ov[i], ov[j + 2],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0 ||
+ Tcl_ObjSetVar2(ti, a, ov[j], ov[i],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0 ||
+ Tcl_ObjSetVar2(ti, a, ov[j], ov[i + 1],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0 ||
+ Tcl_ObjSetVar2(ti, a, ov[j], ov[i + 2],
+ (TCL_APPEND_VALUE |
+ TCL_LIST_ELEMENT |
+ TCL_LEAVE_ERR_MSG)) == 0)
+ goto done;
+ }
+ }
+ }
+ rc = TCL_OK;
+
+done:
+ Tcl_DeleteHashTable(&done);
+ return (rc);
+}
+