# "YSS 7.0" ---About the data structures and the algorithm ---

Japanese original 1997 5/29
This paper was published as "Computer Shogi no Shinpo2" in Japan 1998-05-20. (Editor and writer by Hitoshi Matsubara. ISBN4-320-02892-9 \2300)
Hiroshi Yamashita ( Shogi Programmer )
E-mail: cxj00674@nifty.ne.jp

It was 1987 that I had been interested in the Shogi(Japanese chess) program. I found "ESS" in the secondhand book shop. "ESS" (Electro-brains Shogi System) was printed to the magazine of “MICRO" of the sale in 1984. I began to make shogi program “YSS(Yamashita Shogi System)" at that time. And I (YSS 2.0) participated in the first time the 2nd computer shogi championship in 1991. I participated in the championship continuously after that. My rank was 5, 4, 4, 3, and the 4th place from the 2nd championship. Finally "YSS 7.0" won the 7th championship in February 1997. And "Kanazawa Shogi" that won four times continuously lost.

I explain search algorithm and evaluation function of "YSS 7.0". "YSS 7.0" is sold as“AI Shogi 2" in Japan form Ascii Something Good Company in April, 1997.

```-----------------------------------------------------------------------
1. Data structures

2. Move generator
2.1 Classification of move
2.2 Temporary move evaluation
2.3 Sequence of move generation
2.4 Null move and regret move generation
2.5 Killer move

3. evaluation function
3.1 Judgement opening, middle-game and endgame
3.2 Value of pieces
3.3 Castle making in opening
3.4 Middle-game and endgame
3.5 Evaluation of end node

4. Search algorithm
4.1 Half ply extension
4.2 Transposition table
4.3 Two type of Horizon effect
4.4 Breakthrough repetition moves (successive check)

5. Checkmate problem (Tsume shogi)
5.1 Checkmate problem
5.2 Brinkmate

6. Reference game record

7. Solve the shogi equation

8. Epilogue
```

```1. Data structures

To make computer play shogi, it is necessary to teach the rule of shogi at
least.

The first plan of data structures is important because the influence is the
largest in the programming afterward. I changed basic data structure three
times. Finally I adopted using Piece Number.

All programs are written in the C language, and move on WindowsNT.

A basic data structure of YSS is following.
All 40 pieces are numbered as 1-40.
Black King is 1. White King is 2. Rook is 3-4, Bishop 5-6,
Gold 6-10, Silver 11-14, Knight 15-18, Lance 19-22, Pawn 23-40.

Position and status ( black or white, promoted or non ) are maintained each
pieces.

In real shogi board, right top is (1,1) and left bottom is (9,9).
But this coordinate system is bad for computer.
So I use left top (1,1) and right bottom (9,9).
Real 77-76 Pawn is changed 37-36 Pawn. X coordinates reverse.

Shogi board is 9*9. So it is easy to use two dimension of 9*9.
But I use one dimension board[256] for speed.

The position of coordinates is shown with y*16+x.
So 76 Pawn is 36 Pawn, and x=3, y=6.
Because x=3 and y=6, z = y*16+x = 0x63 ( in the C ).
Board[0x63] show number of piece that exists here.

For clearly outside of board, I make a frame in surroundings of the board.
So board size is 11*11 in program.
When Kiki table (this shows the place where each piece can move) is made,
an extra judgment is unnecessary.

- Table 1 - Kind of Black piece and number

Pawn     Lance     Knight     Silver Gold  Bishop  Rook  King
1        2         3           4     5     6      7     8
Promoted Pawn Pro.Lance Pro.Knight Pro.Silver ----  Horse  Dragon
9       10        11          12    13    14     15

When piece promote, number is add 8. White piece is added 0x80(=128).
For example, White Dragon is 0x8f(= 128+7+8). Do you think shogi piece
is convenience for expressing by hexadecimal notation?

Initialize board data is following. 0xff is outside.

int board[256]= {
0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0,0,0,0,0,

0xff, 0x82,0x83,0x84,0x85,0x88,0x85,0x84,0x83,0x82, 0xff,0,0,0,0,0,
0xff, 0x00,0x87,0x00,0x00,0x00,0x00,0x00,0x86,0x00, 0xff,0,0,0,0,0,
0xff, 0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81,0x81, 0xff,0,0,0,0,0,
0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0,0,0,0,0,
0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0,0,0,0,0,
0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0,0,0,0,0,
0xff, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0xff,0,0,0,0,0,
0xff, 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x07,0x00, 0xff,0,0,0,0,0,
0xff, 0x02,0x03,0x04,0x05,0x08,0x05,0x04,0x03,0x02, 0xff,0,0,0,0,0,

0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0,0,0,0,0};

Piece Number(1-40) that don't exist in the board is pushed in the stack
according to each kind of piece.
When dropping the piece from the hand, program pop the empty Piece Number
from the stack.

For example, when Black drop Pawn to 47 in Fig. 1,
Pawn that don't exist in the board is 4. ( All Pawn is 18)

/* Content of stack */

PN_stack[1][0] = 0 （unused）
PN_stack[1][1] = 25
PN_stack[1][2] = 33
PN_stack[1][3] = 36
PN_stack[1][4] = 27 The number of pawns not used is 4.

PN_stack_number[1] = *PN_stack[1][4] (indicate）

|
V

PN[27][0] = 0x01 Piece Number 27 is Black Pawn.
PN[27][1] = 0x76 Position is 0x76 (=47 Pawn)
PN_stack_number[1]-- decrease stack, [1] is Pawn ,[2] is Lance.

Table 2. Main Data Array of YSS ( all is int.)

board[256] Piece Number is entered.
init_board[256] Kind of piece (nothing is 0, outside is 0xff,
Black Piece is 0x01-0x0f, White is 0x81-0x8f)
Hand_Black[8] Number of Black Hand
Hand_White[8] Number of White Hand
Kiki_Black[256] Kiki number of Black.
Kiki_White[256]
KikiC_B[256][32] Content of Black Kiki (what kind of piece?).
Kiki number maximum is 18.
KikiC_W[256][32] Content of White Kiki
PN[41][2] Piece Number [][0]...kind of piece, [][1]...position of piece.
PN_stack[8][32] Empty Piece Number.
*PN_stack_numbe[8] Pointer of empty Piece Number.
move[64][64][8] Move of each ply. (64 plies depth, 64 moves in one depth,
8 is move content and etc..)
best[64][64][4] best sequence. maximum depth is 64.
(4 is move content. Before, After, Capture piece, Promote flag)
ret_depth[64] depth of calling evaluation function.
depth_add Decimal point part of depth max.
depth_max depth_max.
*MoveP[64] Move pointer in each depth. This indicate move[64][64][8].

In the C language, an internal calculation is expressed by the bit shift
when you use array of 2^n ( for example, [53][64] or [3][16][256] ).
So you should use 2^n array for speed up.

Figure 1: explain of Kiki

There are two kinds of Kiki, indirect Kiki and direct Kiki.

Direct Kiki is the place which piece can actually move.
In indirect Kiki, piece can't move actually.
But when exchange is continue, indirect Kiki become effective.

For example in Figure 1, the place of 86 have indirect Kiki of 82 Rook.
Exceptionally, Kiki of Rook, Bishop and Lance go through opponent King one
step. This is useful in the checkmate judgment of king.

In Figure 1, Kiki of Black 44 Bishop go through opponent 33 King and reach 22.

Additionally in Figure 1, when 62 Silver move to 71, 44 Bishop Kiki is
effective in 71. This is called shadow Kiki. But YSS don't have Shadow Kiki.

KikiC_B[256][32] have Black Piece Number that can move here
(direct or indirect).
For example Figure 1 in White, the place of 86 have Kiki of 85 Pawn
(Piece Number is 26) and 83 Lance (Piece Number is 19) and 82 Rook
(Piece Number is 3).

Kiki_White[0x62] = 3; The number of White Kiki.
KikiC_W[0x62][0] = 26; The 26 Pawns work.
KikiC_W[0x62][1] = 3 + 0x80; The 3 Rook work
(0x80 is added because it is indirect).
KikiC_W[0x62][2] = 19 + 0x80;
The 19 Lance work (0x80 is added because it is indirect).

When the piece moves, these data structure is update partially only the place
with the change.

When 39 Silver moves to 38, all Kiki of 39 Silver is deleted.
And all 38 Silver is written. In this case, right Kiki of 88 Rook is
stopped by 38 Silver. So only right Kiki of Rook is deleted and written.

Besides, the data updated at the same time is hash (transposition) code
and basic value of pieces.

Table 2 shows main data structure of YSS.
Because I divide all data to Black and White, program have exclusive move
generator routine for Black and White.
For example, there are two routines which search fork of Bishop.
It is very useless, but when thinking of speed, it is slight.

2. Move generator

2.1 Classification of move

At first, YSS classify all move to "attacking move" and "defense move".

"Attack move" is the following three.

- Capture opponent's piece.
- Promote piece.
- Threat to capture (include fork).

"Defense move" is following 6.

- Capture piece that threaten my piece.
- Drop my piece before opponent drop.( when opponent drop is good.)
- Threaten square where opponent piece intend to move.
- Threatening piece run away.
- Interposes any piece when opponent rook or bishop or lance moving is good.
- Interposes any piece in square where opponent's rook or bishop or lance
threaten.

Only run away move in this 6, I actually move the piece on the board, and
calculate gain of piece, and select upper 3 or 5 move ( rook and bishop
is 5, gold and silver is 4), when (depth_max - depth) >= 3 .

Other move, I evaluate moves without actually moving on the board (only
temporary evaluation). When fork, the move that the threatening piece run
away and protect another piece can be discovered by actually moving a step.

2.2 Temporary move evaluation

A temporary evaluation of move is processed by the MIN-MAX method
according to the number of opponent and friend's threat in moving square.

Figure 1: explain capturing 85 pawn ( show once more )

For instance, I explain value of capturing 85 pawn in figure 1.
At first, value of pieces is assumed Table 3.
Second, piece exchange is done sequentially from low value piece to high
value piece.
In figure 1, Black pieces moving to 85 is knight, silver, bishop and to rook
sequentially. White is lance, gold and rook. (In figure 2, when white rook
and lance places change, lance can't move 85 first. But my program doesn't
consider it.)

Here, black has right to capture or not capture 85 pawn first.
If black capture 85 pawn by knight, white also has right to capture or not
capture 85 black knight by lance.

Figure 2

This makes Figure 2.
In figure 2, black is max, white is min, capture is left, not capture is
right. At first, if black don't capture 85 pawn, black score is 0 of course.
When black capture, if white don't capture, black score is +200 ( a pawn ...
this use exchange value in Table 3).
And when white recapture, if black don't, white score is +700. ( a knight -
a pawn )

Thus, making MIN-MAX tree, the value of capturing 85 pawn is +160 after all.
I use this value with adding board fixed value etc...

Table 3: value of pieces

Pawn  Lance Knight Silver   Gold Bishop   Rook  King
basic value             100    430    450    640    690    890   1040  ----
promotion value         320    200    190     30   ----    260    260
add in hand (one)        15     50     60     80     90    220    230

exchange value          200    860    900   1280   1380   1780   2080
exchange promoted value 520   1060   1090   1310   ----   2040   2340

p.s. exchange value = basic value * 2.
exchange promoted value = basic value * 2 + promotion value.

2.3 Sequence of move generation

In searching depth N position, the sequence of move generation is following.

If (depth_max - depth) >= 1, these move is generated.

- Capture opponent piece that move immediately before.
- Capture opponent pieces (if effective)
- Promotion piece.
- Regret move. ( explain 2.4 )
- Effective check( piece exchange is effective)
- Most high value piece run away if threaten. ( second doesn't consider)

If (depth_max - depth) >= 2, these move is generated.

- Threaten move (include fork)
- Discovered check.
- Drop Gold and Silver in front of opponent King.
- Discovered threaten move.
- Threaten pin piece. ( Pin piece can't move. If move, King ( or other piece)
is captured by Rook (or Bishop or Lance). )
- Drop Rook and Bishop in opponent's camp.

If (depth_max - depth) >= 3, these move is generated.

- Wild drop around opponent King. ( Drop piece in square that have many
friend and opponent Kiki.)
- Send off move. ( Sacrifice check. And if taken by King, defense piece is
captured.)
- Capture Silver, Gold, Bishop and Rook, even if not effective )

If depth <= 2, these move is generated.

- Pawn move in front of Rook and Lance.
- Sacrifice move and drop. (If taken, new capture and fork is effective.)
- Dangle ( drop a pawn before the target field, threatening promotion next)
- Strike ( drop a pawn right in front of an enemy piece )
- Sacrifice promotion of Pawn.
- Interpose (against enemy Rook and Bishop)
- Promoted pawn (and all) in enemy camp move sideways toward enemy King.
- Drop pawn in front of before move.
- Threaten against before move. Or gold and silver move toward before move.
- King move.

If depth == 2 and opening, these move is generated.

- Threaten pawn.
- Vanguard pawn.
- Random move. ( not include drop )

If depth == 1, these move is generated.

- Random move. ( not include drop )
- Check ( not consider value gain)
- Random pawn drop (under 15)

All move generation subroutine have a upper bound of move number.
And moves is picked up from a move that to be important.
And, the upper bound of number depends on the remainder search depth.

Program does not consider fork if search remainder is only one ply.
It only consider over 2 plies. For example, fork of King and Rook by Bishop
need 2 plies. 2 plies is drop Bishop, and King run away.
You may think that a move Bishop capture Rook can't consider only 2 plies.
It need 3 ply? Yes. But in practice, exchange evaluation routine of end node
is in place of it. ( Of course, certainty is not.)

In short, the move should consider if there is the remainder search depth to
achieve the move's aim.

The threaten move subroutine is made especially and carefully in all move
generations.
In YSS, when remainder search depth is over 3 plies, upper 5 threaten moves
However, threaten moves reaches 10 or 20 moves occasionally. So picking up
sequence is important.

YSS is following.

- Fork by Lance, Knight, Silver, Gold, Bishop and Rook. Move is given
priority than drop.
- Threaten (from Rook to Lance) move. Move is also given priority than drop.
Especially, Gold and Silver drop for threaten Rook and Bishop, is evaluated
low. But Pawn drop is high.

YSS don't sort moves. Move sequence and generation sequence is same.
After generation, YSS only vanish same moves. ( However the last best move
is putted at first.)

The average number of move generation is 80 ( one depth), 40 ( 2 depth ),
20 ( 3 depth ), 6-13 ( over 4 depth ) in the middle and end game.
There is no upper bound number as whole.

In iterative deepening, if it takes 6 times time, YSS can search one ply over.

2.4 Null move and regret move generation

Regret move generation is defense purpose generation.
In selecting defense move, if silver will be captured for free, you can find
easy to protect it.
For example, threatening square that silver exist, or silver run away.
But if opponent rook sacrifice is effective ( if capture rook, king mate!),
you can't find to protect it easy. One ply search can't find rook sacrifice.
In other words, if you see only position ( not include searching), you can't
find defense move.

One of the methods of solving this is regret move.
First of all, program pass and get opponent best move.
And program generate moves to protect it.
In a word, program find an opponent most effective move when I idle (same
Null Move), and program protect it.

In reality, program pass and get best sequence. And in this sequence, if it
is own move, it is generated,
and if it is opponent move, a move to protect it is generated.

Figure 3 is shown as an example. It is Sente turn.

Figure 3

In this position if Sente pass, Gote 54 pawn and Sente bishop run away, and
76 rook will capture 77 knight.

If in this position 55 bishop does not exist, you find that 77 knight is
captured next. So you can easy find threatening move 77 square, ex. 78
silver or 68 gold.

Here I assume Sente passes.
In this case opponent best move is 54 pawn and ... capture 77 knight.
The best sequence will be PASS, 54 pawn, 46 bishop, 77 rook promote, 69 king.

In this sequence Sente moves is added the generation list, and moves to
In this case, 2 moves (46 bishop and 69 king) is added, a move to protect 54
pawn ( nothing this case) and a move to protect 77 rook promote, for example
78 silver, 68 gold.

Then, program can find protect moves that can't find in one ply search.

Notice! These moves might be impossible for changing board if it is not the
move to protect immediate before move. Therefore, it is necessary to check
whether the move is a violation of the rule severely.

In an actual search, YSS passes all nodes without end node and get best
sequence. And in best sequence YSS don't generate to protect opponent move
over 3 depth. ( when root node, generate all.)
The reason for this is that the protect moves will be too much when the best
sequence is long ( 10 plies or more ).

This regret move generation also has the fault.
At first there is need to get opponent best move when pass.
Alpha-beta value must be reset -infinity and +infinity.
So the efficiency of the search worsens (The idea of Window can not be used.)

Moreover, the best opponent move might be always actually the not best
because YSS use alpha-beta value that is taken over from parent node without
root node.
For instance, alpha-beta cut has occurred by capture rook (but a ply mate
exist! in reality).
So program generate moves to protect capture rook, not a ply mate.
For using iterative deepening, I think this fault is less, but not complete.

2.5 Killer move

The best opponent move that is obtained by a pass will become ideal killer
move. However I don't use killer move now, because the necessity is not so
much for remembering all position's best move in big hash table.

3. Evaluation function

3.1 Judgement opening, middle-game and endgame

The evaluation function is divided into two (opening and middle-end game)
in YSS. Program judge before searching whether a present position is opening
or middle-end game. (Do not change during the search).

The standard of the judgment is as follows.

- Sum of both Sente and Gote hand (over lance) is more than three pieces.
- The piece more than silver (or promoted piece) invades the enemy's camp
(Friend's camp is too).
- The piece more than lance is threatened (enemy and friend).

When these three condition is approved, it is judged the middle-end game.
However, if it is less 10 moves from game start, it is opening.

Value of pieces is always constant in YSS. However its value increases and
decreases severely by the position in middle-end game.

3.2 Value of pieces

The value of pieces is Table 3.

Table 3: value of pieces (again)

Pawn  Lance Knight Silver   Gold Bishop   Rook  King
basic value             100    430    450    640    690    890   1040  ----
promotion value         320    200    190     30   ----    260    260
add in hand (one)        15     50     60     80     90    220    230

exchange value          200    860    900   1280   1380   1780   2080
exchange promoted value 520   1060   1090   1310   ----   2040   2340

p.s. exchange value = basic value * 2.
exchange promoted value = basic value * 2 + promotion value.

Exchange value is used when piece exchange. It is twice of basic value.
(Why? if piece is captured, board value is down. and opponent hand value up.
so twice.)

Exchange promoted value is twice of basic value and promotion value.
(You should think yourself!)
"Add in hand" in Table 3. shows one piece hand.
If you have 1 gold, 90 is added . If 2 gold , 90 + 40 is added.
So 1,2,3,4 is 90,40,10,0. Capturing same kind of pieces is less value.

3.3 Castle making in opening

Piece value is constant in opening.
Additional value ( the nearer the center of the board or opponent's king,
the higher value.) is a little (under 10% of the value of the pawn).

A main increase and decrease standard depends on "Increase and decrease table
for the castle making" and "Vanguard Pawn".

YSS don't use opening book at all. So YSS's opening is weak.
But I think computer should not use difficult opening that computer can not
understand. He can't play from the end of it.

YSS use "Pitfall method" (I called) in opening making castle.
YSS makes table that if gold and silver is in a certain position, it is +n
point. If YSS wants to make a piece move fast, the point difference of
square and square is bigger. So each pieces fall (move) in high value
difference order. And Yagura castle or Mino castle is made at last.

YSS makes this table for all pieces.

Actually YSS has this table for "Yagura", " Static Rook Bear-in-the-hole",
"Left(side) Mino", "Yamada System(57Silver Quick Attack)", "Aerial Fight",
"Ranging Rook", "Ranging Rook Bear-in-the-hole", "A castle in 2-(or 4 or 6)
piece handicap)", "undecided castle".
And what table YSS use is decided by random and opponent's rook position.

The increase and decrease by which the actual combat meaning is considered is
For instance, the lance position lower, the value higher. The jumped knight
to the edge of board is low.
The gold and silver in a corner is big low. The rook in 7 rank is a little
low. And etc..

- Vanguard Pawn

Following description is seen from Sente.
Object of vanguard pawn is only Sente pawn in 3, 4, and 5 rank.

- If a pawn is in 5 rank and opponent pawn is in 3 rank, points is +1.
If there is no opponent pawn and my pawn don't threaten from friend,
+2 points. If threaten , +15 points.

- If a pawn is in 4 rank and it can promote next (the forward square
don't have enemy's threat.) is +100 points. If opponent pawn is in 2
rank, +20. If not, +40. If a pawn in 4 rank have friend threat, +10

- If a pawn is in 3 rank, its value is low than in 4 rank.

In short, if a pawn is in 3,4,5 rank and opponent pawn is not in 1,2,3 rank,
pawn value is up.

The other pawn value is as follow.

If there is no pawn in same file that have rook, +35. And if enemy don't
protect its file by pawn, +30. If there is no pawn ahead of king, -15.
Because it is worse that exchange a pawn ahead of king in Yagura fight.

I think making castle in opening can be generalize in the future.
It is sure to become the balance problem between the concept of vanguard
and gold (and silver) position basically.

3.4 Middle-game and endgame

The evaluation function of middle and end game divides into three part that
is value of pieces, king safety and the increase and decrease by piece
position. Piece value is always constant. The big change elements is king
safety and piece position value. I don't care which turn do Black or White
have.

The each king position decide the increase and decrease by piece position.
If a piece is near friend(or opponent) king, value is up. If a piece is
far from both kings, value is down.

Table 4 shows White(Gote) piece value toward Black(Sente) king. It assume
that piece value is 100. If point is 50, piece value is half. It omit
minus X axis because of symmetry.

For instance, if Black king is in 69, and White gold is in 37, it is 114
(69-->(0,0) 37--->(3,+2)). Because gold value is 690, the added point
becomes 690* (114-100)/100=+96 points. It is 690*(75-100)/100=-172 points
when there is gold in 19 (69-->(0,0) 19--->(5,+0)).

--- Table 4 ---

Increase and decrease rate by relative position of Black piece toward White
king. It is symmetry for X axis.

0   1   2   3   4   5   6   7   8  (X distance)

+8   50  50  50  50  50  50  50  50  50
+7   50  50  50  50  50  50  50  50  50
+6   62  60  58  52  50  50  50  50  50
+5   80  78  72  67  55  51  50  50  50
+4  100  99  95  87  78  69  50  50  50
+3  140 130 110 100  95  75  54  50  50
+2  170 160 142 114  98  80  62  55  50  <--- Two above king is maximum.
+1  170 165 150 121  94  78  58  52  50
0  170 145 137 115  91  75  57  50  50  <--- This is center.
-1  132 132 129 102  84  71  51  50  50       Black king is in (0,0).
-2  100  97  95  85  70  62  50  50  50
-3   90  85  80  68  60  53  50  50  50
-4   70  66  62  55  52  50  50  50  50
-5   54  53  51  50  50  50  50  50  50
-6   50  50  50  50  50  50  50  50  50
-7   50  50  50  50  50  50  50  50  50
-8   50  50  50  50  50  50  50  50  50

(Y distance)

Table 5 shows Black piece value toward Black king.
Exceptionally pawn, lance and knight value is less than Table 5. And lance
and knight value are calculated by assuming that lance and knight is in
one rank up position.(Lance and knight maximum value is three above king.)

Finally piece value is decided by larger value from Black king or from
White king.

--- Table 5 ---

Increase and decrease rate by relative position of Black piece toward
Black king. It is symmetry for X axis.

0   1   2   3   4   5   6   7   8  (X distance)

+8   50  50  50  50  50  50  50  50  50
+7   56  53  50  50  50  50  50  50  50
+6   64  61  55  50  50  50  50  50  50
+5   79  77  70  65  54  51  50  50  50
+4  100  99  95  87  74  58  50  50  50
+3  116 117 101  95  88  67  54  50  50
+2  131 129 124 114  90  71  59  51  50
+1  137 138 132 116  96  76  61  53  50
0  142 142 136 118  98  79  64  52  50  <--- This is center.
-1  132 132 129 109  95  75  60  51  50
-2  121 120 105  97  84  66  54  50  50
-3   95  93  89  75  68  58  51  50  50
-4   79  76  69  60  53  50  50  50  50
-5   64  61  55  51  50  50  50  50  50
-6   56  52  50  50  50  50  50  50  50
-7   50  50  50  50  50  50  50  50  50
-8   50  50  50  50  50  50  50  50  50

(Y distance)

Figure 5: gold addition value by position

This figure shows the increase and decrease by the position of Black gold.

Value is added near both kings and value is growing especially in the upper
part of White king. (This feeling is restraining opponent king.)
If one ply search, program select dropping gold in two above opponent king
(attack) in place of dropping near friend king (defense).

In respect of Horse and Dragon, if its position is plus, value is added.
But if its position is minus, value in not added. Major piece(rook and
bishop) have big movement. So if they are far from battlefield, they are
working well.

If rook(dragon) is in enemy camp, addition value is much  influenced its
position (obstacle from king to rook). If anchor pawn exists between opponent
king and friend rook, value is low.

The increase and decrease table for pawn, lance and knight is calculated from
the position of king before searching.
So if king moves while searching, table value will go wrong. Other piece
(Silver, Gold, Rook, Bishop, Promoted piece) are calculated correctly.
This is for speed-up.

King safety element is following.

- Wall gold(silver) is minus.
If king is in 4 or 3 file and king can not move 3 or 2 file, it is minus.
- If surrounding 8 square of king have opponent threatening,
-- If friend piece is in this square, and enemy threatening is ahead
(or same), minus is 1/4 of this piece value.
If friend threatening is ahead, minus is 1/8 of this piece value.
-- If square has no piece, and enemy threatening is ahead, -250.
If threatening is same, and enemy has piece that can be dropped this
square, -200. If no drop piece, -130. And another is -50.

These value is for king above square. Value falls by going below square.

- The piece that is pinned by enemy rook or bishop or lance, is minus.

For entering king, king value is up by nearer enemy camp.
For instance, the addition value form 1 step to 9 step in 1 file is
following.

Step  1   2   3    4    5    6     7    8    9
add   0,  0,  0, 150, 450, 900, 1300,1550,1600 (1 or 9 File)

3.5 Evaluation of end node

Evaluation of end node is following.

At first if there is check, program search more one ply unconditionally.

In another position, program find maximum value of capturing piece by next
move. And program adds this value to the static evaluation function value.
Additional value is piece exchange value. If a pawn is captured next turn,

I don't consider stop searching depth is odd or even. If search depth reaches
depth limit, search stops and evaluation function is called.
I don't use singular extension (that is used in Deep Blue).

4. Search algorithms

4.1 Half ply extension

I used fixed depth alpha-beta search till YSS 6.0. But I have used iterative
deepening from YSS 7.0. The reason is that I want to try whether half ply
extension algorithm is effective.
Iterative deepening (maybe you have known in chess program) is not fixed depth
search, but increase depth search one by one.
At first, program runs one ply depth search, and found a best move. Second,
program runs two ply depth search. This time, program search from the best
move that is found in one ply depth search.
In the same way, program searchs 1,2,3,4,5, ... ,n-1,n ply depth search.
Program can search effectively with alpha-beta algorithm because of searching
from the best move that is found n-1 ply depth search.

This method is effective for time limit play. When time limit has come while
thinking n ply depth search, if program is searching first move(the best move
in n-1 ply depth search), program select this first move.
If searching second move, program select first move because program don't know
the correct value of second move. If searching third or over, and the best
move is changed, program select the now best move.

Half ply extension algorithm is a variation of iterative deepening.
When half ply extension is used, program searches the memorized best move at
first and depth max is added 0.5 ply only first move. Two 0.5 ply extension
make one (real) ply extension. So a move that is thought good is searched
deeper.

Figure 6 is shown as an example.

Figure 6: Three depth game tree of half extension algorithm

Fig.6 shows basic three depth search tree with half ply extension algorithm.
Each node has two branches. And left branch (thick line) shows best move.
The number (that is shown in node left side) shows depth max.

If program select left(best) node, depth max is add 0.5 ply. If program select
right node, depth max is not added.
If program select best move 3 times from root node(depth max = 3), depth max
is +0.5, +0.5, +0.5, so depth max = 4.5 .
If normal search, search stops this 3 depth. But in this case, program can
search continue because of 4.5 depth max.
If program select best move from this depth 3 node, depth max is 5.0 .
Program can search one ply again.
If program select best move from this depth 4 node, depth max is 5.5 .
This depth is 5, and depth max is 5.5. This doesn't reach 6. So program
stops searching this 5 depth.

On the contrary, if program select right branch 3 times, depth max is 3, not
adding. So program stops searching this 3 depth.

As a result, when basic n (=3) depth search, program can search plausible
branch 2n-1 (=5) depth in the maximum.
The feature of this algorithm is that time (number of end position) takes
only 2〜3 times in comparison with normal search. For instance, search
time takes only 2.35 times when basically depth max is 8, maximum is 15,
and branching factor is 20. Table 6 shows this.

Table 6: Time and maximum depth. Branching factor is 20.

Basic Time Maximum
Depth      Depth
2   1.04   3
3   1.14   5
4   1.28   7
5   1.46   9
6   1.70  11
7   2.00  13
8   2.35  15
9   2.79  17
10   3.32  19

In the actual search, branching factor is about 6-80, and extend move is only
one move (best move) in all moves. Program check the hash table for finding
n-1 search's best move. If n-1 best move doesn't exist in hash table,
program have 2 ways. One is extension stop. In this case, node is end node.
Second, program restart iterative deepening from this node and find best move.
(multi iterative deepening) If depth_max = 7 and depth = 3, program change
depth_max =  4, 5, 6, 7.

If program find new best move, depth max is added 0.5 and program search this
new best again.
Why? because old best move have searched in (depth max + 0.5), and new best
move have searched only (depth max).

The most difficult problem is to test strength up by this half extension
method. In my now experiment (1998-03-25), the half extension program
win 249, lose 150, draw 1, against not use half extension. Winning rate is
0.62. Do you feel this is big or small? If my program use twice time,
twice's winning rate is about 0.6. three times is 0.75, fifth times is 0.88.
Ten times is 0.88 ( no big change from fifth).

Note:2003-02-19
Now YSS is using perfect half ply extension.
"Perfect" means if program finds ex-best move from hash table is not "best",
he searches this new best move by added +0.5 depth limit again.
And YSS also uses "Internal Iterative Deepening".
If YSS find there is no "hash" move in 5 left depths search, YSS searches
this node from 1 depth search to 5 depths search one by one.
This is done in all node. Only PV node "internal iterative deepening" was
no good for YSS.

This requres three times thinking time, but it became stronger.
I think it's important how deep it can search when best move is changed.

Table 7 shows the rate of depth by which the evaluation function is called.

This is made by YSS self play. All rate is sum for white and black.
In opening, search stop in short depth, so main depth rate is from middle and
end game. 60 percent or more exceeds basic 8 depth. The maximum depth is 20.
This is because of king check extension and 2 ply extension for horizon
effect.

-- Table 7 -- the depth rate that evaluation function is called.

depth: %
1:  0.0:
2:  0.0:
3:  0.2:
4:  0.5:
5:  1.2: **
6:  3.3: ******
7: 10.7: *********************
8: 21.0: *****************************************
9: 25.7: ***************************************************
10: 20.3: ****************************************
11: 10.1: ********************
12:  3.9: *******
13:  1.7: ***
14:  0.9: *
15:  0.4:
16:  0.1:
17:  0.0:
18:  0.0:
19:  0.0:
20:  0.0:

Game end 140 moves. Basic depth max is 8.
A move search is permitted for 40 second.
All search node is 78436893.
All thinking time is 2250 minutes. (CPU Alpha500MHz).

I don't know  extension rate 0.5 is best.
Another idea is change rate from 0.1 - 0.9, and extended another move in
addition to best move or shortening.

Figure 7 and Figure 8 show the max function of simple alpha-beta search
and the min function of YSS that use half ply extension.

Figure 7. - Max function of simple alpha-beta search -

int f_max( int alpha, int beta )
{
if ( depth >= depth_max ) return(evaluation value);

making moves

for ( i=0 ; i < number of moves ; i++ ) {

depth++;

k = f_min( alpha, beta );

go back a move
depth--;

if ( k > alpha ) alpha = k;
if ( alpha >= beta ) return(alpha);
}

return(alpha);
}

Figure 8 - Min function of YSS that use half ply extension -

int f_min( int alpha, int beta )
{
Check the hash table. (left search depth)
If already searched or high limit <= alpha, return value , best move,
and search depth of value.

if ( depth >= depth_max && King is not check ) {
Set of search depth of value.
Call evaluation function. And add next capturable piece value.
}

if ( King check ) defense move is generated.
else {
Check 1 ply mate.
Call check mate program that depend on left search depth.
Generate move that capture opponent piece that move immediately
before.
Generate move that capture pieces.
Regret move. ( explain 2.4 )
Generate another moves.
}

Cut same move.
Set n-1 best move to first move.
Check 2 ply extension for Horizon Effect in this position.

for ( i=0 ; i < number of moves ; i++ ) {

depth++;

if ( i==0 ) depth_max += 0.5;

k = f_max( alpha, beta );

if ( k < beta && 2 ply extension flag ) {
depth_max += 2;
k = f_max( alpha, beta );
depth_max -= 2;
}

Go back a move.
depth--;

if ( k < beta ) {
beta = k;
Copy search depth of value.
Copy best sequence.
}

if ( i==0 ) depth_max -= 0.5;

if ( alpha >= beta ) {
Set hash table.
return(beta);
}
}

If there is no move to protect King check, drop pawn mate is checked.
if ( Is beta value is renewal once? ) Set beta value to hash table.

return(beta);
}

4.2 Transposition table (Hash table)

YSS use Hash table in Tume search and actual search. End node is not
registered in both searches. I use Open Address method. And re-hash times
are 16. Re-hash sequence is fixed random sequence. ( This is effective in

If YSS use 75% hash table, YSS judge that hash table is full, so registration
stop at 75%.

I use 64 bit value in hash code. At first, I used 32 bit value.
But in 32 bit, 2 or 3 misconceptions occurred frequently at 300,000 position
search. This was very reliability. So I changed 64 bit.
In my rough estimate, if using 64 bit, the probability that one misconception
will occur is 1% at during a day searching.
( Search speed is 10,000 node/sec. And all position in a day search is about
2^32 positions.)
Random number is made by the multiplier combination method.
( a=16807, m=2^32-1 )

In main thinking routine, YSS search Tume search at first. And only position
that is TUMI (checkmate) is registered for main search hash table.
I separate main search hash table and Tume search hash table. And in Tume
search, I separate Black Tume and White Tume. Why? This is for Gyaku Oute
position. ( Black check white king, but next white defense move is check
to black king! This makes confusion.)

Whether now turn is black or white is shown by reversing hash code.
If two pass, hash code returns original. (0x01 -> 0xfe -> 0x01)

Table 8. Value registered in hash table

1. Hash code  64 bit
2. Hand code  32 bit
(Each kinds of number of white hands. Black hands is none.)
3. Evaluation value for main search
( upper bound, or lower bound, or  accurate value)
4. Flag that whether (3.) value show upper or lower or accurate.
5. Search depth ( How depth is searched from this position?)
This is shown by (real depth * 256).
If 3.5 depth is searched, the value is 3*256 + 128 = 0x0380.
6. Relative search depth for Black Tume.
7. Value for Black Tume.
( TUMI(checkmate), UTI-FU-TUME(drop pawn checkmate),
FUMEI(unknown), KIRE(can not checkmate) )
8. Relative search depth for White Tume.
9. Value for White Tume.( TUMI, UTI-FU-TUME, FUMEI, KIRE )
10. Best move

4.3 Two type of Horizon effect

In computer shogi (of course, in computer chess), the program often play some
meaningless striking pawn or strange moves that will be only loss of tempo
or loss of pieces.

This is called "Horizon effect".

Figure 9. Horizon effect is apt to happen.

Figure 9 is YSS - Kiwame at 4th Computer Shogi Championship in 1993.

This is Black turn.
Black king (YSS's king) is checkmate by next White drop 58 Gold.
The best move will be 57 Silver with capturing 57 pawn. But if this move,
87 Horse (check), 58 King, and 65 Horse with capturing Knight. So Black
can't play 53 Knight promote with capturing Rook!

If human, he will think "I have no choice but to play 57 Silver."
This is good. But if computer, he doesn't think so.

YSS's next move was 62 drop Kin. Why? At this time YSS's search depth was
fixed 6 plies. And in 6 depth, YSS could not search check to my king from
enemy.
YSS's thought was that 62 Gold, 82 King, 72 Gold, 72 Do Gold, 53 Knight
promoted. 53 Knight was 5 depth, so YSS didn't search next 58 Gold drop,
and he thought this line was my Rook gain!

Thus, by continuing check, computer pushes out enemy's effective move from
his search limit.

Actual game was played following.
62 Gold, 82 King, 71 Silver, 71 Do Gold, 72 Gold, 72 Do Gold, 57 Silver.

The most fatal move in this line was 71 Silver (check).
62 Gold (check) and 72 Gold (check) were not profitable moves, but not fatal
moves. (If 62 Gold - Do 62 Gold, Do 62 Knight promote - Do King - 53 Knight
promote. This was good for black.)
But 71 Silver was blunder. This was only loss of Silver.
And for this one move, position changed from a little better to very bad.
The reason why played 71 Silver was same as 62 gold.

The problem is here. When Horizon effect happens by a not profitable move
(check or etc.), it is not fatal.
But if he play a loss of piece to protect own one ply checkmate, it is fatal.

If Horizon effect happens without loss of piece (ex.  effective check or
threaten move without loss of piece),
I call this "Slight injury Horizon effect", and I don't deal with it.
(To tell the truth, I don't know how to deal with it...)

The important problem is "Heavy injury Horizon effect".
This plays a loss of piece actually.

I wanted to solve "Heavy injury Horizon effect".
As a result, my conclusion is following two.

1. Don't search such a violent move!
2. It is necessary to make the computer understand a useless attempt after
all when a violent move looks effective.

The first method is applied to deeper node.
It is important that program should not search violent move in deeper node.
In deeper node, program should search only a few moves that is clearly
effective. (runaway or capture)

To solve the second problem, YSS use +2 plies extension.

At first, program search by normal depth limit.
If program play sacrifice move, and value is updated against capturing
sacrifice piece (Horizon effect happen?), depth limit is added 2 plies for
this sacrifice move and capture.

For example in Figure 9, program searchs 79 Silver - Do 79 Gold line. Horizon
effect was happened, and value was updated. So program research 6 depth
limit search after this 79 Silver - Do 79 Gold. (8 depth limit search from
root node.)

Simply, search space is twice. So thinking time is twice too.
If capturing sacrifice move is not only one, program research all capturing
moves.

The best move after 2 plies extension seems root node's best move.
At first I picked up the root best move from hash table, and I only
searched this best move after 2 plies extension for speed up.
But this was not stable. Why? Because this best move was influenced Horizon
effect too. It was often "striking pawn".

Now YSS only use this 2 plies extension at depth 3 and 4.
So YSS play meaningless (sacrifice) move only depth 1 and 2.
By this method, YSS doesn't play "Horizon effect" very much in inferior
position.

4.4 Breakthrough repetition moves (successive check)

I judge repetition moves by preserving all game record position's hash code.
If same position and my hands is less, value -= 5000.
(This is only loss of piece.)
If same position and my hands is same and enemy king is check, value -= 1000.
(This is maybe successive checks.)
If same position and my hands is same, value -= 200.
(I want to break loop.)

5. Checkmate problem (Tsume shogi)

5.1 Checkmate problem

YSS use iterative deepening and hash table in Checkmate problem.
However, it is a routine extremely simplified.
I think YSS only can mate position that will be seen in actual game.
Art of checkmate problem is out of my idea.
So many violence check move is cuted.

1. If piece loss sum is over 2 rook from counting start position, search
stops.
2. Don't search victim interpose move (also drop).
3. If before move is discard move and enemy capture it, don't search discard
move. (Don't search continuous discard move!)
4. Don't search drop move of rook, bishop, and lance. If its position is
over 4 space from enemy's king.
5. If rook and bishop and pawn can promote, it promote.

I don't think check moves order. But in king run move, if it can capture
check piece, searching its move first is effective.

For speed up, I made the last one ply check mate.
At first, YSS search king's around 8 space. And if enemy's threat is not
in each space, movable bit flag is on.
Next, if drop check move, (YSS have made that its drop check move can fill
which king's 8 spaces.) YSS check this fill bit flag AND movable bit flag.
(This AND is '&'. Of course, I believe you know. :-) )

For this method, YSS can search one ply drop mate soon. But in actual, this
idea was bug.

Figure 10. Mistake of one ply drop mate

Figure 10 shows a mistake of one ply drop mate.
In this case, YSS thought 22 drop Silver, and mate! ...No, this is wrong.
King can move 12 square. (Promoted rook line is vanished!)
So now YSS is testing by dropping piece in actual board after bit test. One
ply move check complicate board position. So YSS test these moves in actual
too.

For these extreme cut off, YSS can find over 20 plies check mate problem in
only 10000 node search. Of course, it may be not correct mate because YSS
doesn't search some interpose moves.

5.2 Brink mate

....next is now translating.

6. Reference game record

Black: Kanazawa Shogi 2
White: YSS 7.0

1.S-4h   P-3d     2.P-2f   G-3b     3.P-7f   Bx8h+    4.Sx8h   S-2b
5.S-7g   S-3c     6.P-6f   S-6b     7.G-7h   G-5b     8.K-6i   K-4a
9.G-5h   K-3a    10.K-7i   G5b-4b  11.P-5f   P-6d    12.S-5g   P-8d
13.P-2e   K-2b    14.S-4f   P-4d    15.S-5e   S-6c    16.K-8h   P-7d
17.G5h-6g N-7c    18.P-3f   P-4e    19.N-3g   P-3e    20.Px3e   P-5d
21.S-4d   N-8e    22.Sx3c+  G4bx3c  23.S-8f   S*3f    24.S*4h   R-9b
25.B*1h   Sx3g+   26.Sx3g   N*4b    27.S-2f   G-4d    28.S*5c   G4d-4c
29.Sx4b=  Rx4b    30.N*3d   Gx3d    31.Px3d   S-5b    32.P-7e   Px7e
33.Sx7e   P*7d    34.Sx7d   N*7e    35.G-7f   S*6g    36.Gx7e   B*3i
37.Gx6g   Bx2h+   38.S*5a   R-4c    39.N*3e   R-4d    40.P-2d   Px2d
41.P*2c   Gx2c    42.Nx2c+  Kx2c    43.G*3e   R-4a    44.G*4b   +Bx1i
45.Gx5b   R*2h    46.S*7h   Rx2f+   47.Gx4a   +Rx3e   48.B-2g   +B-2h
49.B-1f   K-1d    50.P-3c+  S*2e    51.P*2f   +Bx1g   52.Bx2e   Px2e
53.R*3d   +Rx3d   54.+Px3d  K-1e    55.Sx8e   Px8e    56.N*2i   +B-2g
57.R*2b   Kx2f    58.Rx2a+  R*3i    59.N*1i   +B-1h   60.S*3g   K-1e
61.+R-2d  K-1f    62.P*1g   +Bx1g   63.+Rx2e  Kx2e    64.Nx1g   K-1f
65.S-2h   R-2i+   66.B*2e   K-1e    67.S-2g   S*7i    68.K-7g   B*5i
69.G-6h   Bx6h+   70.K-7f   G*8f    71.Px8f   +Bx8f   72.K-6g   S-6h+
73.K-5g   +R-5i   74.G*5h   +Rx5h   75.quit

7. Solve the shogi equation

8. Epilogue

P.S.
Thank you for advice and reminder :-).
Nobuhiro Yoshimura
Jeff Rollason
Pauli Misikangas
Reijer Grimbergen's "A Basic Shogi Vocabulary" in his Homepage
And all shogi and computer shogi funs.
```