简体   繁体   中英

How can I convert the grid of symbols into a list of strings

the input for the to_strings function is the grid so whatever that the grid shows should be converted into a list of strings where input example:

   A B C
 1 . . .
 2 . @ .
 3 . O .

output example:

['...', '.@.', '.O.']
True

first Issue is in this particular function as it does not provide the expected output

    def to_strings(self):
        from itertools import chain

        m_list_tostring=[]
        for i in range(len(self.grid)):
            x=list(chain.from_iterable(self.grid))
            m_list_tostring = ''.join([str(x) for self.grid, i in enumerate(x)])  # to convert the list of characters into a string
        print(x)

    return str(x)

I also have an issue with a particular assertion error that needs to be raised where it checks for invalid inputs (the letter x should indicate the row coordinate of the invalid row) where "invalid character in row x" the code shown below is what i came up with however it gives an error

assert i == self.grid[i], "invalid character in row "+i

I need to add an additional optional argument from_strings to the constructor. If it's present, this argument must be a list of strings where each string gives a row of the board with the character encoding used in the __str__() method, but without the spaces and the coordinate letters.

And also a method to_strings(self) that gives a representation of the board as a list of strings in the same format as that accepted by the __init__() method from the from_strings .

How can i get the expected output?

from string import ascii_uppercase as letters
class Board:
#Dictionary created for the colours and the respected symbols
    points = {'E': '.', 'B': '@', 'W': 'O'}
#Constructor
    def __init__(self,size=19,from_strings=None):
        assert 2 <= size <= 26, "Illegal board size: must be between 2 and 26."
        assert type(from_strings) is list,"input is not a list"
        assert len(from_strings)==size, "length of input list does not match size"
        for i in from_strings:
            assert type(i)==str, "row "+i+" is not a string"
            assert len(i)==size,"length of row "+i+" does not match size"
            #assert i== b[i], "invalid character in row "+i
        self.size = size
        self.grid = [['E'] * size for _ in range(size)]
        self.from_strings = [] if from_strings is None else from_strings
       def get_size(self): #Returns the size of the grid created by the constructor
        return self.size

    def __str__(self): #creating the grid
        padding=' ' #Creating a variable with a space assigned so that it acts as a padding to the rows that have a single digit
        heading = '   ' + ' '.join(letters[:self.size]) #Alphabetical heading is created
        lines = [heading] #adding the alphabetical heading into a list named lines to which the rows will be added later
        for r, row in enumerate(self.grid):
            if len(self.grid)<10: #for the grid with a size less than 10 to add the space to the start of the row for the single digits to be aligned
                line = " " +f'{self.size - r} ' + ' '.join(self.points[x] for x in row)
                lines.append(line)
            else: #for the grids that are larger than 9
                if r>9: #for rows 1 to 9 the single digits are aligned according to the first digit from the right of the two digit rows
                    line =f'{self.size - r} ' + ' '.join(self.points[x] for x in row)
                    line=padding+line #adding the space using the variable padding to the row created
                    lines.append(line) #adding the row to the list of rows
                else: #for the rows 10 onwards - as there is no requirement to add a padding it is not added here
                    line = f'{self.size - r} ' + ' '.join(self.points[x] for x in row)#creation of the row
                    lines.append(line) #adding the newly created row to the list of rows
        return '\n'.join(lines)


    def _to_row_and_column(self, coords):
        # destructure coordinates like "B2" to "B" and 2
        alpha, num = coords
        colnum = ord(alpha) - ord('A') + 1
        rownum = self.size - int(num) + 1
        assert 1 <= rownum <= self.size,"row out of range"
        assert 1 <= colnum <= self.size,'column out of range'
        return rownum, colnum

    def set_colour(self, coords, colour_name):
        rownum, colnum = self._to_row_and_column(coords)
        assert len(coords)==2 or len(coords)==3, "invalid coordinates"
        assert colour_name in self.points,"invalid colour name"
        self.grid[rownum - 1][colnum - 1] = colour_name

    def get_colour(self, coords):
        rownum, colnum = self._to_row_and_column(coords)
        return self.grid[rownum - 1][colnum - 1]

    def to_strings(self):
        from itertools import chain
        m_list_tostring=[]
        for i in range(len(self.grid)):
            x=list(chain.from_iterable(self.grid))
            m_list_tostring = ''.join([str(x) for self.grid, i in enumerate(x)])  # to convert the list of characters into a string
            print(x)
        
        return x

b =Board(3, ["O.O", ".@.", "@O."])
print(b)
print(b.to_strings())
c =Board(b.get_size(), b.to_strings())
print(str(b) == str(c))

for now my code is as such

however I'm not getting the expected output which is shown below

   A B C
 3 O . O
 2 . @ .
 1 @ O .

['O.O', '.@.', '@O.']
True

so the output i got is from my code is:

['E', 'E', 'E', 'E', 'E', 'E', 'E', 'W', 'E']

I executed the code myself and make some changes to get closer to your desired answer.

First,i don't know exactly what this line do, neither what b stands for, so i removed it:

assert i== b[i], "invalid character in row "+i .

Then i looked to _str_ method, that is the method that do the class printing, when you call:

print(b)

It doesn't have any mentions to self.from_strings

Basically in each line, respecting formatting style for the size the of the grid, it is print the correspondent character of the letter you defined in points dictionary as we can see here:

join(self.points[x] for x in row)

Since the points and grid is like this:

self.grid = [['E'] * size for _ in range(size)]

points = {'E': '.', 'B': '@', 'W': 'O'}

It gives the output:

   A B C
 3 . . .
 2 . . .
 1 . . .

Assuming that you when from_strings parameter you want that class print that way, i used conditional to use this

    def __str__(self): #creating the grid
            padding=' ' #Creating a variable with a space assigned so that it acts as a padding to the rows that have a single digit
            heading = '   ' + ' '.join(letters[:self.size]) #Alphabetical heading is created
            lines = [heading] #adding the alphabetical heading into a list named lines to which the rows will be added later
            for r, row in enumerate(self.grid):
                if len(self.grid)<10: #for the grid with a size less than 10 to add the space to the start of the row for the single digits to be aligned
                    if (self.from_strings):
                        line = " " +f'{self.size - r} ' + ' '.join(self.from_strings[r])
                    else: 
                        line = " " +f'{self.size - r} ' + ' '.join(self.points[x] for x in row)
                    lines.append(line)
                else: #for the grids that are larger than 9
                    if r>9: #for rows 1 to 9 the single digits are aligned according to the first digit from the right of the two digit rows
                        if (self.from_strings):
                            line = f'{self.size - r} ' + ' '.join(self.from_strings[r])
                        else:
                            line =f'{self.size - r} ' + ' '.join(self.points[x] for x in row)
                        line=padding+line #adding the space using the variable padding to the row created
                        lines.append(line) #adding the row to the list of rows
                    else: #for the rows 10 onwards - as there is no requirement to add a padding it is not added here
                        if (self.from_strings):
                            line = f'{self.size - r} ' + ' '.join(self.from_strings[r])
                        else: 
                            line = f'{self.size - r} ' + ' '.join(self.points[x] for x in row)#creation of the row
                        lines.append(line) #adding the newly created row to the list of rows
            return '\n'.join(lines)

And use the same logic to to_strings method:

    def to_strings(self):
        padding=' '
        lines = [] 
        for r, row in enumerate(self.grid):
            if self.from_strings : 
                lines.append(''.join(self.from_strings[r]))
            else :
                lines.append(''.join(self.points[x] for x in row))
        return lines

The output is shown like this:

   A B C
 3 O . O
 2 . @ .
 1 @ O .
['O.O', '.@.', '@O.']
True

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM