11
\$\begingroup\$

How can I improve this simple code to look better, concise and elegant? I've been learning Python for 2 weeks. I knew about basic Python stuff and some algorithms and data structure as well. I made a Tic-Tac-Toe game and it worked well but the problem is that I can't write code in a Pythonic way.

#importing libraries

from __future__ import print_function
import random
import os
import sys
#clear output 
clear = lambda : os.system('cls')

#creating display board 
def display_board(board):
    clear()
    print('   |   |')
    print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[4] + ' | ' + board[5] + ' | ' + board[6])
    print('   |   |')
    print('-----------')
    print('   |   |')
    print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3])
    print('   |   |')
#getting input from player
def player_input():
    marker = ' '
    while not (marker == 'X' or marker == 'O'):
        marker = raw_input('Choose O or X to play!').upper()
    if marker == 'X':
        return ('X','O')
    else:
        return ('O','X')
#place marker on borard
def place_marker(board,marker,postion):
    board[position] = marker
#Checking win or not 
def win_check (board,mark):
    return ((board[7] == mark and board[8] == mark and board[9] == mark) or # across the top
    (board[4] == mark and board[5] == mark and board[6] == mark) or # across the middle
    (board[1] == mark and board[2] == mark and board[3] == mark) or # across the bottom
    (board[7] == mark and board[4] == mark and board[1] == mark) or # down the middle
    (board[8] == mark and board[5] == mark and board[2] == mark) or # down the middle
    (board[9] == mark and board[6] == mark and board[3] == mark) or # down the right side
    (board[7] == mark and board[5] == mark and board[3] == mark) or # diagonal
    (board[9] == mark and board[5] == mark and board[1] == mark)) # diagonal
# who first to go

def choose_first():
    if random.randint(0,1) == 0:
        return 'Player 1'
    else:
        return 'Player 2'

# checking space is free or not
def check_space(board,position):
    return board[position] == ' '
#full board check 
def full_board_check (board):
    for i in range (1,10):
        if check_space(board,i):
            return False
    return True
#player choice
def player_choice (board):
    position = ' '
    while position not in '1 2 3 4 5 6 7 8 9'.split() or not check_space(board, int(position)):
        position = raw_input('Choose number input 1-9')
    return int(position)
#asking replay or not 
def replay():

    return raw_input('Do you want to play again? Enter Yes or No: ').lower().startswith('y')
print('Welcome to Tic Tac Toe Game!')

while True:
    # Reset the board
    theBoard = [' '] * 10
    player1_marker, player2_marker = player_input()
    turn = choose_first()
    print(turn + ' will go first.')
    game_on = True

    while game_on:
        if turn == 'Player 1':
            # Player1's turn.

            display_board(theBoard)
            position = player_choice(theBoard)
            place_marker(theBoard, player1_marker, position)

            if win_check(theBoard, player1_marker):
                display_board(theBoard)
                print('Congratulations! You have won the game!')
                game_on = False
            else:
                if full_board_check(theBoard):
                    display_board(theBoard)
                    print('The game is a draw!')
                    break
                else:
                    turn = 'Player 2'

        else:
            # Player2's turn.

            display_board(theBoard)
            position = player_choice(theBoard)
            place_marker(theBoard, player2_marker, position)

            if win_check(theBoard, player2_marker):
                display_board(theBoard)
                print('Player 2 has won!')
                game_on = False
            else:
                if full_board_check(theBoard):
                    display_board(theBoard)
                    print('The game is a tie!')
                    break
                else:
                    turn = 'Player 1'

    if not replay():
        break
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

You have created a working game, kuddo's for that.

The good

  • Some parts of the code are divided into functions
  • (nearly) made this work for both python3 and python2

    NameError: name 'raw_input' is not defined

    Adding this to the top of the file would circumvent that

    try:
        raw_input()
    except NameError:
        raw_input = input
    

    This is tagged with 2.7, but if there is no specific reason for it. I suggest to start writing in 3.x

The bad

  • This code is begin suffocated, #add a few blank lines. [PEP8]
  • Stick to DRY (Don't Repeat Yourself)

    You are repeating yourself in some areas

    display_board(theBoard)
    position = player_choice(theBoard)
    place_marker(theBoard, player1_marker, position)
    if win_check(theBoard, player1_marker):
        display_board(theBoard)
        print('Congratulations! You have won the game!')
        game_on = False
    else:
        if full_board_check(theBoard):
            display_board(theBoard)
            print('The game is a draw!')
            break
        else:
            turn = 'Player 2'
    
  • Use 'string'.format() over string concants

    At your display_board(board) function for example

Revised code

import random
try:
    raw_input()
except NameError:
    raw_input = input

# This idea is shamelessly stolen from!
# https://codereview.stackexchange.com/questions/108738/python-tic-tac-toe-game
WIN_COMBINATIONS = [(1, 2, 3),
                    (4, 5, 6),
                    (7, 8, 9),
                    (1, 4, 7),
                    (2, 5, 8),
                    (3, 6, 9),
                    (1, 5, 9),
                    (3, 5, 7)]

def display_board(board):
    print('''   |   |  
 {} | {} | {}
   |   |
-----------
   |   |
 {} | {} | {} 
   |   |
-----------
   |   |
 {} | {} | {}
   |   |'''.format(*board[1:10]))

def player_input():
    marker = ' '
    while not (marker == 'X' or marker == 'O'):
        marker = raw_input('Player 1, Choose O or X to play!').upper()
    if marker == 'X':
        return {'Player 1': 'X', 'Player 2': 'O'}
    else:
        return {'Player 2': 'X', 'Player 1': 'O'}

def win_check (board):
    return any(board[a] != ' ' and board[a] == board[b] == board[c] for a, b, c in WIN_COMBINATIONS)

def choose_first(players):
    random_player = 'Player {}'.format(random.randint(1, 2))
    return random_player, players[random_player]

def full_check (board):
    return all(b != ' ' for b in board)

def player_choice(board):
    while True:
        try:
            position = int(raw_input('Choose number input 1-9'))
            if position in range(1, 9) and board[position] == ' ':
                return position
        except ValueError:
            pass

def replay():
    return raw_input('Do you want to play again? Enter Yes or No: ').lower().startswith('y')

def ttt():
    board = [' ' for _ in range(10)]
    players = player_input()
    name, player_marker = choose_first(players)
    print('{} with marker {} will go first.'.format(name, player_marker))
    while True:
        position = player_choice(board)
        board[position] = player_marker
        display_board(board)
        if win_check(board):
            print('Congratulations {}! You have won the game!'.format(name))
            break

        if full_check(board):
            print('Congratulations {} and {}! You have a tie!'.format(players.keys()))
            break

        name = 'Player 1' if name == 'Player 2' else 'Player 2'
        player_marker = players[name]
        print(name, player_marker)

if __name__ == '__main__':
    print('Welcome to Tic Tac Toe Game!')
    while True:
        ttt()
        if not replay():
            break
\$\endgroup\$
2
  • \$\begingroup\$ For the answer that fix this game in line: print('Congratulations {} and {}! You have a tie!'.format(players.keys())) you need to add the players.values() because its dictionary that key talk about the name (player 1) and the values is about the player_marker. \$\endgroup\$
    – mish
    Oct 26, 2019 at 22:36
  • 1
    \$\begingroup\$ I have a serious issue with starting the module with try:raw_input(). If you're running python 2.x it will actually require you to input something. If it's as much of a function as I'd expect based on my experience with python 3.x, then just leave out the parentheses and it should work as desired. \$\endgroup\$
    – Gloweye
    Oct 28, 2019 at 9:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.