Nemoroth

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Nemoroth

Post by hgm »

If you get bored with normal chess, and are in for something more complex, consider the Game of Nemoroth. Although I am not sure it qualifies as a chess variant, it has some chess-like aspects. Such as an 8x8 board, and a similar composition of the armies (1 +1 + 2 + 2 + 2 + 8 pieces). Most pieces cannot capture, though, and can only move to empty squares. Instead they exert effects on nearby squares, often passively (i.e. the do not have to move to cause the effect, and it doesn't take a turn, but happens automatically, whether in their own turn or that of the opponent.

These are the pieces and their side effects:
Basilisk: passively petrifies any piece (friend or foe) on the squares it could move to had they been empty.
Ghast: cannot be approached to within a range of 2 king steps, and forces pieces already there to flee faway from it.
Leaf Pile: can capture pieces (friend or foe) on its destination, but then leaves a single Mummy when it moves away, as the digested remnants.
Go Away: can push all adjacent pieces (friend or foe) one square away from it. (This takes a turn.)
Wounded Fiend: pollutes squares it moves over or away from with 'ichor'.
Human: promotes to Zombi on reaching 8th rank.
Zombie: can capture (friend or foe) on its destination, and is immune to petrification or the effect of the Ghast. Contact with ichor destroys both the ichor and the Zombie.
Mummy: a completely passive obstacle.

Ichor is not a piece, (and thus cannot be pushed), but pieces other than Zombie are not allowed to move to squares polluted with it. Ichor evaporates spontaneously after 5 moves (10 turns). Like promotion, petrification is permanent. It means the pieces lose the ability to move actively. They still continue to exert their side effects, though.

Although only pieces that can capture may move to occupied squares (after which they still are the only occupant), pushing of pieces by a Go Away can lead to multiple occupants when non-capturing pieces are pushed. Pushing cannot be blocked, and pieces pushed over the board edge simply disappear. There sometimes is a difference between moving to a square or being pushed to it: a Zombie pushed onto a square does not destroy any other occupants the square might have, while a Zombie moving on its own accord would capture those. A Leaf Pile moving or pushed to a square with another Leaf Pile on it would capture the latter, other pieces pushed on a Leaf Pile are digested. Leave Piles cannot voluntarily move to squares containing Mummies or petrified pieces, but will still digest those when pushed together.

There is no royal piece, but there is something similar to check: players have the obligation to resolve illegal conditions such as multiple occupation of a square, pieces standing on ichor, or too close to a Ghast. It isn't necessary to address all existing problems at once, but you must resolve at least one of those. If you cannot, you are checkmated, and lose the game. If you have no legal moves you also lose. Pieces are not compelled to flee from a friendly Ghast, but they are still not allowed to make moves that bring them geometrically closer to it. It is forbidden to repeat a game state a 3rd time.

The moves of the various unpetrified pieces you can see in this diagram (open the table with the piece overview):

[diag]
promoChoice=Z
symmetry=mirror
royal=0
Human::fsmWfmF:Pawn:a2-h2
Wounded Fiend::mR:Rook:a1,h1
Leaf Pile::mcdK:Commoner:c1,f1
Go Away:A:mFmD:Canon:b1,g1
Ghast::mA:Elephant:d1
Basilisk::bmFfmN:Cobra:e1
Zombie::mcdK:Archbishop:
[/diag]
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Nemoroth

Post by hgm »

The more I think about it, the more I feel like building an AI for this game. In JavaScript. Some ideas for an efficient game-state representation:

Since one square can hold multiple pieces, one could use a 0x88 mailbox board containing 'piece sets'. Each bit in such a set would represent a piece, and be set to 1 if that piece is present. There are only 32 pieces, so a normal int should suffice. I am not sure that integer variables in JavaScript can always hold 32 bits, though. (I can imagine some bits are reserved to indicate the variable does hold an integer.) It is possible to economize on bits, however, since Leaf Piles (petrified or not) will never coexist with anything else. So there are only 28 pieces that can have to be represented together with others. One can use 1<<28 as a flag to indicate the square contains a Leaf Pile, and the 4 lower-most bits to indicate which one (of four), whether that is petrified, and whether it is digesting something (so that moving it will leaf behind a Mummy).

In combination with a piece list that holds the location of each piece, and whether it is petrified or promoted, this would make efficient lookup of pieces for a square, or the square for a piece possible. To loop over all pieces on a square to update their location in the piece list (e.g. when these are pushed by a Go Away) one could either access the indicated Leaf Pile or use bit extraction on a set of other pieces. By maintaining a mask that indicates which of the non-Leaf-Pile pieces in a piece set are petrified one can easily test whether a square is accessible to a Leaf Pile.

Keeping track of Ichor pollution seems a pain, as the Wounded Fiend (moving as Rook) could pollute up to 7 squares per turn, and you would have to keep track of its evaporation for 10 ply. But, assuming that searches will not go deeper than 20 ply, one could record the Ichor-deposition history of a square for 30 ply (10 from the game history + 20 from the search). You would need a 0x88 board of such 'Ichor histories'. Each bit in the history corresponds to a ply level in the search, and gets set when Ichor was deposited on the square during that ply. For a given ply in the search you can then test whether there currently is Ichor by testing with a mask where 10 consequtive bits for the most recent 10 ply are set. You only would have to update that mask on MakeMove(); the Ichor-deposition map itself would not require any updating.

Testing for 'compulsion' is simpler than testing for check in normal chess, as it mostly is a local. Downside is that all your pieces can be compelled, not just a royal one. But to test whether a piece is compelled you just have to look up whether its current square is polluted (in the Ichor-deposition map), whether it is multiply occupied (on the board) and what its distance to the enemy Ghast is. The latter could be done from a table indexed by square-number difference, where compulsions get value 1 (furthest from Ghast) to 5 (closest to Ghast). You could add 8 to that for Ichor compulsion, and 16 for multiple occupancy.

You would have to do that for all your non-petrified pieces before your move, and make a list of those (for which the result was non-zero). If the list is empty, any move flies. (It is assumed the move generator would not generate moves towards a Ghast or onto Ichor or occupied squares.) Otherwise you would have to retest the compelled pieces by running through the list, and repeating the compulsion test (in their new location) to see whether their compulsion is resolved. Which would be the case when (!newCompulsion || newCompulsion < (oldCompulsion & 7)). (I.e. only a more-distant Ghast compulsion is allowed to remain.) If there is no piece in the list of compelled pieces that satisfies this, the move is illegal.
User avatar
lithander
Posts: 915
Joined: Sun Dec 27, 2020 2:40 am
Location: Bremen, Germany
Full name: Thomas Jahn

Re: Nemoroth

Post by lithander »

Not sure if you've already found this? https://azgoroth.itch.io/nemoroth Seems to be in active development, even.
Minimal Chess (simple, open source, C#) - Youtube & Github
Leorik (competitive, in active development, C#) - Github & Lichess
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Nemoroth

Post by hgm »

Yes, I had seen it. In fact it was what triggered my interest; I thought it would be fun to have an opponent for it. And I wondered what kind of programming techniques would have to be used for making a search with such exotic rules fast.

But thanks for the link anyway. It is interesting to see in that implementation how multiple occupancy of squares is handled.

Some other tentative thoughts on an implementation:

If we want sets of pieces to be representable by ~30 bits in an int, we would have to deal with changes of piece type. These can happen when a Human promotes to Zombie, or when a piece gets digested to a Mummy. Since Mummies are totally inert there never is a reason to look up a Mummy's location through the piece list. They are encountered on the board to make squares that otherwise would be move destinations inaccessible. In fact all Mummies are the same, whether they resulted from digestion of white or black pieces. But since it would be annoying to make an exception in MakeMove() for updating the location in the piece list when a Mummie gets pushed, as would have to happen for all other piece types. So we could add a dummy 33rd element to the piece list, that would be updated on relocation or capture of any Mummy, but otherwise never used.

The piece list also specifies how each piece moves (as a pointer into an array of move steps). When a piece gets captured or petrified we could make this point to an empty list of move steps, so than no moves would be generated for that piece. If that was the only way to indicate petrification, it would be a bit cumbersome to figure out whether there is a petrified piece (blocking access to a Leaf Pile) on a multiply occupied square, though. This can conveniently done by including a dummy Mummy (;)) in the piece set for a square on which there is a petrified piece (which also blocks Leaf Piles).

The piece list could have white pieces in elements 0-15, and black pieces at index 17-32, and a Mummy at 16. The Leaf Piles would be the last two pieces for each player. Pieces would be represented in a piece set as 1<<pieceNr, except for Leaf Piles. This would then leave bits 14, 15 and 31 unused. Bit 15 can be used to indicate there is a Leaf Pile in the piece set (which then would exclude presence of any other piece). The Mummy bit (16) could indicate whether that Leaf Pile is petrified. The lowest bits could identify which Leaf Pile is on the square, by containing its pieceNr (14, 15, 31 or 32). Bit 14 could be used to indicate the Leaf Pile is digesting something (so that it would leave behind a Mummy on moving).

This makes it both easy to test for immobile pieces on a destination (AND with 1<<16) and for presence of a Leaf Pile (AND with 1<<15).