2
\$\begingroup\$

I am making my first object-oriented program in python and I am having trouble with the __str__ part of Board() class. I want it to be a visual representation of the tic-tac-toe board. I have achieved this but the code looks ridiculous and I know there must be a better way! Here is my project so far:

class Space(object):

    def __init__(self, state="x"):
        self.state = state

    state_names = ['empty', 'x', 'o']

    def __str__(self):

        return str(self.state)

    def change_state(self, string):
        if string == 'x':
            self.state = 'x'
        else:
            self.state = 'o'

class Board(object):

    def __init__(self):
        self.spaces = []
        for num in range(0,9):
            space = Space()
            self.spaces.append(space)
        board = self.spaces

    def __str__(self):
        res = []
        for space in self.spaces:
            res.append(str(space))
        return '   |   |'  + '\n ' + res[6] + ' | ' + res[7] + ' | ' + res[8] + '\n   |   |' + '\n-----------' + '\n   |   |' + '\n ' + res[3] + ' | ' + res[4] + ' | ' + res[5] + '\n   |   |' + '\n-----------' + '\n   |   |' + '\n ' + res[0] + ' | ' + res[1] + ' | ' + res[2] + '\n   |   |' 

the default output should (and does) look like this:

   |   |
 x | x | x
   |   |
-----------
   |   |
 x | x | x
   |   |
-----------
   |   |
 x | x | x
   |   |
\$\endgroup\$

migrated from stackoverflow.com Jul 3 '16 at 10:30

This question came from our site for professional and enthusiast programmers.

2
\$\begingroup\$

Though not according the DRY principle and debatable for PEP8, I would do something like (Readability counts):

def __str__(self):
    s = ('   |   |   \n' +
         ' # | # | # \n' +
         '   |   |   \n' +
         '---+---+---\n' +
         '   |   |   \n' +
         ' # | # | # \n' +  
         '   |   |   \n' +
         '---+---+---\n' +
         '   |   |   \n' +
         ' # | # | # \n' +
         '   |   |   '  ).replace('#', '{}')
    return s.format(* map(str, self.spaces))

(btw.: I messed up the order of self.spaces)

(note: the asterisk in s.format(* map(... unpacks the list returned by map into individual arguments for format)

A bit more 'DRYer' solution would be:

    l1 = '   |   |   '
    l2 = ' {} | {} | {} '
    l3 = '---+---+---'
    s = '\n'.join([l1, l2, l1, l3, l1, l2, l1, l3, l1, l2, l1])
\$\endgroup\$
  • \$\begingroup\$ Quite readable! I highly recommend the first approach over the second though, although perhaps using a multi-line string instead. If the layout would have to change, this is easy to change. The "DRY" (in quotes, as I do not believe it to be DRY) approach would be harder to update. \$\endgroup\$ – Sjoerd Job Postmus Jul 3 '16 at 16:28
2
\$\begingroup\$

You can hugely reduce your __str__ using loops, e.g. using join() and a couple of generator expressions:

def __str__(self):
    return '\n-----------\n'.join('   |   |\n '+' | '.join(str(self.spaces[x]) for x in [0+y, 1+y, 2+y])+'\n   |   |' for y in [6, 3, 0])

Output:

   |   |
 x | x | x
   |   |
-----------
   |   |
 x | x | x
   |   |
-----------
   |   |
 x | x | x
   |   |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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