簡體   English   中英

Python - 從 position 對象的二維數組打印 ASCII 笛卡爾坐標網格

[英]Python - Printing an ASCII cartesian coordinate grid from a 2D array of position objects

非常抱歉,所有人,但這將是一個漫長的過程。 因此,作為我之前關於 STDIN 的查詢的一個分支,不幸的是,似乎沒有足夠多的問題與我的具體問題相似,至少在 Python 中沒有(也沒有使用像 numpy 這樣的東西,這比我的水平高出一點) . 我確實有很多我已經實現的代碼,所以希望這會有所幫助(盡管它不是最干凈的,而且正如我上面提到的,它相當長)。

就目前而言,我的問題是打印出表示 class 對象的二維數組的 ASCII 藝術,以便 ASCII 准確地在簡單的 x,y 笛卡爾坐標網格的方向上描繪它們。

我有幾個相互交互的類,第一個構造包含兩個整數的 position 對象,表示笛卡爾坐標對的 x 和 y:

class Pos:
    def __init__(self, x, y):
        self.x = x
        self.y = y

第二個 class 根據用戶在我程序的不同部分提供的一些大小參數構造一個“正方形”網格,這里實現為一個填充了這些 position 對象的二維數組:

class Grid:
    def __init__(self, size):
        assert size > 0
        self.size = size
        self.grid = []
        #1  Perhaps there is something wrong with my 2D implementation...
        for x in range(size):
            sub_grid = []
            for y in range(size):
                sub_grid.append(Pos(x, y))
            self.grid.append(sub_grid)

在這個 class 中還有一個方法,它打印出網格的 ASCII 藝術作為用戶的外部表示(這是一個混亂的位):

def print(self):
    #  This is the main ASCII-art.
    size_check = self.size - 1
    if self.size > 10:
        print('   +' + ('-' * (((self.size * 2) + 1)) + '+'))
    else:
        print('  +' + ('-' * (((self.size * 2) + 1)) + '+'))
    counter = 0
    #2  ...or perhaps it's something wrong with this iterative condition.
    for x in self.grid[::-1]:
        if self.size > 10:
            if size_check > 9:
                print(self.size - 1 - counter, '|', end=' ')
            else:
                print('', self.size - 1 - counter, '|', end=' ')
        else:
            print(self.size - 1 - counter, '|', end=' ')
        counter += 1
        size_check -= 1
        for y in x:
            #  This is only here to check if the coords are in the correct position in the art.
            ^^if y.x == 5 and y.y == 8:
                print('O ', end='')^^
            else:
                print('. ', end='')
        print('|')
    if self.size > 10:
        print('   +' + ('-' * (((self.size * 2) + 1)) + '+'))
        print('     ', end='')
    else:
        print('  +' + ('-' * (((self.size * 2) + 1)) + '+'))
        print('    ', end='')

    #  This is simply support for grid sizes greater than 10.
    if self.size > 10:
        for x in self.grid:
            if x[0].x <= 9:
                print('', '', end=' ')
            elif x[0].x > 9 and x[0].x < (self.size - 1):
                strng = str(x[0].x)
                print(int(strng[0]), end=' ')
            elif x[0].x == (self.size - 1):
                strng = str(x[0].x)
                print(int(strng[0]))
        print('     ', end='')
        for x in self.grid:
            if x[0].x <= 9:
                print(x[0].x, '', end='')
            elif x[0].x > 9 and x[0].x < (self.size - 1):
                strng = str(x[0].x)
                print(int(strng[1]), end=' ')
            elif x[0].x == (self.size - 1):
                strng = str(x[0].x)
                print(int(strng[1]), end=' ')
    else:
        for x in self.grid:
            if x[0].x < (self.size - 1):
                print(x[0].x, '', end='')
            elif x[0].x == (self.size - 1):
                print(x[0].x, end='')
    print()

我知道這很多,但它成功打印出來的內容看起來像這樣(給定大小 = 10):

  +---------------------+
9 | . . . . . . . . . . |
8 | . . . . . . . . . . |
7 | . . . . . . . . . . |
6 | . . . . . . . . . . |
5 | . . . . . . . . . . |
4 | . . . . . . . . . . |
3 | . . . . . . . . . . |
2 | . . . . . . . . . . |
1 | . . . . . . . . . . |
0 | . . . . . . . . . . |
  +---------------------+
    0 1 2 3 4 5 6 7 8 9

現在這看起來很好,直到我嘗試顯示 position 對象應該位於的位置。 在上面的代碼中,我用 ^^ 標記了一個條件語句,它在坐標 (5, 8) 處打印出一個“O”。 結果看起來像這樣:

  +---------------------+
9 | . . . . . . . . . . |
8 | . . . . . . . . . . |
7 | . . . . . . . . . . |
6 | . . . . . . . . . . |
5 | . . . . . . . . O . |
4 | . . . . . . . . . . |
3 | . . . . . . . . . . |
2 | . . . . . . . . . . |
1 | . . . . . . . . . . |
0 | . . . . . . . . . . |
  +---------------------+
    0 1 2 3 4 5 6 7 8 9

理想的 output 實際上應該是這樣的:

  +---------------------+
9 | . . . . . . . . . . |
8 | . . . . . O . . . . |
7 | . . . . . . . . . . |
6 | . . . . . . . . . . |
5 | . . . . . . . . . . |
4 | . . . . . . . . . . |
3 | . . . . . . . . . . |
2 | . . . . . . . . . . |
1 | . . . . . . . . . . |
0 | . . . . . . . . . . |
  +---------------------+
    0 1 2 3 4 5 6 7 8 9

正如您所看到的,ASCII 藝術以這樣一種方式打印,從外部看起來好像 x 軸和 y 軸已經交換,即使在內部任何 position object 的坐標響應正確。 我在上面的代碼中寫了兩條評論,我推測可能是什么問題。 我最好的猜測是我如何實現網格本身,或者我如何打印藝術作品; 但這就是我需要幫助弄清楚的。

一如既往,我們非常感謝您提供的任何幫助; 我再次道歉!

我建議使用字符串操作而不是直接打印來構建你的線條。 這將使代碼更簡單,並允許將模板字符串中的模式替換為典型的行內容。

例如:

# prepare the empty content
rows = 10
cols = 10
content = [["."]*cols for _ in range(rows)]

# assign values at coordinates as needed (based on your grid)
content[5][8]  = "O"
grid = [(4,1,"H"),(6,3,"L"),(5,2,"E"),(4,6,"R"),(7,4,"L"),(6,6,"W"),(3,6,"L"),(2,6,"D"),(5,6,"O")]
for (y,x,c) in grid: content[y][x] = c

# build frame
width       = len(str(max(rows,cols)-1))
contentLine = "# | values |"

dashes      = "-".join("-"*width for _ in range(cols))
frameLine   = contentLine.replace("values",dashes)
frameLine   = frameLine.replace("#"," "*width)
frameLine   = frameLine.replace("| ","+-").replace(" |","-+")

# print grid
print(frameLine)
for i,row in enumerate(reversed(content),1):
    values = " ".join(f"{v:{width}s}" for v in row)
    line   = contentLine.replace("values",values)
    line   = line.replace("#",f"{rows-i:{width}d}")
    print(line)
print(frameLine)

# x-axis numbers
numLine = contentLine.replace("|"," ")
numLine = numLine.replace("#"," "*width)
colNums = " ".join(f"{i:<{width}d}" for i in range(cols))
numLine = numLine.replace("values",colNums)
print(numLine)

output:

  +---------------------+
9 | . . . . . . . . . . |
8 | . . . . . O . . . . |
7 | . . . . L . . . . . |
6 | . . . L . . W . . . |
5 | . . E . . . O . . . |
4 | . H . . . . R . . . |
3 | . . . . . . L . . . |
2 | . . . . . . D . . . |
1 | . . . . . . . . . . |
0 | . . . . . . . . . . |
  +---------------------+
    0 1 2 3 4 5 6 7 8 9                  

output 行=12,列=15:

   +----------------------------------------------+
11 | .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
10 | .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
 9 | .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
 8 | .  .  .  .  .  O  .  .  .  .  .  .  .  .  .  |
 7 | .  .  .  .  L  .  .  .  .  .  .  .  .  .  .  |
 6 | .  .  .  L  .  .  W  .  .  .  .  .  .  .  .  |
 5 | .  .  E  .  .  .  O  .  .  .  .  .  .  .  .  |
 4 | .  H  .  .  .  .  R  .  .  .  .  .  .  .  .  |
 3 | .  .  .  .  .  .  L  .  .  .  .  .  .  .  .  |
 2 | .  .  .  .  .  .  D  .  .  .  .  .  .  .  .  |
 1 | .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
 0 | .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  |
   +----------------------------------------------+
     0  1  2  3  4  5  6  7  8  9  10 11 12 13 14  

這是一個使用 rust 的實現,分為幾個步驟

1. Grid結構

pub struct Grid {
    cells: Vec<Vec<char>>,
    num_rows: usize,
    num_cols: usize,
}

Grid結構表示字符網格。 它具有三個字段:

  • cells :表示網格中單元格的二維字符向量。
  • num_rows :表示網格中行數的usize
  • num_cols :表示網格中列數的usize

2. Alignment枚舉

#[derive(Debug, PartialEq)]
enum Alignment {
    Left,
    Center,
    Right,
}

Alignment枚舉表示打印網格時單元格值的可能對齊方式。 它具有三種變體:

  • Left :將單元格值左對齊。
  • Center :將單元格值對齊到中心。
  • Right :將單元格值右對齊。

3. new方法

    fn new(num_rows: usize, num_cols: usize, empty_cell_char: char) -> Self {
        let cells = vec![vec![empty_cell_char; num_cols]; num_rows];
        Self {
            cells,
            num_rows,
            num_cols,
        }
    }
}

new方法是Grid結構的構造方法。 它需要三個參數:

  • num_rows :表示網格中行數的usize
  • num_cols :表示網格中列數的usize
  • empty_cell_char :表示要填充空單元格的char的字符。

它創建一個具有給定行數和列數的新網Grid object,並用給定字符填充單元格。

set_cell方法

    fn set_cell(&mut self, row: usize, col: usize, character: char) {
        self.cells[row][col] = character;
    }
}

set_cell方法在網格的特定單元格中設置字符。 它需要三個參數:

  • row :表示單元格行號的usize
  • col :表示單元格列號的usize
  • character :一個char表示要在單元格中設置的字符。

它在給定行和列的單元格中設置字符。

5. draw方法

impl Grid {
    fn draw(
        &self,
        cell_width: usize,
        border_char: char,
        row_separator_char: char,
        col_separator_char: char,
        x_axis_separator_char: char,
        alignment: Alignment,
    ) {
        let frame_top_bottom = (0..self.num_cols)
            .map(|_| border_char.to_string().repeat(cell_width))
            .collect::<Vec<_>>()
            .join(&border_char.to_string());

        let row_template = format!(
            "{row_num}{row_separator}{row_values}{row_values_separator}",
            row_num = "{row_num}",
            row_separator = row_separator_char,
            row_values = "{row_values}",
            row_values_separator = row_separator_char
        );

        let row_num = row_template.replace(
            "{row_num}",
            format!("{:width$}", "", width = cell_width).as_str(),
        );

        let frame_top = row_num.replace("{row_values}", &frame_top_bottom);

        println!("{}", frame_top);

        for (row_num, row) in self.cells.iter().rev().enumerate() {
            let row_num_str = format!("{:width$}", self.num_rows - row_num - 1, width = cell_width);
            let row_values: Vec<String> = row
                .iter()
                .map(|cell| {
                    let aligned_string: String = match alignment {
                        Alignment::Left => format!("{:<width$}", cell, width = cell_width),
                        Alignment::Center => format!("{:^width$}", cell, width = cell_width),
                        Alignment::Right => format!("{:>width$}", cell, width = cell_width),
                    };

                    aligned_string
                })
                .collect();

            println!(
                "{}",
                row_template
                    .replace(
                        "{row_num}",
                        format!("{:<width$}", row_num_str, width = cell_width).as_str()
                    )
                    .replace(
                        "{row_values}",
                        &row_values.join(&col_separator_char.to_string())
                    )
            );
        }
        println!("{}", frame_top);

        let col_nums: Vec<String> = (0..self.num_cols)
            .map(|col| {
                let aligned_string: String = match alignment {
                    Alignment::Left => format!("{:<width$}", col, width = cell_width),
                    Alignment::Center => format!("{:^width$}", col, width = cell_width),
                    Alignment::Right => format!("{:>width$}", col, width = cell_width),
                };

                aligned_string
            })
            .collect();
        let x_axis = row_num.replace(
            "{row_values}",
            &col_nums.join(&x_axis_separator_char.to_string()),
        );
        println!("{}", x_axis);
    }
}

draw方法使用給定的參數將網格打印到控制台。 它需要六個參數:

  • cell_width :表示打印網格時每個單元格寬度的usize

  • border_char :一個char表示用於網格邊界的字符。

  • row_separator_char :一個char表示用作網格行之間分隔符的字符。

  • col_separator_char :一個char表示用作網格列之間分隔符的字符。

  • x_axis_separator_char :一個char ,表示用作網格底部列號之間分隔符的字符。

  • alignment :一個Alignment值,表示打印網格時單元格值的 alignment。

draw方法首先使用border_charcell_width生成網格的頂部和底部邊框。 然后它為網格的每一行創建一個模板,該模板由行號、行分隔符、該行的單元格值和行值分隔符組成。

然后它從下到上遍歷網格的行,並使用模板和當前行號和單元格值為每一行生成一個字符串。 然后它將每一行打印到控制台。

最后,它使用alignmentx_axis_separator_char在網格底部生成列號,並將它們打印到控制台。

6. main function

復制代碼

fn main() {
    let mut grid = Grid::new(3, 3, ' ');
    grid.set_cell(0, 0, 'X');
    grid.set_cell(1, 1, 'O');
    grid.set_cell(2, 2, 'X');
    grid.draw(
        4,
        '+',
        '|',
        ' ',
        ' ',
        Alignment::Right,
    );
}

main function新建一個3行3列的Grid object,並使用set_cell方法設置單元格中的字符。 然后它調用Grid object 上的draw方法將其打印到控制台,單元格寬度為 4,邊框字符為'+' ,行分隔符為'|' 、列分隔符' ' 、x 軸分隔符' '和 alignment Alignment::Right

這是表格中的摘要

描述
定義Grid結構 Grid結構表示具有三個字段的字符網格: cells ,表示網格中單元格的二維字符向量; num_rows ,表示網格中行數的usize num_cols ,一個表示網格中列數的usize
定義Alignment枚舉 Alignment枚舉表示打印網格時單元格值的可能對齊方式。 它具有三種變體: Left ,將單元格值左對齊; Center ,將單元格值與中心對齊; Right ,它將單元格值右對齊。
定義new方法 new方法是Grid結構的構造函數。 它需要三個參數: num_rows ,一個表示網格中行數的usize num_cols ,表示網格中列數的usize empty_cell_char ,一個char表示要填充空單元格的字符。 它創建一個具有給定行數和列數的新網Grid object,並用給定字符填充單元格。
定義set_cell方法 set_cell方法在網格的特定單元格中設置字符。 它需要三個參數: row ,一個usize代表單元格的行號; col ,表示單元格列號的usize character ,一個char表示要在單元格中設置的字符。 它在給定行和列的單元格中設置字符。
定義draw方法 draw方法使用給定的參數將網格打印到控制台。 它有六個參數: cell_width ,一個usize ,表示打印網格時每個單元格的寬度; border_char ,一個char表示用於網格邊界的字符; row_separator_char ,一個char表示用作網格行之間分隔符的字符; col_separator_char ,一個char表示用作網格列之間分隔符的字符; x_axis_separator_char ,一個char表示用作網格底部列號之間分隔符的字符; alignment ,一個Alignment值,表示打印網格時單元格值的 alignment。 它首先使用border_charcell_width生成網格的頂部和底部邊框。 然后它為網格的每一行創建一個模板,該模板由行號、行分隔符、該行的單元格值和行值分隔符組成。 然后它從下到上遍歷網格的行,並使用模板和當前行號和單元格值為每一行生成一個字符串。 然后它將每一行打印到控制台。 最后,它使用alignmentx_axis_separator_char在網格底部生成列號,並將它們打印到控制台。
定義main function main function新建一個3行3列的Grid object,並使用set_cell方法設置單元格中的字符。 然后它調用Grid object 上的draw方法將其打印到控制台,單元格寬度為 4,邊框字符為'+' ,行分隔符為 `'

這是表格的超摘要

描述
定義Grid結構 Grid結構表示具有三個字段的字符網格: cells ,表示網格中單元格的二維字符向量; num_rows ,表示網格中行數的usize num_cols ,一個表示網格中列數的usize
定義Alignment枚舉 Alignment枚舉表示打印網格時單元格值的 alignment。 它具有三個變體: LeftCenterRight
定義new方法 new方法創建一個新的Grid object 具有給定的行數和列數,並用給定的字符填充單元格。
定義set_cell方法 set_cell方法在網格的特定單元格中設置字符。
定義draw方法 draw方法使用給定的參數將網格打印到控制台。
定義main function main function 創建一個Grid object 並在其單元格中設置字符。 然后它使用draw方法將網格打印到控制台。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM