📜 ⬆️ ⬇️

Dagaz: Kicks to common sense (part 6)

image ... my twin is waiting in the house of Ihi, I meet him, I raise my chip to [him]
I meet him at the Beautiful House.
I pick up three chips and find two chips, my counterpart behind me.
...

papyrus since the time of Ramses III

Until now, I considered games in which each figure acts as if “by itself”. The interaction of the figures, in such games, is reduced to "eating" the enemy figures. But not all games are as follows. There are many games in which one shape can “strengthen” or “weaken” another, thereby changing its properties. This is what I want to talk about today.

5. In unity, strength


The idea that the properties of figures may depend on their relative position is not new. Apparently, this principle was used in the ancient Egyptian game Senet , known since 3500 BC. Nowadays, no one knows the exact rules of this game, but there are several reconstructions based on the analysis of materials discovered by Egyptologists.
')
According to Timothy Kendall, published in 1978, the battle of the figures in Seneta was carried out in a special way. The beaten figure was not removed from the board, but was reversed from the one who performed the turn. This idea fits well with the name of the Ibau figures - “dancers” (unlike most other games, Senet used the dance metaphor, not the fighting). The game of Senet was considered as a “training” in passing the soul of its death tests (the ancient Egyptians were very serious about this issue).

An important point of the rules of Kendall is the ability to "protect" the figures with each other. It is forbidden to "beat" a chip that is part of a "pair" - two chips belonging to one player, located in the adjacent fields of the board. Unfortunately, Kendall's reconstruction does not specify a number of important points. Is it possible to jump over a pair? Is it possible to break the "troika" and "four" chips? These questions are not answered. The rules for running chips in “houses” (special board margins) are also not very successful. As a result, the game is pretty tedious:



There are several "improvements" to Kendall's rules, among which I would like to highlight the version of Dmitry Skiryuk . In this version of the rules, "pairs" prevent the promotion of other chips. Jump them can not be! It is also impossible to break a “pair”, but if there are three or more chips in a row - this is no longer a “pair”. A chip that has two neighbors can be “beaten” (a “troika” is thus easily “broken up” in the middle). Simple rule changes make the Senet Kendall a very dynamic and exciting game. As in the case of the “ Game from the city of Ur, ” Dmitry did a great job of checking the proposed version of the rules in practice.

Sija is another Egyptian game in which the figures act "together". In this ancient game, which has survived to the present day, the capture of an enemy figure is carried out by “pinching” it into “tongs” from two sides. It is quite possible that other “clamping” games, such as Hnefatafl, originated from this game.



The method of taking "clamp in pincers" allows you to take several enemy figures at once (up to three figures, in different directions), but this is not the only possibility of "increasing productivity". In the Tibetan game " Min Mang " it is allowed to take several enemy pieces at once, lined up, "closing" the line with their own figures on both sides. Taken pieces "change color", just as it does in Reversi .



Some further regional variations of Hasami Shogi go even further. The following video shows how a “compact” group of figures located in the corner of the board can be taken. Frankly, I still find it difficult to formalize these rules. For example, from the explanation it is not clear how to take the pieces at the edge of the board:



The idea of ​​the "connectedness" of the figures reaches its highest development in another ancient game, Go . This game is based on the concept of a "group" of stones. Stones located on adjacent points of the board (vertically or horizontally) form a single group. The group must be adjacent to not captured points of the board ( dame ), otherwise, it “dies” and is completely removed from the board. Surprisingly, such simple rules lead to an incredible variety of tactical combinations.



Go - not the only game that uses the idea of ​​"connectivity". In the game " Ordo ", for example, players pursue two goals: a breakthrough to the opposite side of the board and the preservation of the "order" of their pieces. Unlike Go, the figures are considered to be connected not only in orthogonal, but also in diagonal directions. The moves "tearing" a single group of figures are not allowed. If the group is broken, as a result of the attack of the enemy, its integrity must be restored in the next move (otherwise, the player is defeated). In the video version of this game, allowing the movement of groups of figures connected diagonally:



Of course, this is not the limit of where the inflamed fantasy of the inventor of board games can lead. Connecting figures, it is not necessary to be limited to adjacent cells. In the "war" game of Guy Deborah " Krigshpil ", straight lines from "Arsenals" and "Transmitters" symbolize the supply lines. Having lost contact with such a line (either directly or through a nearby figure), the figure “freezes”, losing the opportunity to move, until contact is restored. I do not know how anyone, but it reminds me a lot of the “energy network” of the Starcraft protoss.



The simplicity of the formulation of Guo rules is deceptive. Their correct implementation, in the language of ZRF , is as verbose as it is obscure. I will give, as an example, a fragment of the implementation of " Stoical Go ":

A lot of incomprehensible code
(define adjacent-to (or (position-flag? $1 n) (position-flag? $1 s) (position-flag? $1 e) (position-flag? $1 w) ) ) (define set-danger-flag (if (and (enemy? $1) (not-neutral? $1) (not-position-flag? safe $1)) (set-position-flag danger true $1) (set-flag Changed true) ) ) (define stone (name Stone) (image Black "images\Stoical Go\pieces\b$1.bmp" White "images\Stoical Go\pieces\w$1.bmp" ) (attribute makes-capture false) (drops ( (verify empty?) (verify (not-position? end)) (set-flag Capturing false) ; if next to enemy (if (or (and (enemy? n) (not-neutral? n) ) (and (enemy? s) (not-neutral? s) ) (and (enemy? e) (not-neutral? e) ) (and (enemy? w) (not-neutral? w) ) ) mark ; *** Initialize safe ; for each point ; if enemy ; if next to empty ; P[safe] = true a1 (while (not-position? end) (set-position-flag safe empty?) next ) back (set-position-flag safe false) a1 (while (not-position? end) (if (and enemy? not-neutral? (adjacent-to safe) ) (set-position-flag safe true) ) next ) ; *** Initialize danger ; for each adjacent ; if enemy ; P[danger] = true back (set-flag Changed false) (set-danger-flag n) (set-danger-flag s) (set-danger-flag e) (set-danger-flag w) (if (flag? Changed) ; *** Spread danger, safe ; Changed = true ; while Changed ; Changed = false ; for each point ; if enemy ; if !P[safe] ; if any adjacent is enemy with P[safe] ; P[safe] = true ; if !P[safe] and !P[danger] ; if any adjacent is enemy with P[danger] ; P[danger] = true ; Changed = true (while (flag? Changed) (set-flag Changed false) a1 (while (not-position? end) (if (and enemy? not-neutral?) (if (and (not-position-flag? safe) (adjacent-to safe)) (set-position-flag safe true) (set-flag Changed true) ) (if (and (not-position-flag? safe) (not-position-flag? danger) (adjacent-to danger) ) (set-position-flag danger true) (set-flag Changed true) ) ) next ) ) ; *** Add captures for stones ; for each point ; if P[danger] and !P[safe] ; capture a1 (while (not-position? end) (if (and (position-flag? danger) (not-position-flag? safe)) capture (set-flag Capturing true) ) next ) back ) ; if Changed ) ; if next to enemy ;!!!!!!! Find out if suicide ; if no captures (if (and (not-flag? Capturing) (not (or (empty? n) (empty? s) (empty? e) (empty? w) ) ) ) ; *** Initialize safe ; for each point ; P[safe] = empty and not-marked a1 (while (not-position? end) (set-position-flag safe empty?) next ) back (set-position-flag safe false) ; Changed = true ; while Changed and not adjacent to safe ; Changed = false ; for each point ; if friend ; if !P[safe] ; if any adjacent is friend with P[safe] ; P[safe] = true ; Changed = true (set-flag Valid (adjacent-to safe)) (set-flag Changed true) (while (and (not-flag? Valid) (flag? Changed) ) (set-flag Changed false) a1 (while (not-position? end) (if (and friend? (not-position-flag? safe) ) (if (adjacent-to safe) (set-position-flag safe true) (set-flag Changed true) ) ) next ) back (set-flag Valid (adjacent-to safe)) ) ; *** Add if not suicide ; verify next to safe square back (verify (flag? Valid)) ) ; if no captures ; *** Add stone (if (flag? Capturing) (go last-to) (if (piece? CapturingStone) (verify friend?) (change-type Stone) ) was-a-capture (change-type yes) back (add CapturingStone) else was-a-capture (if (piece? yes) (change-type no) (go last-to) (change-type Stone) ) back add ) ) ) ; drops ) 


Even with comments, it is extremely difficult to understand this (it is even more difficult to find errors in the code). With the appearance of arrays in Axiom , the situation has improved somewhat (as much as possible, when using the ForthScript language). Here is a snippet of code that checks the connectivity of groups from my Ordo implementation:

Slightly more concise, but no less mysterious.
 20 CONSTANT LS 10 CONSTANT SS LS [] list[] VARIABLE list-size SS [] set[] VARIABLE set-size VARIABLE curr-pos : not-in-list? ( pos - ? ) curr-pos ! TRUE list-size @ BEGIN 1- DUP 0 >= IF DUP list[] @ curr-pos @ = IF 2DROP FALSE 0 ENDIF ENDIF DUP 0> NOT UNTIL DROP ; : not-in-set? ( pos - ? ) curr-pos ! TRUE set-size @ BEGIN 1- DUP 0 >= IF DUP set[] @ curr-pos @ = IF 2DROP FALSE 0 ENDIF ENDIF DUP 0> NOT UNTIL DROP ; : add-position ( -- ) list-size @ LS < IF here not-in-list? IF here list-size @ list[] ! list-size ++ ENDIF ENDIF ; : not-from? ( pos -- ? ) DUP from <> SWAP not-in-set? AND ; : check-dir ( 'dir -- ) EXECUTE here not-from? AND friend? AND IF add-position ENDIF ; : check-coherence ( -- ? ) here 0 list[] @ 0 BEGIN DUP list[] @ DUP to ['] n check-dir DUP to ['] s check-dir DUP to ['] w check-dir DUP to ['] e check-dir DUP to ['] nw check-dir DUP to ['] sw check-dir DUP to ['] ne check-dir to ['] se check-dir 1+ DUP list-size @ >= UNTIL 2DROP to TRUE SIZE BEGIN 1- DUP 0 >= IF DUP not-from? IF DUP from <> OVER friend-at? AND IF DUP not-in-list? IF 2DROP FALSE 0 ENDIF ENDIF ENDIF ENDIF DUP 0> NOT UNTIL DROP 0 list-size ! ; 


In any case, now the whole board is not visible, but only a group of connected figures, which has a very beneficial effect on performance. The algorithm for constructing a connected group requires a queue that allows you to add elements “to the tail” without stopping the search started “from the head”. Having reached the elements added during processing, the looping cycle should process them as well as all previous elements. This is how this algorithm should look like “in a new design”:

Dagaz connectivity check
 (define add-piece-neighbors (foreach current-group (all (if (any nsew nw sw ne se) (check is-friend?) (if (not (piece-contains current-group)) (take-piece current-group) ) ) ) ) ) (define check-coherence (if (exists? any-position (check is-friend?) (take-piece current-group) add-piece-neighbors ) (check (not (exists? any-position (check is-friend?) (check (not (piece-contains current-group))) ) ) ) ) ) 


After the two previous listings, it may be hard to believe, but there is everything you need to solve the problem. Select any friendly shape, add to the set of its neighbors, then the neighbors of its neighbors, and so on, until the neighbors run out. If at the end of this procedure at least one friendly figure remains that does not belong to the constructed set, the invariant is broken. It is a pity that in ZoG and Axiom it is impossible to solve this problem as simply.

Source: https://habr.com/ru/post/256701/


All Articles