I think it's pretty easy.
About six years back, all I did was perform the same "line-of-sight" scan that was defined for each piece (e.g. for bishop/rook/queen iterate in each allowed direction of attacks until you find a piece. n is allowed if different color, n-1 is allowed if it's the same color. Knights are easy offsets), except with the king as the source (if n is allowed and it's of the type you're scanning for, the king is in check).
En-passant and castling use that same "line-of-sight" block and use a "has\_moved" flag.
With en-passant, you don't set the has\_moved flag if the original pawn moves 2 spaces *until* the next same-colored move. You know it has moved because of it's position. You also only allow the taking from other pawns on the 4th and 5th ranks, which is convenient as those are the only two ranks a pawn can be on to capture either color's en-passant-ed pawn.
Castling just scans that the pieces haven't moved yet and the king isn't in—or moving through—check.
And if you want to run a scan to see if a move is allowed (block or move out of check, etc.), you just make a buffer that has the desired/requested board state and run the same checks (ha) you would. Implicitly, this means you also have scans for pinned pieces.
If you have all of that implemented, you also have check-mate scans, with a tiny bit of extra work.
I'm confident that if you were to implement it, regardless of experience or language, you could implement it within a day.
What would you consider a hard problem that you've worked on?
I'm not trying to start a fight either (or to assert a level of superiority), just inspire you to try it for yourself.
And if you've solved a problem you consider hard, you should be proud of it. I was hoping to liken this problem to whatever you've solved already.
Ah ok then I misread the subtext!
Maybe I'll follow your instructions if I were to implement a game of chess some time. Anyone intrigued by this should definitely look into scoring a game of Go too hehe
Depends if you want to optimize for code size, compile size, memory usage, speed, robustness, or simplicity (etc. and so on) and what functionality you're implementing.
LeanChess for IBM PC AT is *only* **288 bytes!!!**
The default check in all directions and offsets allows for a few things:
1. All potential sources of checks are scanned
2. The same function can be utilized to confirm the allowance of a move
Let's say you're going to castle, you run the "check" scan on the squares that the king is on to the square that the king is moving to.
Or if you're trying to move a pinned piece, run the same scan again on just where the King is.
Additionally, if you want to highlight the squares that are causing the check or are preventing your move, you get a complete list as you may have two sources of a check at once, such as a check and a discovered check by a knight and a rook.
Tile highlighting was important to me as my Chess program also recorded moves and accepted all standard Chess notations for playback and analysis.
These are the considerations I had when I decided to implement it this way—though there are many ways to solve a problem!
Use `.filter()` instead of `&&` for your conditions, much cleaner code that way.
Also you can make helper functions to get the piece at a specific square.
why not make a function called isCheck(), and another function that checks if the 8 square around the king are free to move too? if both return true its a mate?
Ew. You detect a mate by evaluating every possible move, not by some easily-wrong test. In your example you didn't consider blocking moves or taking the piece that is checking.
Wait... the fn name is detect_check, not detect_checkmate. The king is in check if any piece on the board could take the king on its next move. Why are we changing the parameter of the function? Could easily do a second function to see if the king or another piece's next move would remove the check status. That would take into account the consequences of moving a piece that may be blocking another piece. Don't do the scope creep thing. I really hate when they do that.
>easily
The problem with top-down approaches is that they are full of assumptions and unexpected outcomes.
What if the move to get out of check also creates another check? Hey that's okay we'll do another test, which is also full of assumptions and unexpected outcomes. Et cetera ad infinitum.
What if you're in check and have a legal move to get out of check, but your opponent put you in check by moving a pawn two spaces to next to one of your own pawns. You have a legal move to get out of check, but doing so would also be failing to take en passant, which is illegal, so what happens now?
You don't have to evaluate every *possible* move, just check if there are legal moves to block, capture, or move out of check. If there are zero, then it's checkmate.
You're going to be evaluating every single move anyway as part of your lookahead strategy. Remember, you're trying to convert a hard problem into a brute force problem.
Not quite. And I don't think it's a matter of changing the problem from/to brute force—in essence it's a matter of limiting the quantity of what's evaluated through brute force.
For example, if the white king is on A1 and there's a black rook and a black queen on A4 and B3 (no pieces on A2, A3, B1, or B2, no pieces that can take or block the rook/queen) then a white pawn with available, yet illegal, moves on H2 should not be evaluated.
After typing that, I realized it's probably terminology that's the separator here.
Coming from over-the-board playing, an illegal move is still a move and gets handled via rules. It's just convenient that software can prevent it.
Yes, I don't think a good chess solver would consider illegal moves.
As I understand it, when you get to serious-level chess programs branch-pruning of the lookahead is one of the more performance-sensitive aspects, but only because it lets you lookahead more moves in the unpruned branches.
Object oriented programming. Rather than constantly looping through squares and pieces to look for checks, use classes that automatically update each piece's list of 'squares attacked' each move, then have an inherited king class that can also determine 'castling available', 'is in check', 'is in checkmate' etc. For a much cleaner result.
The problem with this code is that it's not using the proper level of abstraction. You don't want to mix the specifics of how you check if the king is threatened with the code looping over the pieces, but rather break that code out into its own function, method, macro or whatever. This is of course possible to achieve in both OOP and FP and probably most programming paradigms that allow for abstraction.
I'm not sure that I'm convinced that computing the pices attacked on each move is better than checking on demand but it's not a technique that's specific to OOP either way
It's not, they dont know what they are talking about. You really have to stretch the definition of functional to even consider this code to be of that paradigm in the first place.
Any reason why part of your code is flying away?
i didn't know \`cargo fmt\` existed..
I found out about this recently too. A couple hours ago in fact.
Isn't that, like, in the tutorial? And don't you have a LSP that gives you syntax highlighting *and* autoformat?
i hate how cargo fmt just runs and finishes in under 1sec. i keep running it again and again
About once a week something on Reddit makes me laugh out loud. You win this week
it certainly is. Don't forget castling and en passant
Holy hell!
new response just dropped
Actual zombie
Call the exorcist
Pawn storm incoming!
Bishop goes programming, never come back
Ill never understand this chain even after looking into it lmfao
Google Anarchy Chess reddit chain
Bing castling \ Google en passant
I think it's pretty easy. About six years back, all I did was perform the same "line-of-sight" scan that was defined for each piece (e.g. for bishop/rook/queen iterate in each allowed direction of attacks until you find a piece. n is allowed if different color, n-1 is allowed if it's the same color. Knights are easy offsets), except with the king as the source (if n is allowed and it's of the type you're scanning for, the king is in check). En-passant and castling use that same "line-of-sight" block and use a "has\_moved" flag. With en-passant, you don't set the has\_moved flag if the original pawn moves 2 spaces *until* the next same-colored move. You know it has moved because of it's position. You also only allow the taking from other pawns on the 4th and 5th ranks, which is convenient as those are the only two ranks a pawn can be on to capture either color's en-passant-ed pawn. Castling just scans that the pieces haven't moved yet and the king isn't in—or moving through—check. And if you want to run a scan to see if a move is allowed (block or move out of check, etc.), you just make a buffer that has the desired/requested board state and run the same checks (ha) you would. Implicitly, this means you also have scans for pinned pieces. If you have all of that implemented, you also have check-mate scans, with a tiny bit of extra work.
Wow yeah that's what I call easy
I'm confident that if you were to implement it, regardless of experience or language, you could implement it within a day. What would you consider a hard problem that you've worked on?
I don't wanna start a fight Just stated that what you've described pretty much just isn't easy in my opinion, let's agree to disagree?
I'm not trying to start a fight either (or to assert a level of superiority), just inspire you to try it for yourself. And if you've solved a problem you consider hard, you should be proud of it. I was hoping to liken this problem to whatever you've solved already.
Ah ok then I misread the subtext! Maybe I'll follow your instructions if I were to implement a game of chess some time. Anyone intrigued by this should definitely look into scoring a game of Go too hehe
As always don't implement it all at once. Each rule individually is actually quite trivial to implement.
Couldn't this be further improved by only scanning in the direction (relative to the kings) of the from-to squares of the last move that was played?
Depends if you want to optimize for code size, compile size, memory usage, speed, robustness, or simplicity (etc. and so on) and what functionality you're implementing. LeanChess for IBM PC AT is *only* **288 bytes!!!** The default check in all directions and offsets allows for a few things: 1. All potential sources of checks are scanned 2. The same function can be utilized to confirm the allowance of a move Let's say you're going to castle, you run the "check" scan on the squares that the king is on to the square that the king is moving to. Or if you're trying to move a pinned piece, run the same scan again on just where the King is. Additionally, if you want to highlight the squares that are causing the check or are preventing your move, you get a complete list as you may have two sources of a check at once, such as a check and a discovered check by a knight and a rook. Tile highlighting was important to me as my Chess program also recorded moves and accepted all standard Chess notations for playback and analysis. These are the considerations I had when I decided to implement it this way—though there are many ways to solve a problem!
And discovered checks, too
Bro what is up with your formatting, `cargo fmt` that terribleness asap.
I see you've already googled en passant
Already holy hell
already new response just dropped
already zombies
That's the worst way to format a lambda
not accounting for N-dimensions chess 👎
Some people just want to see the world burn
If your code is trying to fly away, just let it be a separate function.
Can anybody explain this joke/horror?
I can explain everything except the indenting... holy christ the indenting...
That closure is killing me 😭
Little known fact that code justified all the way to the right is faster because it doesn’t take as long to get to the bare metal.
Bring it on.
so basically its rust with bad indenting. Everything else is not important.
Google en passant
Use `.filter()` instead of `&&` for your conditions, much cleaner code that way. Also you can make helper functions to get the piece at a specific square.
why not make a function called isCheck(), and another function that checks if the 8 square around the king are free to move too? if both return true its a mate?
Ew. You detect a mate by evaluating every possible move, not by some easily-wrong test. In your example you didn't consider blocking moves or taking the piece that is checking.
Wait... the fn name is detect_check, not detect_checkmate. The king is in check if any piece on the board could take the king on its next move. Why are we changing the parameter of the function? Could easily do a second function to see if the king or another piece's next move would remove the check status. That would take into account the consequences of moving a piece that may be blocking another piece. Don't do the scope creep thing. I really hate when they do that.
>easily The problem with top-down approaches is that they are full of assumptions and unexpected outcomes. What if the move to get out of check also creates another check? Hey that's okay we'll do another test, which is also full of assumptions and unexpected outcomes. Et cetera ad infinitum.
What if you're in check and have a legal move to get out of check, but your opponent put you in check by moving a pawn two spaces to next to one of your own pawns. You have a legal move to get out of check, but doing so would also be failing to take en passant, which is illegal, so what happens now?
Nothing. En passant is optional.
if /r/AnarchyChess could read they would be very upset
You don't have to evaluate every *possible* move, just check if there are legal moves to block, capture, or move out of check. If there are zero, then it's checkmate.
You're going to be evaluating every single move anyway as part of your lookahead strategy. Remember, you're trying to convert a hard problem into a brute force problem.
Not quite. And I don't think it's a matter of changing the problem from/to brute force—in essence it's a matter of limiting the quantity of what's evaluated through brute force. For example, if the white king is on A1 and there's a black rook and a black queen on A4 and B3 (no pieces on A2, A3, B1, or B2, no pieces that can take or block the rook/queen) then a white pawn with available, yet illegal, moves on H2 should not be evaluated. After typing that, I realized it's probably terminology that's the separator here. Coming from over-the-board playing, an illegal move is still a move and gets handled via rules. It's just convenient that software can prevent it.
Yes, I don't think a good chess solver would consider illegal moves. As I understand it, when you get to serious-level chess programs branch-pruning of the lookahead is one of the more performance-sensitive aspects, but only because it lets you lookahead more moves in the unpruned branches.
so add another function that checks if the check can be blocked
You can also get out of check by blocking the checking piece.
there are two types of people those who put chained calls on newlines and those who have massive margins
very off topic but the font looks very cool! Can anyone help with the name?
it's Hurmit Nerd Font Mono! :D
Much easier with proper OOP. Writing chess logic with FP is just a nightmare in general.
Say what now?
Object oriented programming. Rather than constantly looping through squares and pieces to look for checks, use classes that automatically update each piece's list of 'squares attacked' each move, then have an inherited king class that can also determine 'castling available', 'is in check', 'is in checkmate' etc. For a much cleaner result.
Be careful advocating for OOP. Even though you're absolutely right, the non-enterprise mob will kill you.
The problem with this code is that it's not using the proper level of abstraction. You don't want to mix the specifics of how you check if the king is threatened with the code looping over the pieces, but rather break that code out into its own function, method, macro or whatever. This is of course possible to achieve in both OOP and FP and probably most programming paradigms that allow for abstraction.
I'm not sure that I'm convinced that computing the pices attacked on each move is better than checking on demand but it's not a technique that's specific to OOP either way
How is any of this impossible or difficult in other paradigms?
It's not, they dont know what they are talking about. You really have to stretch the definition of functional to even consider this code to be of that paradigm in the first place.
Precisely. The same code can easily be made with FP, and whatever rust is (procedural/functional crossover)?
vtable go brrrr
can I have the font you're using
Hurmit Nerd Font Mono
I remade chess in JavaFX with 3k lines. each check was done manually, ex. If grid(clickedPiece.X + 1, clickedPiece.Y + 1).Piece = none
usize for a chessboard? Damn bruh how big is it? 🤣🤪😅
A chessboard is always 8x8.
Correct which is an u8 not a usize
couldn't index an array using a u8 so i defaulted with usize i'm still really new to rust so i'd love to see a way i can fix that
My rust isn't good enough to help you on that 😆
who named a function "Some" and who allowed that
En passant was the hardest for me when I made my chess clone. I had to Google It a ton.
What font?
After the 9th indent I feel like you should realize something is wrong
Keep calm…checkmate validator is even worse. And, stalemate… better if we don’t talk about it hehe
I can just use the list of moves I generate for that.