HiveBrain v1.2.0
Get Started
← Back to all entries
principlepythonMinor

A game of NIM (Basic AI strategy)

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gamenimbasicstrategy

Problem

I tried creating the game of NIM in python. I researched a couple of videos on how to always win at NIM. Eventually, I found a method and i was able to implement it in my code. This is the result...

```
#---------------------
# NIM GAME
# Author : Akil Riaz
#---------------------

import random
import time

def welcome_message():
print("""
----------------------------------------------------------------------------
WELCOME TO THE GAME OF NIM!
----------------------------------------------------------------------------
Rules: 1 - The user plays against the computer.
2 - Only 1-3 sticks can be taken at a time.
3 - The person who is left with the last stick is the loser.
4 - Have FUN!
----------------------------------------------------------------------------
""")

def display_board(board):
print("\n----------------------------------------------------------------------------")
print(" ",*board, sep=" ")
print("----------------------------------------------------------------------------\n")

def who_starts(question):
choice = None
while choice not in ("F", "S","f","s"):
choice = input(question)
if choice.upper() == "F":
f_player = "USER"
s_player = "USER"
elif choice.upper() == "S":
f_player = "CMP"
s_player = "CMP"
else:
print("\nInvalid choice. Please re-enter your choice.")

return f_player, s_player

def users_pick(question,minStick,maxStick,userIn,board):
print("\n--USER'S TURN--")
while userIn not in range(minStick, maxStick) or userIn >= len(board):
try:
userIn = int(input(question))
if userIn not in range(minStick, maxStick) or userIn >= len(board):
print("\nYou can cannot choose that many sticks!")
userIn = int(input(question))

except Exception as e:
print("\nAn error has occured.\nError: " +

Solution

General coding style and other useful tips

Tip 1
When using conditions, you don't need to type x == True, which means :

while anotherGo == True:


can be :

while anotherGo:


Tip 2 Don't use time.sleep for nothing. It could create confusion as to why you're using it when, I think, you're using it just so the program doesn't go too fast, but... why would you want that? :)

Tip 3 When you use if/else, you can move the common code to the end or the beginning of the conditions, this removes code duplication :

if f_player == "USER":
    time.sleep(0.5)
    userIn,f_player = users_pick("\nEnter your choice [1, 2 or 3]: ", 1, 4, 20,nimBoard)
    nimBoard = update_board(nimBoard,userIn)
    display_board(nimBoard)
    print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")
else:
    time.sleep(1)
    nimBoard, f_player,winning_position, earlier_move = computers_move(nimBoard,userIn,s_player,winning_position,earlier_move)
    time.sleep(1)
    display_board(nimBoard)
    print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")


Becomes :

if f_player == "USER":
    userIn,f_player = users_pick("\nEnter your choice [1, 2 or 3]: ", 1, 4, 20,nimBoard)
    nimBoard = update_board(nimBoard,userIn)

else:
    nimBoard, f_player,winning_position, earlier_move = computers_move(nimBoard,userIn,s_player,winning_position,earlier_move)

display_board(nimBoard)
print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")


Tip 4 If all your prints start with a line break, you could consider creating an helper function so you don't have to retype it every time :

def printn(s):
    print("\n" + s)


Tip 5 Create constants for those "magic numbers". When I read :

users_pick("\nEnter your choice [1, 2 or 3]: ", 1, 4, 20,nimBoard)

Tip 6 You don't pay per character written, use meaningful variable names

Instead of having a variable named userIn, you could consider naming it userInput. It's... 3 more characters, but it's also much clearer what it does

I need to go check the function definition to see what 1,4,20 mean. If you had constants named MIN_STICK = 1, MAX_STICKS=4, USERIN=20.

Python tips

Tip 1 If you create an array with the same value multiple times, you can do :

# Notice how nice it is not to have to count to see the number of sticks
["/"] * 17


instead of :

["/","/","/","/","/","/","/","/","/","/","/","/","/","/","/","/","/"]


But I also think you don't need this array at all. You could simply keep the number of sticks available as an int and decrease it when necessary. This array is used to print the board, so you shouldn't mix the display logic with the game logic, it'll make code easier to maintain and to read.

Tip 2 Use only one naming style

You mix snake_case and camelCase in your code, which makes the code harder to read. Since you're using Python, you should stick to snake_case.

Code "cleanness"

In the users_pick method, you pass a userIn that's higher than the maximal accepted value, only so that your while loop works (I suspect). Don't do this, as a matter of fact, you shouldn't pass userIn at all as a parameter, because you completely ignore the input.

In users_pick again. Doing this : userIn not in range(minStick, maxStick) might look "great", but it also means every time you call this you generate a range, only to check if the value is in there, why not use userIn maxStick that's much faster and more... logical.

I'm not sure if it's a copy/paste error, but in the who_starts method you set both f_player and s_player to the same values.

All in all, I think you should try to separate the display logic and the game logic in your code. You've done it pretty well regarding user inputs, but for example, you don't need to keep an array of / to see where the game is at.

Code Snippets

while anotherGo == True:
while anotherGo:
if f_player == "USER":
    time.sleep(0.5)
    userIn,f_player = users_pick("\nEnter your choice [1, 2 or 3]: ", 1, 4, 20,nimBoard)
    nimBoard = update_board(nimBoard,userIn)
    display_board(nimBoard)
    print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")
else:
    time.sleep(1)
    nimBoard, f_player,winning_position, earlier_move = computers_move(nimBoard,userIn,s_player,winning_position,earlier_move)
    time.sleep(1)
    display_board(nimBoard)
    print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")
if f_player == "USER":
    userIn,f_player = users_pick("\nEnter your choice [1, 2 or 3]: ", 1, 4, 20,nimBoard)
    nimBoard = update_board(nimBoard,userIn)

else:
    nimBoard, f_player,winning_position, earlier_move = computers_move(nimBoard,userIn,s_player,winning_position,earlier_move)

display_board(nimBoard)
print("\nThere are " + str(len(nimBoard)) + " stick(s) remaining.")
def printn(s):
    print("\n" + s)

Context

StackExchange Code Review Q#160403, answer score: 2

Revisions (0)

No revisions yet.