Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Playing for position (mobility)

70 views
Skip to first unread message

S.Read

unread,
Sep 29, 1995, 3:00:00 AM9/29/95
to
I have heard it said, "computers can't steer the game into the sort
of position that they are happy with." ie open games, where tactics
are more likely to decide. Closed games make players rely more on long
range strategy which needs moer chess knowledge.

SO: how to remedy this? How to get computers to steer the game into
the open type of position where tactics are more relevant?

Mobility: computers score MOB = (My mobility) - (opponent's mobility)
how about another score OP = openness of position
OP = (My mobility) + (Opponent's mobility) ?

So then if we want the computer to steer the game towards a more open
position, we put not just MOB but MOB + OP in the evaluation function.

BUT This makes the evaluation function ASYMMETRICAL.... it makes the
computer's evaluation function (My mobility) with no account of
(Opponent's mobility). This might actually be good. If the opponent has low
mobility, fine, he's tied up. Alternatively, if the opponent has high
mobility, fine, it's the open-type position we like.

REFINEMENT we may choose two coefficients C1 and C2 so the final evaluation
function contains C1 x MOB + C2 x OP. Thus the evaluation function can be
more or less asymmetrical as we choose.

Simon "Lurk before you leap!"
s.r...@cranfield.ac.uk


Joe Stella

unread,
Sep 29, 1995, 3:00:00 AM9/29/95
to

"S.Read" <me944p> writes:

>[...]


>Mobility: computers score MOB = (My mobility) - (opponent's mobility)
>how about another score OP = openness of position
> OP = (My mobility) + (Opponent's mobility) ?

>[...]


This sort of thing is really nothing new, and it (or some variant of it)
is employed by all chess programs nowadays (even mine :-) ).

It does improve things in general, but it doesn't solve all problems because
there are times when it causes the program to make a pawn break to "open
up" the position even when this break is not really sound in terms of
other (more subjective) "positional" considerations. I mean the type of
thing that a master instinctively knows about, but is hard to code (or even
to express in words).

Joe S.


Joe Stella

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to

kerr...@alpha.pr1.k12.co.us (Thomas Kerrigan) writes:

>There are other ways to get to open positions. I don't do mobility
>because it would hit my performance hard, but I do try for open positions
>by assigning a tiny bonus for open files and penalizing pawn rams...


Ooops, I guess whipped out my "all chess programs" phrase a bit too quickly...

There is a way to include "mobility" (of sorts) without any performance
penality at all. Here's how I do it:

I keep two variables, white_mobility and black_mobility. Whenever the
move generator is called, I save the number of moves that were generated
in the appropriate variable (white_mobility if generating moves for white,
etc.).

At evaluation time, I just use these variables. The values are "old", in
the sense that at ply n, we know what the mobility was at ply n-1 for
the opponent, and what it was at ply n-2 for the side to move. It is
based upon the assumption that the mobility does not change quickly, that is,
one move by each side does not change the mobility much. Not always true,
I know, but I think it is better than not having mobility at all.

I discovered this completely on my own, only to find out later that it is
already in the books but I just didn't know it... :-(

Joe S.


Thomas Kerrigan

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to
Yeah, I also "discovered" that idea myself. :)

The problem I have with it is that I have a gen_caps() function which I
call in quiescence. If I counted the moves it generates, I would have
nothing of significance. If I counted the moves for my full width search
and used them in quiescence, that wouldn't be useful either. Let's say I
have a really mobile bishop in full-width that's traded off in every
resulting position. Those positions' scores would be artifically inflated.

I guess I am slamming your idea, but I just think its another one of
these things that should work but don't. God knows I've tried some weird
things to get mobility. :)

Cheers,
Tom

------------------------------------------------------------------------------
"You can bring any calculator you like to the midterm, as long as it
doesn't dim the lights when you turn it on." -Hepler, Systems Design 182

Thomas C. Kerrigan
'kerr...@alpha.pr1.k12.co.us'

Joe Stella

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to

kerr...@alpha.pr1.k12.co.us (Thomas Kerrigan) writes:

>The problem I have with it is that I have a gen_caps() function which I
>call in quiescence. If I counted the moves it generates, I would have
>nothing of significance.

My gen_caps() function is essentially the same as the gen_moves() function,
except that non-captures just don't get added to the final list. I can
still count them, though, so this works out a little better.

I hope more programmers will post other good ideas here about evaluating
mobility. This could get interesting...

Joe S.


Robert Hyatt

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to
In article <44kaje$a...@alpha.pr1.k12.co.us>,
Thomas Kerrigan <kerr...@alpha.pr1.k12.co.us> wrote:
--->Yeah, I also "discovered" that idea myself. :)
--->
--->The problem I have with it is that I have a gen_caps() function which I
--->call in quiescence. If I counted the moves it generates, I would have
--->nothing of significance. If I counted the moves for my full width search
--->and used them in quiescence, that wouldn't be useful either. Let's say I
--->have a really mobile bishop in full-width that's traded off in every
--->resulting position. Those positions' scores would be artifically inflated.
--->
--->I guess I am slamming your idea, but I just think its another one of
--->these things that should work but don't. God knows I've tried some weird
--->things to get mobility. :)
--->
--->Cheers,
--->Tom

Of course, you *could* use rotated bitboards, so that mobility requires
one array reference for each of the two diagonals (or rank/files). :)


--
Robert Hyatt Computer and Information Sciences
hy...@cis.uab.edu University of Alabama at Birmingham
(205) 934-2213 115A Campbell Hall, UAB Station
(205) 934-5473 FAX Birmingham, AL 35294-1170

Robert Hyatt

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to
In article <44kof5$r...@alpha.pr1.k12.co.us>,
Thomas Kerrigan <kerr...@alpha.pr1.k12.co.us> wrote:
--->Yes, my gen_caps() is very similar to my gen() but I've made several
--->optimizations so it only generates captures, promotes, and en passants.
--->That way I don't have to waste time when I'm putting the moves on the
--->move stack.
--->
--->Anyway, one of the mobility ideas I tried recently was to generate new
--->piece square tables before I started a search, and these tables would
--->have a mobility bonus... 0.01 pawns for every attackable square, sliding
--->through pieces but not pawns or kings. The theory here is that pawns and
--->kings don't move around a lot. Anyway, the results were pretty bad. My
--->program made weird moves (even weirder than usual, I mean) and Hyatt told
--->me the idea was quite frankly very stupid, so that was the end of that...
--->

I don't think I said "very stupid" just not very worthwhile. The problem
is that mobility at the root doesn't have a lot to do with what is going on
at the terminal positions. I've just about eliminated piece/square tables
in crafty, only having them for centralization scoring, which is a static
thing since the center of the board doesn't move. :) However, to compute
mobility for each piece on every square, based on the configuration of things
at the root, is not so hot. Imagine taking the king position and computing
the distance of each square from this king an dputting that in the piece/
square table. If you do a 12 ply search, the king could be 6 squares away
from where you are trying to attack.

In any case, I tried the "quick and dirty" movgen mobility, but it overlooks
one important detail: a bishop with 1 square of mobility and a rook with 10,
is much worse than a bishop with 5 and a rook with 5, because the bishop is in
a real bind. If you do it piece by piece, you can build a vector of mobility
scores that is negative for 0, 1 or even 2, and gets better after that. If
you do it the "conglomerate" way, that detail is hidden. I played with this
some in Cray Blitz, as even when I generated captures, I had to step through
empty squares (x88 approach) and could therefore count 'em easily. I had
mixed results, however. In crafty, it would be impossible, as with bitboards,
I don't "step through" empty squares, but simply enumerate only capture moves,
which would produce the problem you explained before, that mobility would either
(a) look bad since only captures were generated or (b) be "stale" since it could be 1 or 2 (or 10-20) plies removed from the last full-width move generation.

However, as I mentioned, with crafty it's a trivial problem anyway. Of course,
the "thought" that went into developing the rotated bitboards and the mechanism
for looking up the attack bitmaps and mobility values wasn't easy. Looks easy
now, but drove me to the brink when I was working on it. Make_Move() and so
forth are now *easy* to understand. Initializing these various tables is insane.

Bob

Thomas Kerrigan

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to
There are other ways to get to open positions. I don't do mobility
because it would hit my performance hard, but I do try for open positions
by assigning a tiny bonus for open files and penalizing pawn rams...

Cheers,

Robert Hyatt

unread,
Sep 30, 1995, 3:00:00 AM9/30/95
to
In article <joes.516...@ultranet.com>,
Joe Stella <jo...@ultranet.com> wrote:
--->
--->

---> kerr...@alpha.pr1.k12.co.us (Thomas Kerrigan) writes:
--->
--->>The problem I have with it is that I have a gen_caps() function which I
--->>call in quiescence. If I counted the moves it generates, I would have
--->>nothing of significance.
--->
--->My gen_caps() function is essentially the same as the gen_moves() function,
--->except that non-captures just don't get added to the final list. I can
--->still count them, though, so this works out a little better.
--->
--->I hope more programmers will post other good ideas here about evaluating
--->mobility. This could get interesting...
--->
---> Joe S.
--->

One of the neat things about the rotated bitboards: I've explained how
you use them to grab a bit-vector of attacks from a given square, on a
particular rank, file or diagonal, based on the contents of the occupied-
squares of that "thing"... however, I also have a table of ints, index
in exactly the same way, but which returns the mobility along that
rank, file, or diagonal. In essence, for every piece, the mobility
function is two table lookups, and an add. Hard to get much faster than
that.

I have probably only scratched the surface of this. How about a "count"
of the number of squares around the king this bishop or whatever attacks
along this diagonal? Again a table lookup, although it would be a table
of 64x64x256 rather than the usual 64x256. Or maybe 4 tables rather than
64, and count attacks into a particular "quadrant" of the board, to save
some memory (64x64 is not big, but 64x64x256 is a million if I added
exponents right.

no telling what we might come up with after everyone gets "in sync" with
this way of thinking.

Thomas Kerrigan

unread,
Oct 1, 1995, 3:00:00 AM10/1/95
to
Yes, my gen_caps() is very similar to my gen() but I've made several
optimizations so it only generates captures, promotes, and en passants.
That way I don't have to waste time when I'm putting the moves on the
move stack.

Anyway, one of the mobility ideas I tried recently was to generate new

piece square tables before I started a search, and these tables would

have a mobility bonus... 0.01 pawns for every attackable square, sliding

through pieces but not pawns or kings. The theory here is that pawns and

kings don't move around a lot. Anyway, the results were pretty bad. My

program made weird moves (even weirder than usual, I mean) and Hyatt told

me the idea was quite frankly very stupid, so that was the end of that...

Cheers,

Ian Kennedy

unread,
Oct 1, 1995, 3:00:00 AM10/1/95
to
>I keep two variables, white_mobility and black_mobility. Whenever the
>move generator is called, I save the number of moves that were generated
>in the appropriate variable (white_mobility if generating moves for
>white,etc.).

I use the same idea in my program, with just an additional factor which I
multiply in depending on which phase of the game we're in - mobility is
treated as most important in the mid-game and relatively discouraged in
the opening to avoid premature development of the major pieces and
delaying castling, which can temporarily reduce the mobility of the
king-rook pair.

The main trouble is if your legal move generator only gives pseudo-legal
moves which haven't been tested for self-check yet. What do you do if the
side to move is in check? This can be a big distorting factor - do you
want to reward the other side for this (temporary) drastic reduction in
opponent mobility or ignore it? My current method is to bottle out of the
decision. If either side is in check I simply throw away the mobility
factor.

Ian Kennedy

Joe Stella

unread,
Oct 1, 1995, 3:00:00 AM10/1/95
to

hy...@willis.cis.uab.edu (Robert Hyatt) writes:

>In any case, I tried the "quick and dirty" movgen mobility, but it overlooks
>one important detail: a bishop with 1 square of mobility and a rook with 10,
>is much worse than a bishop with 5 and a rook with 5, because the bishop is in
>a real bind. If you do it piece by piece, you can build a vector of mobility
>scores that is negative for 0, 1 or even 2, and gets better after that. If
>you do it the "conglomerate" way, that detail is hidden.


Thanks for the info, Bob -- as usual, you have pointed out a shortcoming
in my program, and now it is "back to work again" to try and fix it...

Joe S.


Joe Stella

unread,
Oct 1, 1995, 3:00:00 AM10/1/95
to

iken...@cix.compulink.co.uk ("Ian Kennedy") writes:

>The main trouble is if your legal move generator only gives pseudo-legal
>moves which haven't been tested for self-check yet. What do you do if the
>side to move is in check? This can be a big distorting factor - do you
>want to reward the other side for this (temporary) drastic reduction in
>opponent mobility or ignore it?


I don't quite understand. If the move generator generates moves that
have not been tested for self-check yet, then where is the "drastic reduction"
in mobility? My movegen function gives me the number of pseudo-legal
moves generated, and I use this in the "mobility" estimate. Most of these
moves are not really legal if the side to move is in check, but who cares?
The object is to get a measure of the mobility inherent in the position, and
it seems to me that the number of pseudo-legal moves is exactly what we
want for this.

Joe S.


Tom_King

unread,
Oct 2, 1995, 3:00:00 AM10/2/95
to
All,

My program doesn't use the number of pseudo-legal moves generated
during the search for approximating mobility.

This is because sometimes I don't call the generate_moves function at
a given depth because I don't always generate all moves at
once. Also, at some depths where I'm doing a null move, I won't
be calling generate_moves at all. How do others get round this
problem?

For my program, all concepts of mobility are handled via the
piece square values. Obviously, this isn't ideal.

Tom King

***********************************************************************
* Tom King (Tom_...@cegelecproj.co.uk) *
* ...all opinions expressed are my own and not those of my employer...*
***********************************************************************

Peter Mysliwietz

unread,
Oct 2, 1995, 3:00:00 AM10/2/95
to
In article <joes.516...@ultranet.com>, jo...@ultranet.com (Joe Stella) writes:
>
>
>I hope more programmers will post other good ideas here about evaluating
>mobility. This could get interesting...
>
> Joe S.
>

In zugzwang we keep a list of squares that can be reached by either side.
This list is sorted into a part of occupied and a part with empty squares.
These list a incrementally updated for move-generating purpuses.
However, since we have these lists (so to say for free) these are used to
approximate mobility.
So we do NOT have the number of possible moves, but we have something like

X * Number of empty squares reachable by side s +
Y * Squares occupied by opponents pieces reachable by side s

So it is possible to play a bit with the value of attacking pieces
as opposed to attacking empty squares.


Peter Mysliwietz

0 new messages