How to promote a pawn? - python-chess

I put a FEN where on the next move White can promote a pawn by moving b7a8.
In the library that I currently use (and that I want to replace). When doing this type of action, it returns a type of error so you ask why and then you get the indication that it is an error in this case because it is a type of movement that involves promotion.
So what I do is know what type of error it was, and if it is promotional, show on an display lcd, the options Queen, Rook, Bishop, Knight ... so the user select and i pass then the b7a8 with the letter of the piece.
When trying with " if move.promotion != None: " I find that you have to first send what you want for example "b7a8q" and then it tells you if it was a promotion move. But I would need to know before. For example: when doing b7a8, error, why? because it is a promotion movement, the user reintroduces the movement choosing, and there i have b7a8q.
Is this possible to do? or in what way could you solve this problem?
Thanks a lot.
This is the code im using to try things:
import asyncio
import chess
import chess.engine
engine = chess.engine.SimpleEngine.popen_uci("stockfish.exe")
board = chess.Board()
board.set_fen("rn1qkbnr/pPpb1ppp/4p3/8/3p4/8/PP1PPPPP/RNBQKBNR w KQkq - 1 5") #Position to try to promote "b7a8"
while not board.is_game_over():
print(board)
mover = input("Make your move")
prueba = chess.Move.from_uci(mover)
if prueba in board.legal_moves:
if board.is_castling(prueba):
print("good you castling")
else:
print ("that is not a good move, make another valid")
mover = input("a valid move please: ")
if prueba.promotion != None:
print ("This is a promotion (or was)")
board.push_xboard(mover)
print(board)
result = engine.play(board, chess.engine.Limit(time=0.1))
board.push(result.move)
print(board)
engine.quit()

In case the move is invalid, you could check whether adding "q" to it makes it valid. If so, then it must be that this is a pawn promotion move and you could then ask the user which piece they want to promote the pawn to.
So:
if prueba in board.legal_moves:
if board.is_castling(prueba):
print("good job castling!")
else:
if chess.Move.from_uci(mover + "q") in board.legal_moves:
mover += input("Which piece you want to promote the pawn to? [q,r,b,n]: ")
prueba = chess.Move.from_uci(mover)
if prueba not in board.legal_moves:
print ("that is not a good move, make another valid")
mover = input("a valid move please: ")
Still, there are some issues you would like to deal with:
There can be an exception when the input does not even resemble a move
Even after the above code, you may be left with an invalid move, so there really should be a loop that continues until the move is valid:
while True:
mover = input("Make your move: ")
prueba = None
try:
prueba = chess.Move.from_uci(mover)
except ValueError:
pass
if prueba not in board.legal_moves:
try:
if chess.Move.from_uci(mover + "q") in board.legal_moves:
mover += input("Which piece you want to promote the pawn to? [q,r,b,n]: ")
prueba = chess.Move.from_uci(mover)
except ValueError:
pass
if prueba in board.legal_moves:
break
print ("that is not a good move, make another valid move")

You should test if the promotion move is legal with the piece of your choice. After that, you can ask the user about the piece he wants.

Related

What is the best way to find out if the move captured a piece in python chess?

The best way I found to check if the move captured a piece is to count all the pieces before and after the move and verify if different, but seems to me very inefficient and not elegant.
You also need to check for en passant, but I think that is all you have to worry about.
The following code should work; it returns 0 if nothing captured, otherwise uses the codes from python chess (e.g. chess.PAWN, chess.ROOK, etc.):
def CapturedPiece(board, move):
if board.is_capture(move):
if board.is_en_passant(move):
return chess.PAWN
else:
return board.piece_at(move.to_square).piece_type
return 0
I couldn't find a function in the module that does this already, but that doesn't mean it doesn't exist or that it won't be added at some point.
Board's is_capture method encapsulates the necessary logic for normal captures as well as en passant:
# Position after e4 d5
b = chess.Board('rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 1')
move = chess.Move.from_uci('e4d5')
print(b.is_capture(move)) # True
Here is how they actually implement it (copied directly from Board):
def is_capture(self, move: Move) -> bool:
"""Checks if the given pseudo-legal move is a capture."""
touched = BB_SQUARES[move.from_square] ^ BB_SQUARES[move.to_square]
return bool(touched & self.occupied_co[not self.turn]) or self.is_en_passant(move)
I've found a better way than counting (even if still not nice is the best so far).
Verify if in the target square there is a piece or if the move is of a pawn verify if source and target file (x coordinate) is different.
quiet = board.piece_type_at(move.to_square)==None
if ( board.piece_type_at(move.from_square)==chess.PAWN ) \
and ( chess.square_file(move.from_square)!=chess.square_file(move.to_square) ):
quiet=False

What am I doing wrong with this simple If function in ruby

I have been trying to teach myself to code and have gravitated towards Ruby.
Upon working on if functions I have come across this problem where even if the user input is == to the answer variable it still comes back as false in the if function. It will not come back as true
I can get it to work if it is an Integer, but for some reason it always returns false when having a string. Tried to convert is as well but can not figure it out.
Thank you for any help.
puts("For each question select A, B, or C")
puts("What is the capital of Kentucky?")
puts()
puts("A. Louisville")
puts("B. Frankfort")
puts("C. Bardstown")
puts()
answer = String("B")
text = gets()
puts()
if text == answer
puts("correct")
else
puts("incorrect")
puts("The correct answer was " + answer + ".")
end
There is an additional method you can call when declaring the "text" variable that will solve this.
The method you used preserves a line break at the end when you press enter to submit an answer so it will never actually correspond to the answer. To remove the line break use the "chomp" method.
text = gets.chomp
Hope this helped. Good luck.

Python 2, raw_input in define function. Returning value

I decided to have a little bit fun with coding python 2 in a long while and decided to try make somewhat playable game of Go.
I quickly tumbled on this issue while trying to make function for the game, it seems like I'm not understanding how raw_input or functions work fundamentally. I cut the part of the code that is giving me the trouble here. When I try to run this, I can get to give inputs, but after that I get NameError: name 'crd_x' is not defined, in the stoneplacement line. The code does work without using the function, but when I try to clean it up like this, I get the said error.
What exactly does return crd give out and how I'm actually supposed to give out variables from def functions?
def checkplayerinput():
if player_on_turn == 0:
crd = raw_input("Place Black stone (X-Y): ").split("-")
elif player_on_turn == 1:
crd = raw_input("Place White stone (X-Y): ").split("-")
crd_x = int(crd[1])
crd_y = int(crd[0])
return crd_x, crd_y
def stoneplacement(crd_x, crd_y, player_on_turn):
if board[crd_x][crd_y] == "+" and player_on_turn == 0:
board[crd_x][crd_y] = "B"
elif board[crd_x][crd_y] == "+" and player_on_turn == 1:
board[crd_x][crd_y] = "W"
stop = 0
while stop == 0:
#User input and derive coordinates
checkplayerinput()
# Stone placement
stoneplacement(crd_x, crd_y, player_on_turn)
edit. just switched the place of crd_x and crd_y like they are in the actual code. It produces exact same NameError however.
So crd is going to give you an array of strings based on whatever the user types in, separated by the ‘-‘ symbols. For example if player_on_turn == 0, and you entered for example “X-Y” (whatever your game calls for), checkplayerinput() would return crd as [“X”, “Y”].
Also, remember that an array is indexed starting at 0. So in this example, crd[0] == “X”.
Running through your code, does that explain why your stoneplacement() function throws a NameError? I.e. are you inputting the right raw_input to yield crd[1]?
Also, did you define crd before def checkplayerinput() in the code? According to python scope rules, if you define the variable crd inside of the function, it will not have a global value outside of it (and will throw an error if you reference it in another function). This is likely why you are able to run your code without the function definitions. Try adding a line “global crd” or “crd = [ ]” somewhere outside of the function and it will allow you to access crd in the stoneplacement(( function.

Infinite Loop x Counter Problems

Hello I have three problems with my code:
when I type in "N" for my first question, it goes into an error.
I get in an infinite loop after the "Run again?" input.
my counters do not add up properly so even when I get an answer right or wrong, it doesn't count them.
Please help me.
Below is my code:
#Introduction-ish print statement
print("In this application, we will be playing a coin coss game. For as "\
"many times as you like, we will continue playing the game.")
#def function1():
response=str(input("\nWould you like to run this application? Type 'Y' to run "\
"or 'N' to not run: "))
if response=="N":
print("\nOutcome of Game:")
print("You did not run the application."\
" Nothing happened. You did not play the game.")
#Counters
programCounter=0
hCounter=0
tCounter=0
guessCountR=0
guessCountW=0
#User Input
if response=="Y":
funcGuess=str(input("\nPick one- Type 'H' for Heads or 'T' for Tails: "))
#Coins
import random
#number=random.randint(1,2)
while response !="N" and funcGuess=="H" or funcGuess=="T":
number=random.randint(1,2)
if number==1:
number=="Heads"
hCounter+=1
else:
number=="Tails"
tCounter+=1
if funcGuess==number:
guessCountR+=1
else:
guessCountW+=1
print(number)
response=str(input("Run again?"))
if response=="Y":
funcGuess=str(input("\nPick one- Type 'H' for Heads or 'T' for Tails: "))
if response=="N":
print("\nOutcome of Game:")
print("You guessed ",programCounter, "time(s).")
print("You guessed heads",hCounter, "time(s).")
print("You guessed tails",tCounter, "time(s).")
print("You guessed correctly",guessCountR, "time(s).")
print("You guessed incorrectly",guessCountW, "time(s).")
#Guess Count
guessCount=guessCountR+guessCountW
#paste
#if response =="Y":
#function1()
#else:
#print("\nOutcome of Game:")
#print("You did not run the application."\
#" Nothing happened. You did not play the game.")
I don't mind all the comments. I purposely left them there but if anyone helping finds them useful, please let me know.
Apologies in advanced for the long post.
Problem 1:
On line 34 you're evaluating a variable called funcGuess. It only gets defined on line 26 should you answer 'Y' to the initial question.
Problem 2:
The while loop loops infinitely, because break conditions can never be met. There's no way to assign response the value "N" within the loop. Also, be sure to put both sides of the or evaluation between parentheses in order to evaluate the line correctly
Problem 3:
The correct number and the guess are assigned into variables number and funcGuess, respectively. number is always 1 or 2, and funcGuess is always "H" or "T". Therefore funcGuess == number can never evaluate as True.

problems implementing negamax for tic-tac-toe in ruby

I'm banging my head against the wall trying to implement negamax for tic-tac-toe
def negamax(board_obj, mark, depth)
if board_obj.game_over?
return value(board_obj)
else
max = -1.0/0 # negative infinity
if mark == #mark
next_mark = #opponent_mark
else
next_mark = #mark
end
board_obj.empty_squares.each do |square|
board_obj[square] = mark
x = -negamax(board_obj, next_mark, depth + 1)
board_obj[square] = ' '
if x > max
max = x
#scores << x
#best_move = square if depth == 1
end
end
return max
end
end
# determines value of final board state
def value(board_obj)
if board_obj.mark_win?(#mark)
return 1
elsif board_obj.mark_win?(#opponent_mark)
return -1
else
return 0
end
end
the rest of the code is here: https://github.com/dave-maldonado/tic-tac-doh/blob/AI/tic-tac-doh.rb
It does produce a result but the AI is easily beat so I know something's wrong, any help
is appreciated!
The problem is that value needs to be relative to the mark in the current execution of negamax rather than always relative to the computer. If you pass in the mark argument to value from negamax with the following modified definition for value, you'll get the right results:
def value(board_obj, mark)
if board_obj.mark_win?(mark)
return 1
elsif board_obj.mark_win?(mark == 'X' ? 'O' : 'X')
return -1
else
return 0
end
end
That is, the first two lines of the negamax body need to be:
if board_obj.game_over?
return value(board_obj, mark)
That said, this overall program leaves an awful lot to be desired relative to Ruby, good design principles, etc (no offense intended). Now that you have it running, you might want to head over to the Code Review SE for some feedback. :-) And while it's too late to use TDD ;-), it would also be a good one to put "under test".
Also, please understand that per one of the other comments, this is not a kind of question that you'll typically get an answer to here at SO. I don't even know if this question will survive the review process without getting deleted. I worked on it for a variety of personal reasons.
Update: Looking at your reference implementation, you'll note that the negamax code includes the expression sign[color]*Analysis(b). It's that sign[color] that you were missing, effectively.

Resources