Stack Overflow Asked on December 13, 2021
Please excuse this post if it doesn’t suit you. Maybe I shouldn’t ask this sort of question.
I don’t often post, however I was writting some code with my son. We codded a simple "Fingers War" game. I wasn’t familiar with this but I soon understood the elementary algorithm. I know we code a little verbose but it’s easier to read and understand when you are learning basic code.
Usually you play this facing another player in a playground. Both players tart with their hands showing one finger each. Player1 one can either pass a (or some) finger(s) to his other hand or touch his opponents hand thus adding the same amount of fingers there. If a hand gets to more than five fingers you substarct five and keep on playing. If one hand gets down to 0 you can still add fingers to it. However when opponents hands both get down to 0 its a win for player with fingers left.
You can try the game by running my code: Player1 hands are A & B Player2 hands are C & D. Player1 starts.
My question is "How might I go about codding the ‘Play against computer’?" I have no idea where to start. I have just this "def ai(self): pass" in my class. What might I put in it?
cheers to anyone how takes up the challenge and teaches us something,
kind regards,
Quinkink
Here is the code so far.
class FingerWars:
hands = {'A': 1, 'B': 1, 'C': 1, 'D': 1}
players = {'player1': 'Player1', 'player2': 'Player2'}
player = 'player2'
loop = True
source_hands_str = {'player1': 'A or B', 'player2': 'C or D'}
target_hands_str = {'A': 'B, C or D', 'B': 'A, C or D', 'C': 'A, B or D', 'D': 'A, B or C'}
def __init__(self, player1='Player1', player2='Player2'):
"""
Set player names or leave default
:param player1:
:param player2:
"""
self.players['player1'] = player1
self.players['player2'] = player2
def game(self):
"""
Main game loop.
Toggle player turns.
:return: void
"""
while self.loop:
if self.player == 'player1':
self.player = 'player2'
else:
self.player = 'player1'
self.fingers()
if self.players[self.player] == 'computer':
self.ai()
else:
self.turn()
self.evaluate()
def ai(self):
"""
AI is called when one of the players is called 'computer'.
How on earth might this work?
LEVEL ONE: challenge
LEVEL TWO: unbeatable
:return: void
"""
pass
def turn(self):
"""
Game turn.
Can player only play from one hand?
User specified target.
Auto or user specified number of fingers.
Do the math.
:return: void
"""
# AUTO CHOOSE IF ONE HAND = 0
if self.player == 'player1':
if self.hands['A'] == 0:
source_hand = 'B'
print(self.players[self.player] + 'source hand is : ' + source_hand)
elif self.hands['B'] == 0:
source_hand = 'A'
print(self.players[self.player] + 'source hand is : ' + source_hand)
else:
source_hand = input(
self.players[self.player] + " choose a source hand (" + self.source_hands_str[self.player] + ")? ").upper()
else:
if self.hands['C'] == 0:
source_hand = 'D'
print(self.players[self.player] + 'source hand is : ' + source_hand)
elif self.hands['D'] == 0:
source_hand = 'C'
print(self.players[self.player] + 'source hand is : ' + source_hand)
else:
source_hand = input(
self.players[self.player] + " choose a source hand (" + self.source_hands_str[self.player] + ")? ").upper()
# SPECIFY TARGET HAND
target_hand = input(
self.players[self.player] + " choose a target hand (" + self.target_hands_str[source_hand] + ")? ").upper()
fingers = self.hands[source_hand]
# SPECIFY NB OF FINGERS IN INTERNAL FINGER SWAP
if fingers > 1:
if (source_hand in ('A', 'B') and target_hand in ('A', 'B'))
or (source_hand in ('C', 'D') and target_hand in ('C', 'D')):
fingers = int(input(self.players[self.player] + " how many fingers? "))
print(self.players[self.player] + " : " + source_hand + " (" + str(self.hands[source_hand]) + ") -> " + target_hand)
# DO THE TURN PLAY MATH
if source_hand == 'A' or source_hand == 'B':
if target_hand == 'A' or target_hand == 'B':
self.hands[source_hand] = self.hands[source_hand] - fingers
self.hands[target_hand] = self.hands[target_hand] + fingers
else:
self.hands[target_hand] = self.hands[target_hand] + fingers
if source_hand == 'C' or source_hand == 'D':
if target_hand == 'C' or target_hand == 'D':
self.hands[source_hand] = self.hands[source_hand] - fingers
self.hands[target_hand] = self.hands[target_hand] + fingers
else:
self.hands[target_hand] = self.hands[target_hand] + fingers
def evaluate(self):
"""
evaluates fingers in hand. Evaluates win.
:return: void
"""
# EVALUATE FINGERS IN HAND
for key, value in self.hands.items():
if value > 4:
self.hands[key] = self.hands[key]-5
# EVALUATE WINNER
if self.hands['A'] == 0 and self.hands['B'] == 0:
print('Player : ' + self.players[self.player] + ' wins the finger war!')
self.fingers()
self.loop = False
if self.hands['C'] == 0 and self.hands['D'] == 0:
print('Player : ' + self.players[self.player] + ' wins the finger war!')
self.fingers()
self.loop = False
def fingers(self):
"""
prints user feedback. This is called after each turn
:return: void
"""
feedback = "A:" + str(self.hands['A']) + " B:" + str(self.hands['B'])
+ " vs C:" + str(self.hands['C']) + " D:" + str(self.hands['D'])
print(feedback)
def main():
# game = FingerWars()
game = FingerWars('Player1', 'Player2')
game.game()
if __name__ == "__main__":
main()
To do this you need to build a model of the state space that the AI can use for searching. A good way to do this is using:
Given these functions, you can apply the minimax algorithm to forward simulate the game. But, there are a few complications:
An alternate approach is to just enumerate all possible state of the game (there aren't that many, relatively speaking) and to work backwards from proven states until you reach the start state. Then, you'll have an optimal strategy to play the game.
This should get you started - there are lots of questions about minimax, alpha-beta pruning, monte-carlo tree search and similar things here that can help you go deeper when you're ready.
Answered by Nathan S. on December 13, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP