📜 ⬆️ ⬇️

Dagaz: Kicks to common sense (part 8)

image - To begin with, you have to understand the main thing ...
- What is the main thing?
- There is no spoon!

" Matrix "


As I have said many times before , it is simply impossible to implement some things in Zillions of Games . However, if you can not, but really want, then sometimes it is still possible. How far can you go this way?

3. All deception


We have already encountered this. ZoG does not allow to determine the moves, limited to the removal of pieces from the board? No problem - let's create a move that drops a piece onto the board and immediately deletes it (as a result, the piece located on the target field will be deleted automatically). In this way, you can create "buttons", expanding the ZoG interface capabilities (although, in fact, no these are not buttons, but simply special pieces on the board). Does ZoG limit board dimension to five dimensions? Too no trouble!
')
Create the missing positions and manually link them.
(define 6D (image "images\6DChess\6DChess.bmp") (grid (start-rectangle 34 7 76 53) (dimensions ; 2x2x2x2x2 ("Zii/Zi" (0 148)) ; 5D ("A/B" (162 0)) ; 4D ("II/I" (0 68)) ; 3D ("a/b" (66 0)) ; columns ("2/1" (31 19))) ; rows offset 31 (directions (n 0 0 0 0 -1) (s 0 0 0 0 1) (e 0 0 0 1 0) (w 0 0 0 -1 0) (u 0 0 -1 0 0) (d 0 0 1 0 0) (4e 0 1 0 0 0) (4w 0 -1 0 0 0) (5u -1 0 0 0 0) (5d 1 0 0 0 0))) (positions ; 6D (YiAIa1 413 241 445 287) (YiAIa2 383 223 415 269) (YiAIb1 477 241 509 287) (YiAIb2 448 223 480 269) (YiAIIa1 413 175 445 221) (YiAIIa2 383 155 415 201) (YiAIIb1 477 175 509 221) (YiAIIb2 448 155 480 201) (YiBIa1 577 241 609 287) (YiBIa2 547 223 579 269) (YiBIb1 641 241 673 287) (YiBIb2 609 223 642 269) (YiBIIa1 577 175 609 221) (YiBIIa2 547 155 579 201) (YiBIIb1 641 175 673 221) (YiBIIb2 609 155 642 201) (YiiAIa1 413 95 445 141) (YiiAIa2 383 76 415 122) (YiiAIb1 477 95 509 141) (YiiAIb2 448 76 480 122) (YiiAIIa1 413 26 445 72) (YiiAIIa2 383 7 415 53) (YiiAIIb1 477 26 509 72) (YiiAIIb2 448 7 480 53) (YiiBIa1 577 95 609 141) (YiiBIa2 547 76 579 122) (YiiBIb1 641 95 673 141) (YiiBIb2 609 76 642 122) (YiiBIIa1 577 26 609 72) (YiiBIIa2 547 8 579 54) (YiiBIIb1 641 26 673 72) (YiiBIIb2 609 8 642 54) ) (links n (YiAIa1 YiAIa2) (YiAIb1 YiAIb2) (YiAIIa1 YiAIIa2) (YiAIIb1 YiAIIb2) (YiBIa1 YiBIa2) (YiBIb1 YiBIb2) (YiBIIa1 YiBIIa2) (YiBIIb1 YiBIIb2) (YiiAIa1 YiiAIa2) (YiiAIb1 YiiAIb2) (YiiAIIa1 YiiAIIa2) (YiiAIIb1 YiiAIIb2) (YiiBIa1 YiiBIa2) (YiiBIb1 YiiBIb2) (YiiBIIa1 YiiBIIa2) (YiiBIIb1 YiiBIIb2)) (links s (YiAIa2 YiAIa1) (YiAIb2 YiAIb1) (YiAIIa2 YiAIIa1) (YiAIIb2 YiAIIb1) (YiBIa2 YiBIa1) (YiBIb2 YiBIb1) (YiBIIa2 YiBIIa1) (YiBIIb2 YiBIIb1) (YiiAIa2 YiiAIa1) (YiiAIb2 YiiAIb1) (YiiAIIa2 YiiAIIa1) (YiiAIIb2 YiiAIIb1) (YiiBIa2 YiiBIa1) (YiiBIb2 YiiBIb1) (YiiBIIa2 YiiBIIa1) (YiiBIIb2 YiiBIIb1)) (links e (YiAIa1 YiAIb1) (YiAIa2 YiAIb2) (YiAIIa1 YiAIIb1) (YiAIIa2 YiAIIb2) (YiBIa1 YiBIb1) (YiBIa2 YiBIb2) (YiBIIa1 YiBIIb1) (YiBIIa2 YiBIIb2) (YiiAIa1 YiiAIb1) (YiiAIa2 YiiAIb2) (YiiAIIa1 YiiAIIb1) (YiiAIIa2 YiiAIIb2) (YiiBIa1 YiiBIb1) (YiiBIa2 YiiBIb2) (YiiBIIa1 YiiBIIb1) (YiiBIIa2 YiiBIIb2)) (links w (YiAIb1 YiAIa1) (YiAIb2 YiAIa2) (YiAIIb1 YiAIIa1) (YiAIIb2 YiAIIa2) (YiBIb1 YiBIa1) (YiBIb2 YiBIa2) (YiBIIb1 YiBIIa1) (YiBIIb2 YiBIIa2) (YiiAIb1 YiiAIa1) (YiiAIb2 YiiAIa2) (YiiAIIb1 YiiAIIa1) (YiiAIIb2 YiiAIIa2) (YiiBIb1 YiiBIa1) (YiiBIb2 YiiBIa2) (YiiBIIb1 YiiBIIa1) (YiiBIIb2 YiiBIIa2)) (links u (YiAIa1 YiAIIa1) (YiAIa2 YiAIIa2) (YiAIb1 YiAIIb1) (YiAIb2 YiAIIb2) (YiBIa1 YiBIIa1) (YiBIa2 YiBIIa2) (YiBIb1 YiBIIb1) (YiBIb2 YiBIIb2) (YiiAIa1 YiiAIIa1) (YiiAIa2 YiiAIIa2) (YiiAIb1 YiiAIIb1) (YiiAIb2 YiiAIIb2) (YiiBIa1 YiiBIIa1) (YiiBIa2 YiiBIIa2) (YiiBIb1 YiiBIIb1) (YiiBIb2 YiiBIIb2)) (links d (YiAIIa1 YiAIa1) (YiAIIa2 YiAIa2) (YiAIIb1 YiAIb1) (YiAIIb2 YiAIb2) (YiBIIa1 YiBIa1) (YiBIIa2 YiBIa2) (YiBIIb1 YiBIb1) (YiBIIb2 YiBIb2) (YiiAIIa1 YiiAIa1) (YiiAIIa2 YiiAIa2) (YiiAIIb1 YiiAIb1) (YiiAIIb2 YiiAIb2) (YiiBIIa1 YiiBIa1) (YiiBIIa2 YiiBIa2) (YiiBIIb1 YiiBIb1) (YiiBIIb2 YiiBIb2)) (links 4e (YiAIa1 YiBIa1) (YiAIa2 YiBIa2) (YiAIb1 YiBIb1) (YiAIb2 YiBIb2) (YiAIIa1 YiBIIa1) (YiAIIa2 YiBIIa2) (YiAIIb1 YiBIIb1) (YiAIIb2 YiBIIb2) (YiiAIa1 YiiBIa1) (YiiAIa2 YiiBIa2) (YiiAIb1 YiiBIb1) (YiiAIb2 YiiBIb2) (YiiAIIa1 YiiBIIa1) (YiiAIIa2 YiiBIIa2) (YiiAIIb1 YiiBIIb1) (YiiAIIb2 YiiBIIb2)) (links 4w (YiBIa1 YiAIa1) (YiBIa2 YiAIa2) (YiBIb1 YiAIb1) (YiBIb2 YiAIb2) (YiBIIa1 YiAIIa1) (YiBIIa2 YiAIIa2) (YiBIIb1 YiAIIb1) (YiBIIb2 YiAIIb2) (YiiBIa1 YiiAIa1) (YiiBIa2 YiiAIa2) (YiiBIb1 YiiAIb1) (YiiBIb2 YiiAIb2) (YiiBIIa1 YiiAIIa1) (YiiBIIa2 YiiAIIa2) (YiiBIIb1 YiiAIIb1) (YiiBIIb2 YiiAIIb2)) (links 5u (YiAIa1 YiiAIa1) (YiAIa2 YiiAIa2) (YiAIb1 YiiAIb1) (YiAIb2 YiiAIb2) (YiAIIa1 YiiAIIa1) (YiAIIa2 YiiAIIa2) (YiAIIb1 YiiAIIb1) (YiAIIb2 YiiAIIb2) (YiBIa1 YiiBIa1) (YiBIa2 YiiBIa2) (YiBIb1 YiiBIb1) (YiBIb2 YiiBIb2) (YiBIIa1 YiiBIIa1) (YiBIIa2 YiiBIIa2) (YiBIIb1 YiiBIIb1) (YiBIIb2 YiiBIIb2)) (links 5d (YiiAIa1 YiAIa1) (YiiAIa2 YiAIa2) (YiiAIb1 YiAIb1) (YiiAIb2 YiAIb2) (YiiAIIa1 YiAIIa1) (YiiAIIa2 YiAIIa2) (YiiAIIb1 YiAIIb1) (YiiAIIb2 YiAIIb2) (YiiBIa1 YiBIa1) (YiiBIa2 YiBIa2) (YiiBIb1 YiBIb1) (YiiBIb2 YiBIb2) (YiiBIIa1 YiBIIa1) (YiiBIIa2 YiBIIa2) (YiiBIIb1 YiBIIb1) (YiiBIIb2 YiBIIb2)) (links 6e (ZiAIa1 YiAIa1) (ZiAIa2 YiAIa2) (ZiAIb1 YiAIb1) (ZiAIb2 YiAIb2) (ZiAIIa1 YiAIIa1) (ZiAIIa2 YiAIIa2) (ZiAIIb1 YiAIIb1) (ZiAIIb2 YiAIIb2) (ZiBIa1 YiBIa1) (ZiBIa2 YiBIa2) (ZiBIb1 YiBIb1) (ZiBIb2 YiBIb2) (ZiBIIa1 YiBIIa1) (ZiBIIa2 YiBIIa2) (ZiBIIb1 YiBIIb1) (ZiBIIb2 YiBIIb2) (ZiiAIa1 YiiAIa1) (ZiiAIa2 YiiAIa2) (ZiiAIb1 YiiAIb1) (ZiiAIb2 YiiAIb2) (ZiiAIIa1 YiiAIIa1) (ZiiAIIa2 YiiAIIa2) (ZiiAIIb1 YiiAIIb1) (ZiiAIIb2 YiiAIIb2) (ZiiBIa1 YiiBIa1) (ZiiBIa2 YiiBIa2) (ZiiBIb1 YiiBIb1) (ZiiBIb2 YiiBIb2) (ZiiBIIa1 YiiBIIa1) (ZiiBIIa2 YiiBIIa2) (ZiiBIIb1 YiiBIIb1) (ZiiBIIb2 YiiBIIb2)) (links 6w (YiAIa1 ZiAIa1) (YiAIa2 ZiAIa2) (YiAIb1 ZiAIb1) (YiAIb2 ZiAIb2) (YiAIIa1 ZiAIIa1) (YiAIIa2 ZiAIIa2) (YiAIIb1 ZiAIIb1) (YiAIIb2 ZiAIIb2) (YiBIa1 ZiBIa1) (YiBIa2 ZiBIa2) (YiBIb1 ZiBIb1) (YiBIb2 ZiBIb2) (YiBIIa1 ZiBIIa1) (YiBIIa2 ZiBIIa2) (YiBIIb1 ZiBIIb1) (YiBIIb2 ZiBIIb2) (YiiAIa1 ZiiAIa1) (YiiAIa2 ZiiAIa2) (YiiAIb1 ZiiAIb1) (YiiAIb2 ZiiAIb2) (YiiAIIa1 ZiiAIIa1) (YiiAIIa2 ZiiAIIa2) (YiiAIIb1 ZiiAIIb1) (YiiAIIb2 ZiiAIIb2) (YiiBIa1 ZiiBIa1) (YiiBIa2 ZiiBIa2) (YiiBIb1 ZiiBIb1) (YiiBIb2 ZiiBIb2) (YiiBIIa1 ZiiBIIa1) (YiiBIIa2 ZiiBIIa2) (YiiBIIb1 ZiiBIIb1) (YiiBIIb2 ZiiBIIb2)) (symmetry Black (ns) (sn) (ud) (du) (4e 4w) (4w 4e) (5u 5d) (5d 5u) (6e 6w) (6w 6e)) (zone (name promotion-zone) (players White) (positions YiiAIIa2 YiiAIIb2 YiiBIIa2 YiiBIIb2)) (zone (name promotion-zone) (players Black) (positions ZiAIa1 ZiAIb1 ZiBIa1 ZiBIb1)) ) 


Looks scary? But it works !



A little cheating, you can define the hexagonal boards:



It's all the same two-dimensional grid whose rows are shifted relative to each other.
 (define Board-Definitions (image "Images\6Chess.bmp") (grid (start-rectangle 21 -79 69 -31) (dimensions ("a/b/c/d/e/f/g/h/i" (38 22)) ; files ("10/9/8/7/6/5/4/3/2/1" (0 44)) ; ranks ) (directions (z0 0 -1) (z1 1 -2) (z2 1 -1) (z3 2 -1) (z4 1 0) (z5 1 1) (z6 0 1) (z7 -1 2) (z8 -1 1) (z9 -2 1) (zx -1 0) (zy -1 -1) ) ) (kill-positions a7 a8 a9 a10 b8 b9 b10 c9 c10 d10 f1 g1 g2 h1 h2 h3 i1 i2 i3 i4) (symmetry Black (z0 z6)(z6 z0) (z1 z7)(z7 z1) (z2 z8)(z8 z2) (z3 z9)(z9 z3) (zx z4)(z4 zx) (zy z5)(z5 zy) ) (zone (name promotion-zone) (players White) (positions a6 b7 c8 d9 e10 f10 g10 h10 i10) ) (zone (name promotion-zone) (players Black) (positions a1 b1 c1 d1 e1 f2 g3 h4 i5) ) (zone (name fast-through) (players White) (positions b3 c3 d3 e3 f4 g5 h6) ) (zone (name fast-through) (players Black) (positions b5 c6 d7 e8 f8 g8 h8) ) (zone (name faster-through) (players White) (positions d4 e4 f5) ) (zone (name faster-through) (players Black) (positions d6 e7 f7) ) ) 


You can move parts of the board, along with the figures on them!



It is really easy.

In fact, there are two boards
  (board (image "Images\PlatformChess\Void8x8.bmp") (grid (start-rectangle 10 10 48 48) (dimensions ("a/b/c/d/e/f/g/h" (49 0)) ; files ("8/7/6/5/4/3/2/1" (0 49)) ; ranks ) (directions (n 0 -1) (e 1 0) (s 0 1) (w -1 0) (ne 1 -1) (nw -1 -1) (se 1 1) (sw -1 1) ) ) (grid (start-rectangle 5 5 103 103) (dimensions ("A/B/C/D" (98 0)) ; grid files ("4/3/2/1" (0 98)) ;grid ranks ) (directions (n 0 -1) (e 1 0) (w -1 0) (s 0 1))) (links up (A1 a2) (A2 a4) (A3 a6) (A4 a8) (B1 c2) (B2 c4) (B3 c6) (B4 c8) (C1 e2) (C2 e4) (C3 e6) (C4 e8) (D1 g2) (D2 g4) (D3 g6) (D4 g8)) (links down (a1 A1) (a2 A1) (b1 A1) (b2 A1) (a3 A2) (a4 A2) (b3 A2) (b4 A2) (a5 A3) (a6 A3) (b5 A3) (b6 A3) (a7 A4) (a8 A4) (b7 A4) (b8 A4) (c1 B1) (c2 B1) (d1 B1) (d2 B1) (c3 B2) (c4 B2) (d3 B2) (d4 B2) (c5 B3) (c6 B3) (d5 B3) (d6 B3) (c7 B4) (c8 B4) (d7 B4) (d8 B4) (e1 C1) (e2 C1) (f1 C1) (f2 C1) (e3 C2) (e4 C2) (f3 C2) (f4 C2) (e5 C3) (e6 C3) (f5 C3) (f6 C3) (e7 C4) (e8 C4) (f7 C4) (f8 C4) (g1 D1) (g2 D1) (h1 D1) (h2 D1) (g3 D2) (g4 D2) (h3 D2) (h4 D2) (g5 D3) (g6 D3) (h5 D3) (h6 D3) (g7 D4) (g8 D4) (h7 D4) (h8 D4) ) (symmetry Black (ns) (sn) (ne se) (se ne) (nw sw) (sw nw)) (zone (name promotion-zone) (players White) (positions a8 b8 c8 d8 e8 f8 g8 h8) ) (zone (name promotion-zone) (players Black) (positions a1 b1 c1 d1 e1 f1 g1 h1) ) (zone (name enemy-promotion-zone) (players Black) (positions a8 b8 c8 d8 e8 f8 g8 h8) ) (zone (name enemy-promotion-zone) (players White) (positions a1 b1 c1 d1 e1 f1 g1 h1) ) (zone (name third-rank) (players White) (positions a3 b3 c3 d3 e3 f3 g3 h3 a2 b2 c2 d2 e2 f2 g2 h2) ) (zone (name third-rank) (players Black) (positions a6 b6 c6 d6 e6 f6 g6 h6 a7 b7 c7 d7 e7 f7 g7 h7) ) ) 


The traditional 8x8 board is combined with a 4x4 board, along which the “pieces of the board” - the platforms - move. Additional up and down directions help the figures to control the presence of “soil under their feet”. The most difficult is to ensure the synchronous movement of the figures together with the platforms.

Cascade and to operators come to the rescue.
 (define wplatform-move (mark $1 (verify empty?) to back up (if (and empty? (empty? e) (empty? s) (empty? se)) add else back up (if not-empty? cascade from $1 (if (and (in-zone? promotion-zone $1) (piece? Pawn (opposite $1)) (friend? (opposite $1))) $1 (change-type Queen) to else $1 to)) back up e (if not-empty? cascade from $1 (if (and (in-zone? promotion-zone $1) (piece? Pawn (opposite $1)) (friend? (opposite $1))) $1 (change-type Queen) to else $1 to)) back up s (if not-empty? cascade from $1 (if (and (in-zone? enemy-promotion-zone $1) (piece? Pawn (opposite $1)) (enemy? (opposite $1))) $1 (change-type Queen) to else $1 to)) back up se (if not-empty? cascade from $1 (if (and (in-zone? enemy-promotion-zone $1) (piece? Pawn (opposite $1)) (enemy? (opposite $1))) $1 (change-type Queen) to else $1 to)) add ) ) ) 


You might think that this is the limit of ZoG's capabilities, but look at this :


There is clearly something wrong here. The figures overlap each other! Does ZoG do that? Of course not! But who said that the figures must be whole? In this game, each “figure” is made up of four pieces, and the board is, of course, three-dimensional (but we see only its “upper plan”). The implementation is great. The only thing that can confuse is that in order to select any of the figures, it is necessary to indicate its upper left corner (this can be corrected, if desired).

You can go even further! From the moment I saw this book for the first time, I had a burning desire to make a board for Margo. Since I am a realist, I realize that I can hardly get AI ZoG to work with it correctly. Even for the classic implementation of Go on a two-dimensional board, ZoG needed an engine to play at the level of an average beginner. In Margo, with its “zombies”, “bridges” and “virtual groups”, it is still more difficult. The full game can be implemented in Axiom , but there the development of AI is a separate story. To begin with, I am completely satisfied with the board controlling the rules of the game, supporting the game of two people and the analysis of etudes. Start by defining the board:

Margo board
  (board (image "../images/margo/board.bmp") (grid (start-rectangle 30 30 59 59) (dimensions ("a/b/c/d/e/f/g/h/i/j/k/l/m/n" (30 0)) ; files ("14/13/12/11/10/9/8/7/6/5/4/3/2/1" (0 30)) ; ranks ("I/II/III/IV/V/VI/VII" (1600 0)) ;layers ) (directions (n 0 -1 0) (e 1 0 0) (s 0 1 0) (w -1 0 0) (nw -1 -1 0) (ne 1 -1 0) (sw -1 1 0) (se 1 1 0) (u 0 0 -1) (d 0 0 1) ) ) (zone (name im) (players R) (positions a1I) ) (zone (name im) (players B) (positions a2I) ) (zone (name empty-plane) (players RB) (positions a2I a4I a6I a8I a10I a12I a14I c2I c4I c6I c8I c10I c12I c14I e2I e4I e6I e8I e10I e12I e14I g2I g4I g6I g8I g10I g12I g14I i2I i4I i6I i8I i10I i12I i14I k2I k4I k6I k8I k10I k12I k14I m2I m4I m6I m8I m10I m12I m14I ) ) (zone (name plane) (players RB) (positions a1I a2I a3I a4I a5I a6I a7I a8I a9I a10I a11I a12I a13I a14I b1I b2I b3I b4I b5I b6I b7I b8I b9I b10I b11I b12I b13I b14I c1I c2I c3I c4I c5I c6I c7I c8I c9I c10I c11I c12I c13I c14I d1I d2I d3I d4I d5I d6I d7I d8I d9I d10I d11I d12I d13I d14I e1I e2I e3I e4I e5I e6I e7I e8I e9I e10I e11I e12I e13I e14I f1I f2I f3I f4I f5I f6I f7I f8I f9I f10I f11I f12I f13I f14I g1I g2I g3I g4I g5I g6I g7I g8I g9I g10I g11I g12I g13I g14I h1I h2I h3I h4I h5I h6I h7I h8I h9I h10I h11I h12I h13I h14I i1I i2I i3I i4I i5I i6I i7I i8I i9I i10I i11I i12I i13I i14I j1I j2I j3I j4I j5I j6I j7I j8I j9I j10I j11I j12I j13I j14I k1I k2I k3I k4I k5I k6I k7I k8I k9I k10I k11I k12I k13I k14I l1I l2I l3I l4I l5I l6I l7I l8I l9I l10I l11I l12I l13I l14I m1I m2I m3I m4I m5I m6I m7I m8I m9I m10I m11I m12I m13I m14I n1I n2I n3I n4I n5I n6I n7I n8I n9I n10I n11I n12I n13I n14I ) ) ) 


Taking the definition of the “Mahjong” board, I changed the graphic resources and the size of the board (to get a 7x7 board, you must define a grid of 14x14 tiles, with support for 7 layers). Here you should pay attention to the definition of gaming areas. First, it is necessary to define the “top plan” - the plane zone in which all visible tiles will be located. Only in this zone is it possible to add new figures and the removal of them should begin with it. Further, the creation of figures on an empty board may not anywhere. The empty-plan zone defines the possible location of their left upper tiles.

As for the definition of the zone, “ im ” is a funny trick that will allow you to further determine whether a piece belongs to a player (and not just their friendliness or hostility). This macro will be used to obtain complete information about the tile located at the current position (unfortunately, it is impossible to implement a similar functionality in the ZRF in any clearer way):

Getting tile information
 (define get-piece (set-flag is-piece? false) (set-flag is-black? false) (set-flag is-left? false) (set-flag is-top? false) (if not-empty? (set-flag is-piece? true) (if (and enemy? (in-zone? im a1I)) (set-flag is-black? true) ) (if (and friend? (in-zone? im a2I)) (set-flag is-black? true) ) (if (or (piece? tnw) (piece? tne)) (set-flag is-top? true) ) (if (or (piece? tnw) (piece? tsw)) (set-flag is-left? true) ) ) ) 


The task of placing a figure (four tiles) on an empty board is solved trivially. The only technical difficulty is that the move begins by resetting another special piece (not a tile), since this is the only piece that can be dropped to any field. At the point of discharge, it must be replaced with the corresponding tile (this is almost the same as what was done in “Huffing Checkers” in the previous article). The remaining tiles are simply created in the adjacent fields (since the move can start from any tile, 4 possible moves must be defined):

Move to the empty board
 (define pre-check-3 (verify (on-board? $1)) (verify (on-board? $2)) (verify (in-zone? $3)) ) (define pre-check-4 (verify (on-board? $1)) (verify (on-board? $2)) (verify (in-zone? $3 $4)) ) (define check-e (verify empty?) (verify (empty? $1)) (verify (empty? $2)) (verify (empty? $3)) ) (define post-action (create t-$1) (create t-$2 $2) (create t-$3 $4) (create t-$5 $6) add ) (define de-nw ( (pre-check-3 es empty-plane) (check-e es se) (post-action nw se ne e sw s) )) (define de-ne ( (pre-check-4 ws empty-plane w) (check-e ws sw) (post-action ne sw nw w se s) )) (define de-se ( (pre-check-4 wn empty-plane nw) (check-e nw nw) (post-action se nw ne n sw w) )) (define de-sw ( (pre-check-4 en empty-plane n) (check-e en ne) (post-action sw ne nw n se e) )) (define tile (name $1$2) (image G "../images/margo/w$1$2.bmp" R "../images/margo/b$1$2.bmp") (attribute is-ko? false) ) (piece (tile t nw) ) (piece (tile t ne) ) (piece (tile t sw) ) (piece (tile t se) ) (piece (name M) (image R "../images/margo/m.bmp" B "../images/margo/m.bmp") (drops (de-nw) (de-ne) (de-se) (de-sw) ) ) 


A move that builds a "pyramid" is more complicated. It is necessary to make sure that all four tiles on which the new figure is placed have the required type and the depth below them is the same. Further, before placing a piece on the board in the upper (visible) layer, it is necessary to transfer the tiles previously placed there to deeper layers. Initially, I chose a not entirely successful solution, using layers from II to VII as a “stack”, from top to bottom:

Building the pyramids
 (define check-p (verify (piece? t-$1)) (verify (piece? t-$2 $3)) (verify (piece? t-$4 $5)) (verify (piece? t-$6 $7)) ) (define check-d mark u (while not-empty? (verify (not-empty? $1)) (verify (not-empty? $2)) (verify (not-empty? $1$2)) u ) (verify (empty? $1)) (verify (empty? $2)) (verify (empty? $1$2)) back ) (define dp-nw ( (pre-check-3 es plane) (check-p se sw e nw se ne s) (check-d se) (pre-action se) (post-action nw se ne e sw s) )) (define dp-ne ( (pre-check-4 ws plane w) (check-p sw se w nw s ne sw) (check-d sw) (pre-action sw) (post-action ne sw nw w se s) )) (define dp-se ( (pre-check-4 wn plane nw) (check-p nw sw n ne w se nw) (check-d nw) (pre-action nw) (post-action se nw ne n sw w) )) (define dp-sw ( (pre-check-4 en plane n) (check-p ne nw e se n sw ne) (check-d ne) (pre-action ne) (post-action sw ne nw n se e) )) (piece (name M) (image R "../images/margo/m.bmp" B "../images/margo/m.bmp") (drops (de-nw) (dp-nw) (de-ne) (dp-ne) (de-se) (dp-se) (de-sw) (dp-sw) ) ) 


Subsequently, it became clear that it is much more convenient to keep all the tiles of one shape (except the visible ones) in one layer. The stack had to be " turned over " (for this it was necessary to create an additional direction connecting the first layer with the seventh). The next step was removal. The algorithms for removing figures, in connection with their “death” in Go (and even more so in Margo) are very complex. I decided to start with a simple one - removing any shape with a simple mouse click. Of course, in order for the whole structure not to fall apart, it is also necessary to remove all the figures “relying” on the removed one (directly or indirectly) by the same move. In itself, the removal of marked tiles is fairly obvious.

Group tile removal
 (define clean-piece (set-flag is-piece? false) d (while empty? d) (while (and not-empty? (position-flag? is-dead?)) capture d ) (if not-empty? (get-piece) capture ) (while (not-in-zone? plane) u) (if (flag? is-piece?) (add-piece) else capture ) ) (define clean-pieces mark a0 (while (on-board? next) next (if (and not-empty? (position-flag? is-dead?)) (if (empty? b) capture else (clean-piece) ) ) ) back ) 


In the main clean-pieces cycle, all top-level tiles are viewed. If one of them is marked for deletion, the tiles are checked directly below it, in the lower layers. Everything marked for deletion is deleted, and the first unmarked tile moves up to the first layer. Positional flags are used for marking, which allow to associate a Boolean value with an arbitrary position. It remains to figure out how to mark tiles for deletion.

Marking tiles for removal
 (define check-top (verify (on-board? $1)) (if (and (not-empty? $1) (not-position-flag? is-dead? $1) (not-position-flag? is-current? $1)) $1 (set-position-flag is-current? true) (if (not-piece? t$3) d (while (and empty? (on-board? d)) d) (verify not-empty?) (if (and not-empty? (not-position-flag? is-dead?) (not-position-flag? is-current?)) (set-position-flag is-current? true) ) (while (not-in-zone? plane) u) ) $2 ) ) (define check-deep (verify (on-board? $1)) (if (and (not-empty? $1) (not-position-flag? is-dead? $1) (not-position-flag? is-current? $1)) $1 (set-position-flag is-current? true) (verify (on-board? u)) (if (and (not-empty? u) (not-position-flag? is-dead? u) (not-position-flag? is-current? u)) u (set-position-flag is-current? true) d ) $2 ) ) (define proceed-current (set-position-flag is-dead? true) (set-position-flag is-current? false) (get-piece) (if (in-zone? plane) (if (flag? is-left?) (if (flag? is-top?) (check-top ew ne) (check-top sn sw) (check-top se nw se) else (check-top ew se) (check-top ns nw) (check-top ne sw ne) ) else (if (flag? is-top?) (check-top we nw) (check-top sn se) (check-top sw ne sw) else (check-top we sw) (check-top ns ne) (check-top nw se nw) ) ) else (if (flag? is-left?) (if (flag? is-top?) (check-deep ew) (check-deep sn) (check-deep se nw) else (check-deep ew) (check-deep ns) (check-deep ne sw) ) else (if (flag? is-top?) (check-deep we) (check-deep sn) (check-deep sw ne) else (check-deep we) (check-deep ns) (check-deep nw se) ) ) ) ) (define proceed-all (set-flag is-done? false) (while (not-flag? is-done?) (set-flag is-done? true) mark a0 (while (on-board? next-all) next-all (if (position-flag? is-current?) (set-flag is-done? false) (proceed-current) ) ) back ) ) (define dp-clear ( (verify not-empty?) (set-position-flag is-current? true) (proceed-all) (clean-pieces) add )) ... (piece (name M) (image G "../images/margo/m.bmp" R "../images/margo/m.bmp") (drops (de-nw) (dp-nw) (de-ne) (dp-ne) (de-se) (dp-se) (de-sw) (dp-sw) (dp-clear) ) ) 


Here, it is important to understand that deletion always begins with visible tiles located in the first layer. Having set the initial mark in dp-clear , we perform proceed-current as long as there are new, not yet deleted tiles. This procedure itself performs the “distribution” of flags to neighboring tiles and does this in different ways, depending on whether the action takes place in the upper layer or in the depth.

In the first layer, the type of the adjacent tile is controlled and if it does not coincide with the expected one (this means that the figure is overlapped lying above), in addition to marking the tile of the overlapping figure, the flag extends in depth. On deeper layers, the shape tiles are always located in one layer. We simply spread the flag to neighboring tiles, and if there is something on top of them, pass it up as well. As a result, everything works as expected, but the picture itself looks something like this:



Well ... these are tiles. In order to take into account the color of the figure below, it will be necessary, having worked in a graphic editor, add two more types for each tile and complicate the code a little. In the end, all together will look like this .



Of course, in order to turn this piece into a full-fledged game “Margo”, I will have to work a lot more. Most likely, I still have to redo everything on the Axiom, and this in itself is a whole story. In Axiom there are no attributes of figures, play zones and positional flags, but, in terms of development (including AI), its capabilities are immeasurably superior to ZRF. In addition, the code in ForthScript can somehow debug. When (and if) I cope with all the difficulties, it will deserve a separate article, today I just wanted to show that with the help of ZRF you can do really amazing things. It is enough to show a little ingenuity and not be afraid (very much) to work with your hands.

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


All Articles