ThoughtWorks公司——算法岗位作业题(计算机生成迷宫)

                           ThoughtWorks公司算法岗位面试经历总结

一、面试的具体流程:

1、面试时间:8月22日(周三)15:00

2、公司地址:成都市高新区天府软件园E1-1 7楼(请从1号门进入)

3、面试流程:技术面试 1H

4、面试经历:

(1)技术面:自带笔记本,在原来的作业题(计算机自动生成迷宫的基础上)添加新的2个功能,及时编程,时限30分钟;

  • 介绍一个自己最感兴趣的项目(导师的自然科学基金项目),详说技术路线(水平集与U-Net)
  • 介绍自己的论文具体原理;
  • 面向对象编程与面向过程编程的区别
  • 介绍一下卷积神经网络的常见几个模型,具体说说VGG,ResNet两者间的区别
  • 神经网络如果卷积层数无穷多,会出现什么后果?
  • 谈谈机器学习与深度学习之间的区别
  • 机器学习中的Stacking融合技术原理是什么?为什么会分块?

(2)HR面

  • 自我介绍(1分钟)
  • 你最大的优势是什么?
  • 详细介绍一个比赛?
  • 别人是如何评价你的?缺点是什么?
  • 成绩如何?
  • 遇到挑战如何处理,有没有与同事发生较大冲突?有的话如何解决?
  • 比实验室其他人的优势是什么?
  • 做过最有意义(最有挑战)的项目是什么?最困难的一段学习经历是什么?
  • 平时是如何学习的?
  • 遇到最大的挫折是什么?
  • 为什么选择跨专业学计算机?
  • 你平时喜欢做什么?看过哪些书?最近在看什么书?
  • 是否愿意做开发岗位?

(3)面试结束时,面试官问:你还有什么想问的?(面试官面试其实想知道两件事:你能干这活不?你愿意在我们公司干这活不?)

  • 请问公司对我这个职位的期望是什么?(问了)
  • 请问入职后是否有相关的职位技能培训?(问了)
  • 团队成员有多少人?核心工作是什么?(问了)
  • 贵公司未来5年的发展方向是什么?(问了)
  • 您能形容一下部门的工作氛围吗,以及部门有团建活动吗?
  • 这个职位的发展路径一般是怎么样的呢?(问了)
  • 能告诉我现在公司/部门面临的最大机遇/挑战是什么吗?
  • 这个职位为什么空缺?
  • 这个职位换过多少人?主要原因是什么?
  • 目前这个职位最紧要的任务是什么?如果我有幸进入贵公司,您希望我三个月完成哪些工作?(问了)
  • 贵公司/部门希望通过这个职位实现的长期目标是什么?
  • 这一职位面临的最大困难是什么?
  • 贵公司最近有什么重大规划?
  • 请问在这个职位做出出色业绩的员工,将有什么发展机会?大约多长时间能实现?能举个例子吗?
  • 贵公司在产品与服务上的成功之处是什么?
  • 这个职位的工作业绩是如何评估的?(问了)
  • 为什么这个职位仍然空缺着?
  • 我有多少假期,以及加班情况?
  • 公司/部门的目标有哪些?
  • 贵公司什么时候可以答复面试结果?

5、内心戏与总结(已挂)

         提前一天去的成都,晚上也刷了很多面经,思特沃克算是我的第一次现场面试,手撕代码。可惜两个功能知道怎么做,未在30分钟实现,感觉自己还是太菜了。

(1)内推校招作业题的通过标准(我用的是Python)

  • 良好的编程习惯,特别注重细节,小到一个空格,缩进,注释的方式都会被怼;
  • 仅仅实现功能,未必能通过筛选,必须对代码进行优化,如面向对象编程,最好封装成类,可以直接调用;
  • 能展现出自己编程的个性
  • MarkDown的编辑说明,网易云笔记的使用,如何写readme说明文档

(2)现场手撕代码,时限30分钟

  • 在原来的作业题的基础上,继续完善,并不能破坏原来的结构;
  • 最好写成类函数的形式,方便调用,可读性强;
  • 模式是什么?几个面试官坐在你对面,给你两张A4纸,上面是需要添加的功能说明,先理解,如有不懂可以提问,知道怎么做后,先给面试官讲一下自己的思路,再进行编程实现,30分钟。

(3)为什么会挂?

个人觉得主要还是编程没有实现,印象分肯定差了不少。加上后面的面试表现不太好,哎,还得努力

 

二、作业题(通过筛选标准)

       完整版代码(作业题+面试附加题)已上传至百度云盘:https://pan.baidu.com/s/1l12swNRooGAOwwgKlvQofg 密码:swa2 ,内容如下:

一、作业内容

* 本作业限时3天完成

* 作业完成后必须附上 Readme 纯文本文档(推荐使用 markdown 排版)

* Readme文档中必须描述如何运行单元测试或主程序来证明作业的正确性(至少针对测试用例输入能够得到对应输出)

* 作业的输入和输出必须和题目的测试用例输出严格一致

* 可以选用擅长的语言完成,例如C、C++、Java、C#、Javascript、Python、Scala等

*请注意作业的保密性,不要将作业放在Git等渠道上面


校招题目
       用计算机生成迷宫是一个很有趣的任务。我们可以用 ​道路网格(Road Grid)​ ​来表示迷宫的道路,那么 3 x 3 的 ​道路网格​(​图-1 左​)可以对应一个 7 x 7 的 ​渲染网格(Render Grid)​ ——​图-1 右​ 的方式(迷宫的墙是灰色的,道路是白色的):


连通 ​道路网格​ 有如下的约束条件:

● 每一个 ​cell​ 只能够直接与相邻正南、正北、正东、正西的 ​cell​ 连通。不能够和其他的 ​cell​ 连通。

● 两个 ​cell​ 之间的连通一定是双向的。即 ​cell(0,0) ​和 ​cell(1,0)​ 连通等价于 ​cell(1,0)​ 和cell(0,0)​ 的连通。


要求1:将迷宫渲染为字符串

       现在我们希望你书写程序,将给定迷宫的 ​道路网格​,渲染为字符串输出。例如,其使用方式如下(伪代码,仅做演示,实际实现时请应用实际语言的编程风格)

Maze maze = MazeFactory.Create(command);
String mazeText = maze.Render();


其中 command 是一个字符串。它的定义如下:

● 第一行是迷宫 ​道路网格​ 的尺寸。例如 3 x 3 的迷宫为 ​3 3​,而 5 x 4 的迷宫为 ​5 4​(5 行 4 列)​。

● 第二行是迷宫 ​道路网格​ 的连通性定义。如果 ​cell(0,1) ​和​ cell(0,2) ​是连通的,则表示为:0,1 0,2​,多个连通以分号 ​; ​隔开。

例如,如果给定输入:

3 3
0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1


则输出字符串为(如果当前 渲染网格 为墙壁,则输出 [W] 如果为道路则输出 [R]):

[W] [W] [W] [W] [W] [W] [W]
[W] [R] [W] [R] [R] [R] [W]
[W] [R] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [R] [R] [W]
[W] [W] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [W] [R] [W]
[W] [W] [W] [W] [W] [W] [W]

要求2:检查输入的有效性
在处理输入的时候需要检查输入的有效性。需要检查的有效性包括如下的几个方面:

● 无效的数字:输入的字符串无法正确的转换为数字。此时,该函数的输出为字符串 ​”Invalid number format​. ​”

● 数字超出预定范围:数字超出了允许的范围,例如为负数等。此时,该函数的输出为字符串”Number out of range​. ​”

● 格式错误:输入命令的格式不符合约定。此时,该函数的输出为字符串​ ”Incorrect command format​. ​”

● 连通性错误:如果两个网格无法连通,则属于这种错误。此时,该函数的输出为字符串​ ”Maze format error.”

当多个问题同时出现时,报告其中一个错误即可。
 

 

二、文档说明

0. 写在前面

该方法主要功能包括以下几个部分:

  • 利用Python实现迷宫字符串:类的封装、输入数据的有效性判断
  • 测试数据的输入有两种输入方式:手动输入与直接加载(考虑到第二行输入的不便性)
  • 个性化输出结果:将迷宫中的路径标记为红色,便于检查

1. 运行环境

Windows(64位) + PyCharm + Anaconda(Python3.5.2)

2. 代码如何运行

(1) 代码说明

1) 该代码已封装为类Maze,具体函数见文件getMaze.py。其中包括两个属性:num与command,分别表示为:

num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,而5 x 4的迷宫为5 4(5行4列)
command: 迷宫道路网格的连通性定义。如果cell(0,1)和cell(0,2) 是连通的,则表示为:0,1 0,2,多个连通以分号;隔开。

2)另外,类Maze主要包含三个功能:initial_maze,getFinalMaze与showResult,分别表示为:

  • Maze.initial_maze():初始化迷宫&道路网格
  • Maze.getFinalMaze():将迷宫渲染为字符串
  • Maze.showResult():矩阵形式打印最终迷宫字符串

3)getMaze.py还包括另外三个函数:judge_num,dataInput_byHand与dataInput_withFile,其功能分别表示为:

  • judge_num():判断迷宫道路网格的尺寸的输入是否合法
  • dataInput_byHand():手动输出5种不同的测试数据
def dataInput_byHand():
    """
    输入:
        num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,(3行3列),即num = [3,3]
        command:迷宫道路网格的连通性定义。如果cell(0,1)和cell(0,2) 是连通的,则表示为:0,1 0,2 当多个连通,则以分号;隔开

    输出:
        num, command
    """
    # step1: 输入迷宫的行列数,中间用空格隔开
    while True:
        num = [int(i) for i in input().split()]
        # 判断输入数据是否合法
        if judge_num(num):
            break
        else:
            num = [i for i in input().split()]
            if judge_num(num):
                break

    # step2: command的输入
    command = list(input().split(';'))

    return num,command
  • dataInput_withFile():直接加载已准备好5种的测试文档
def dataInput_withFile():

    # 请选择5种不同的待测试的文件
    data = list(open('data/data_正确输入.txt').read().split('\n'))                    # 正确输入
    # data = list(open('data/data_Incorrect command format.txt').read().split('\n'))   # 格式错误
    # data = list(open('data/data_Invalid number format.txt').read().split('\n'))      # 无效的数字
    # data = list(open('data/data_Mazeformat error.txt').read().split('\n'))           # 连通性错误
    # data = list(open('data/data_Number out of range.txt').read().split('\n'))        # 数字超出预定范围

    num = [i for i in data[0].split()]
    command = list(data[1].split(';'))

    # 判断num的输入是否存在错误!
    if len(num) != 2:
        print('Invalid number format.')
        quit()
    else:
        # 判断读入行列数是否为数字
        if num[0].lstrip('-').isdigit() == 0 or num[1].lstrip('-').isdigit() == 0:
            print('Invalid number format.')
            quit()
        else:
            num = [int(i) for i in num]
    return num, command

4)主函数为:

# 主函数
if __name__ == "__main__":

    # step1: 数据输入
    # num, command = dataInput_byHand() # 手动输入测试数据
    num, command = dataInput_withFile() # 直接加载5种txt格式的测试数据

    # step2: 调用函数
    maze = Maze(num, command) # 定义类maze
    initial_Result = maze.initial_maze() # 初始化迷宫
    final_Result = maze.getFinalMaze(initial_Result) # 迷宫渲染为字符串

    # step3: 输出结果
    maze.showResult(final_Result) # 矩阵形式打印最终迷宫字符串

(2)测试数据

1)data_正确输入

3 3
0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1

2)data_Incorrect command format

3 3
0,1 0,2aa;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1

3)data_Invalid number format

3 a
0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1

4)data_Mazeformat error

3 3
0,1 1,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1

5)data_Number out of range

3 -1
0,1 0,2;0,0 1,0;0,1 1,1;0,2 1,2;1,0 1,1;1,1 1,2;1,1 2,1;1,2 2,2;2,0 2,1

(3)运行结果

1)data_正确输入

[W] [W] [W] [W] [W] [W] [W]
[W] [R] [W] [R] [R] [R] [W]
[W] [R] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [R] [R] [W]
[W] [W] [W] [R] [W] [R] [W]
[W] [R] [R] [R] [W] [R] [W]
[W] [W] [W] [W] [W] [W] [W]

2)data_Incorrect command format

Incorrect command format.

3)data_Invalid number format

Invalid number format.

4)data_Mazeformat error

Mazeformat error.

5)data_Number out of range

Number out of range.

(4)个性化输出结果

为了方便直观检查迷宫生成是否合理,该方法将"[R]"标记为红色,函数如下:

# 矩阵形式打印最终迷宫字符串
    def showResult(self,result):
        """
        输入:
            result: 渲染后的迷宫字符串二维列表

        输出:
            矩阵形式打印出结果
        """

        # 如果添加颜色,代码如下:
        for i in range(len(result)):
            count = 0
            for j in result[i]:
                if j == '[R]':
                    print('\033[5;31m' + j + ' \033[0m', end='') # 将"[R]"标记为红色
                    count += 1
                else:
                    print(j, end=' ')
                    count += 1

                if (count % len(result[0]) == 0):
                    print(end='\n')

        # 如果不添加颜色,代码如下:
        # for i in range(len(result)):
        #     print(" ".join(str(j) for j in result[i]))

运行结果如下:

  • 当第一行输入为:3 3,第二行不变时。

 

  • 当第一行输入为:6 8,第二行不变时。

     

三、具体代码 

# !/usr/bin/python3.5.2
# -*- coding: UTF-8 -*-

# 计算机生成迷宫,再渲染为字符串
class Maze:
    def __init__(self, num, command):
        """
        初始化:
            num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3​,而5 x 4的迷宫为5 4(5行4列)
            command: 迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​,多个连通以分号;隔开。
        """
        self.num = num
        self.command = command

# 初始化迷宫&道路网格
    def initial_maze(self):
        """
         输入:
             self.num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3​,而5 x 4的迷宫为5 4(5行4列)

         输出:
             result: 初始的迷宫
         """
        row, col = self.num[0], self.num[1]  # 获取行数,列数
        result = [['[W]']*(2*col+1) for index in range(2*row+1)] # 初始化迷宫
        for i in range (row):
            for j in range(col):
                result[2*i+1][2*j+1] = '[R]'# 初始化输出
        return result


# 迷宫渲染为字符串
    def getFinalMaze(self, result):
        """
        输入:
           self.num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,而5 x 4的迷宫为5 4(5行4列)
           self.command: 迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​,多个连通以分号;隔开。
           result: 初始的迷宫

        输出:
           result: 渲染后的迷宫,即根据self.command联通信息渲染后的迷宫
        """
        row, col = self.num[0], self.num[1]  # 获取行数,列数

        #  step1: 判断迷宫道路网格的连通性定义输入是否合法
        if row < 0 or col < 0:
            print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
            quit()  # 判断行列数是否合法

        for i in range(len(self.command)):  # 进入循环
            # 判断每个分开字符长度
            if '-' in self.command[i]:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断每个分开字符长度
            elif len(self.command[i]) != 7:
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

            # 判断读入的点是否能转换为数字
            elif self.command[i][0].isdigit() == 0 or self.command[i][2].isdigit() == 0 or self.command[i][4].isdigit() == 0 or self.command[i][6].isdigit() == 0:
                print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
                quit()

            # 判断读入的点是否合法
            elif int(self.command[i][0]) < 0 or int(self.command[i][2]) < 0 or int(self.command[i][4]) < 0 or int(self.command[i][6]) < 0:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断读入的点是否超出范围
            elif int(self.command[i][0]) >= row or int(self.command[i][4]) >= row or int(self.command[i][2]) >= col or int(self.command[i][6]) >= col:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断读入数据格式是否正确
            elif self.command[i][1] != ',' and self.command[i][5] != ',':
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

            # 判断读入数据格式是否正确
            elif self.command[i][3] != ' ':
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

        # step2: 迷宫渲染为字符串
            x = abs(int(self.command[i][0]) - int(self.command[i][4]))
            y = abs(int(self.command[i][2]) - int(self.command[i][6]))

            # 判断读入点是否连通
            if (x + y) > 1:
                print('\033[5;31m' + 'Mazeformat error.' + ' \033[0m')
                quit()

            # 连通的是同一个点跳过
            if (x + y) == 0:
                break
            if x == 0:
                result[int(self.command[i][0]) * 2 + 1][min(int(self.command[i][2]), int(self.command[i][6])) * 2 + 2] = '[R]'
            else:
                result[min(int(self.command[i][0]), int(self.command[i][4])) * 2 + 2][int(self.command[i][2]) * 2 + 1] = '[R]'
        return result

# 矩阵形式打印最终迷宫字符串
    def showResult(self,result):
        """
        输入:
            result: 渲染后的迷宫字符串二维列表

        输出:
            矩阵形式打印出结果
        """

        # 如果添加颜色,代码如下:
        for i in range(len(result)):
            count = 0 # 用于计数
            for j in result[i]:
                if j == '[R]':
                    print('\033[5;31m' + j + ' \033[0m', end='') # 将"[R]"标记为红色
                    count += 1
                else:
                    print(j, end=' ')
                    count += 1

                if (count % len(result[0]) == 0): # 换行判断
                    print(end='\n')

        # 如果不添加颜色,代码如下:
        # for i in range(len(result)):
        #     print(" ".join(str(j) for j in result[i]))


# 判断迷宫道路网格的尺寸的输入是否合法
def judge_num(num):
    index = False
    if len(num) == 2:
        # 判断读入行列数是否为数字
        if str(num[0]).lstrip('-').isdigit() == 1 and str(num[1]).lstrip('-').isdigit() == 1:
            index = True
    return index

def dataInput_byHand():
    """
    输入:
        num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,(3行3列),即num = [3,3]
        command:迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​当多个连通,则以分号;隔开

    输出:
        num, command
    """
    # step1: 输入迷宫的行列数,中间用空格隔开
    while True:
        num = [int(i) for i in input().split()]
        # 判断输入数据是否合法
        if judge_num(num):
            break
        else:
            num = [i for i in input().split()]
            if judge_num(num):
                break

    # step2: command的输入
    command = list(input().split(';'))

    return num,command


def dataInput_withFile():

    # 请选择5种不同的待测试的文件
    data = list(open('data/data_正确输入.txt').read().split('\n'))                    # 正确输入
    # data = list(open('data/data_Incorrect command format.txt').read().split('\n'))   # 格式错误
    # data = list(open('data/data_Invalid number format.txt').read().split('\n'))      # 无效的数字
    # data = list(open('data/data_Mazeformat error.txt').read().split('\n'))           # 连通性错误
    # data = list(open('data/data_Number out of range.txt').read().split('\n'))        # 数字超出预定范围

    num = [i for i in data[0].split()]
    command = list(data[1].split(';'))

    # 判断num的输入是否存在错误!
    if len(num) != 2:
        print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
        quit()
    else:
        # 判断读入行列数是否为数字
        if num[0].lstrip('-').isdigit() == 0 or num[1].lstrip('-').isdigit() == 0:
            print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
            quit()
        else:
            num = [int(i) for i in num]
    return num, command



# 主函数
if __name__ == "__main__":

    # step1: 数据输入
    # num, command = dataInput_byHand() # 手动输入测试数据
    num, command = dataInput_withFile() # 直接加载5种txt格式的测试数据

    # step2: 调用函数
    maze = Maze(num, command) # 定义类maze
    initial_Result = maze.initial_maze() # 初始化迷宫
    final_Result = maze.getFinalMaze(initial_Result) # 迷宫渲染为字符串

    # step3: 输出结果
    maze.showResult(final_Result) # 矩阵形式打印最终迷宫字符串

 

三、福利——手撕代码(添加的两个功能)

1、题目内容

 2、代码实现

      尽管知道自己已经挂了,但还是想实现以下,内心还是有点不甘。代码本身不难,就是4连通区域的分析,双重循环判断,当时我错在了Python中二维列表赋值,result与tmp,因为需要判断,这会改变其中一个二维列表中的值,另一个二维列表也会变化!面试过程中调试知道有这个问题,没能及时找到合适的解决方案。详细可以参考博客:Python中的赋值、浅拷贝与深拷贝。现在我更改代码后结果如下:

新增功能后的代码如下(完整版,未优化封装,没过实在是没心情再封装咯):

# !/usr/bin/python3.5.2
# -*- coding: UTF-8 -*-
import  copy

# 计算机生成迷宫,再渲染为字符串
class Maze:
    def __init__(self, num, command):
        """
        初始化:
            num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3​,而5 x 4的迷宫为5 4(5行4列)
            command: 迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​,多个连通以分号;隔开。
        """
        self.num = num
        self.command = command

# 初始化迷宫&道路网格
    def initial_maze(self):
        """
         输入:
             self.num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3​,而5 x 4的迷宫为5 4(5行4列)

         输出:
             result: 初始的迷宫
         """
        row, col = self.num[0], self.num[1]  # 获取行数,列数
        result = [['[W]']*(2*col+1) for index in range(2*row+1)] # 初始化迷宫
        for i in range (row):
            for j in range(col):
                result[2*i+1][2*j+1] = '[R]'# 初始化输出
        return result


# 迷宫渲染为字符串
    def getFinalMaze(self, result):
        """
        输入:
           self.num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,而5 x 4的迷宫为5 4(5行4列)
           self.command: 迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​,多个连通以分号;隔开。
           result: 初始的迷宫

        输出:
           result: 渲染后的迷宫,即根据self.command联通信息渲染后的迷宫
        """
        row, col = self.num[0], self.num[1]  # 获取行数,列数

        #  step1: 判断迷宫道路网格的连通性定义输入是否合法
        if row < 0 or col < 0:
            print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
            quit()  # 判断行列数是否合法

        for i in range(len(self.command)):  # 进入循环
            # 判断每个分开字符长度
            if '-' in self.command[i]:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断每个分开字符长度
            elif len(self.command[i]) != 7:
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

            # 判断读入的点是否能转换为数字
            elif self.command[i][0].isdigit() == 0 or self.command[i][2].isdigit() == 0 or self.command[i][4].isdigit() == 0 or self.command[i][6].isdigit() == 0:
                print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
                quit()

            # 判断读入的点是否合法
            elif int(self.command[i][0]) < 0 or int(self.command[i][2]) < 0 or int(self.command[i][4]) < 0 or int(self.command[i][6]) < 0:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断读入的点是否超出范围
            elif int(self.command[i][0]) >= row or int(self.command[i][4]) >= row or int(self.command[i][2]) >= col or int(self.command[i][6]) >= col:
                print('\033[5;31m' + 'Number out of range.' + ' \033[0m')
                quit()

            # 判断读入数据格式是否正确
            elif self.command[i][1] != ',' and self.command[i][5] != ',':
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

            # 判断读入数据格式是否正确
            elif self.command[i][3] != ' ':
                print('\033[5;31m' + 'Incorrect command format.' + ' \033[0m')
                quit()

        # step2: 迷宫渲染为字符串
            x = abs(int(self.command[i][0]) - int(self.command[i][4]))
            y = abs(int(self.command[i][2]) - int(self.command[i][6]))

            # 判断读入点是否连通
            if (x + y) > 1:
                print('\033[5;31m' + 'Mazeformat error.' + ' \033[0m')
                quit()

            # 连通的是同一个点跳过
            if (x + y) == 0:
                break
            if x == 0:
                result[int(self.command[i][0]) * 2 + 1][min(int(self.command[i][2]), int(self.command[i][6])) * 2 + 2] = '[R]'
            else:
                result[min(int(self.command[i][0]), int(self.command[i][4])) * 2 + 2][int(self.command[i][2]) * 2 + 1] = '[R]'
        return result

# 矩阵形式打印最终迷宫字符串
    def showResult(self,result):
        """
        输入:
            result: 渲染后的迷宫字符串二维列表

        输出:
            矩阵形式打印出结果
        """

        # 如果添加颜色,代码如下:
        for i in range(len(result)):
            count = 0 # 用于计数
            for j in result[i]:
                # 迷宫的判断1
                if j != '[W]' and j != '[T]':  # j == '[R]'
                    print('\033[5;31m' + j + ' \033[0m', end='') # 将"[R]"标记为红色
                    count += 1
                elif j == '[T]':
                    print('\033[1;32m' + j + ' \033[0m', end='')  # 将"[R]"标记为红色
                    count += 1
                else:
                    print(j, end=' ')
                    count += 1

                if (count % len(result[0]) == 0): # 换行判断
                    print(end='\n')

        # 如果不添加颜色,代码如下:
        # for i in range(len(result)):
        #     print(" ".join(str(j) for j in result[i]))


# 判断迷宫道路网格的尺寸的输入是否合法
def judge_num(num):
    index = False
    if len(num) == 2:
        # 判断读入行列数是否为数字
        if str(num[0]).lstrip('-').isdigit() == 1 and str(num[1]).lstrip('-').isdigit() == 1:
            index = True
    return index

def dataInput_byHand():
    """
    输入:
        num: 迷宫道路网格的尺寸。例如 3 x 3 的迷宫为3 3,(3行3列),即num = [3,3]
        command:迷宫道路网格的连通性定义。如果cell(0,1)和​cell(0,2) 是连通的,则表示为:0,1 0,2​当多个连通,则以分号;隔开

    输出:
        num, command
    """
    # step1: 输入迷宫的行列数,中间用空格隔开
    while True:
        num = [int(i) for i in input().split()]
        # 判断输入数据是否合法
        if judge_num(num):
            break
        else:
            num = [i for i in input().split()]
            if judge_num(num):
                break

    # step2: command的输入
    command = list(input().split(';'))

    return num,command


def dataInput_withFile():

    # 请选择5种不同的待测试的文件
    # data = list(open('data/data_正确输入.txt').read().split('\n'))                    # 正确输入
    # data = list(open('data/data_Incorrect command format.txt').read().split('\n'))   # 格式错误
    # data = list(open('data/data_Invalid number format.txt').read().split('\n'))      # 无效的数字
    # data = list(open('data/data_Mazeformat error.txt').read().split('\n'))           # 连通性错误
    # data = list(open('data/data_Number out of range.txt').read().split('\n'))        # 数字超出预定范围

    data = list(open('data/maze_plus2.txt').read().split('\n'))  # 迷宫拐弯


    num = [i for i in data[0].split()]
    command = list(data[1].split(';'))

    # 判断num的输入是否存在错误!
    if len(num) != 2:
        print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
        quit()
    else:
        # 判断读入行列数是否为数字
        if num[0].lstrip('-').isdigit() == 0 or num[1].lstrip('-').isdigit() == 0:
            print('\033[5;31m' + 'Invalid number format.' + ' \033[0m')
            quit()
        else:
            num = [int(i) for i in num]
    return num, command



def calNum(result,i,j):

    tmp = copy.deepcopy(result)  # 采用深拷贝,防止传入的值被影响
    sum = 0
    if tmp[i][j + 1] == '[R]':
        sum += 1
    if tmp[i][j - 1] == '[R]':
        sum += 1
    if tmp[i + 1][j] == '[R]':
        sum += 1
    if tmp[i - 1][j] == '[R]':
        sum += 1
    return sum


def get4Union(result):
    row, col = len(result), len(result[0])
    tmp = copy.deepcopy(result)
    for i in range(1, row-1):
        for j in range(1, col-1):
            if tmp[i][j] == '[R]':
                index = calNum(result, i, j)
                if index >= 1:
                    tmp[i][j] = '['+str(index)+']'
    return tmp

# 验收作业二
def checkPoint(result, i, j):
    tmp = copy.deepcopy(result)
    index = False
    if tmp[i][j + 1] == '[W]' and tmp[i + 1][j] == '[W]' and tmp[i - 1][j] != '[W]' and tmp[i][j - 1] != '[W]': # 右下为[W]
        index = True

    if tmp[i][j + 1] == '[W]' and tmp[i + 1][j] != '[W]' and tmp[i - 1][j] == '[W]' and tmp[i][j - 1] != '[W]': # 右上为[W]
        index = True

    if tmp[i][j + 1] != '[W]' and tmp[i + 1][j] == '[W]' and tmp[i - 1][j] != '[W]' and tmp[i][j - 1] == '[W]': # 左下为[W]
        index = True

    if tmp[i][j + 1] != '[W]' and tmp[i + 1][j] != '[W]' and tmp[i - 1][j] == '[W]' and tmp[i][j - 1] == '[W]': # 左上为[W]
        index = True

    return index

def setTower(result):
    row, col = len(result), len(result[0])
    tmp = copy.deepcopy(result)
    for i in range(1, row-1):
        for j in range(1, col-1):
            if tmp[i][j] == '[W]' and checkPoint(result, i, j):
                tmp[i][j] = '[T]'
    return tmp



# 主函数
if __name__ == "__main__":

    # step1: 数据输入
    # num, command = dataInput_byHand() # 手动输入测试数据
    num, command = dataInput_withFile() # 直接加载5种txt格式的测试数据

    # step2: 调用函数
    maze = Maze(num, command) # 定义类maze
    initial_Result = maze.initial_maze() # 初始化迷宫
    final_Result = maze.getFinalMaze(initial_Result) # 迷宫渲染为字符串
    print("\n第一步:原始结果为:\n")
    print(final_Result)

    # step3: 输出结果
    print("\n第二步:个性化输出结果:\n")
    maze.showResult(final_Result) # 矩阵形式打印最终迷宫字符串

    ###################### 题目二 ######################
    print("\n第三步:输出结果1(4连通区域分析):\n")
    myres1 = get4Union(final_Result)
    maze.showResult(myres1)

    print("\n第四步:输出结果2(拐点分析):\n")
    myres2 = setTower(myres1)
    maze.showResult(myres2)

 

3、在面试的前一晚,看了一些面经:http://www.job592.com/pay/comms81356.html,看到一篇文章中写到,面试追加的题目为,设计一个机器人去行走这个迷宫,并给出其动态变化。这个功能函数代码如下:

################################ 走迷宫 ####################################
# 矩阵处理
def matrix01(result):
    row, col = len(result), len(result[0])
    if row==0:
        quit()
    elif row>0:
        for i in range(row):
            for j in range(col):
                if result[i][j]=='[W]':
                    result[i][j] = 0
                elif result[i][j]=='[R]':
                    result[i][j] = 1
    return result

# 用来判断坐标是否合法
def check_valid(mg, x, y):
    if x >= 0 and x < len(mg) and y >= 0 and y < len(mg[0]) and mg[x][y] == 1:
        return True
    else:
        return False


# 迷宫结果优化
def process(step):
    # 先识别哪些无路可走的点的下一个点
    change_records = []
    for i in range(len(step) - 1):
        if (abs(step[i][0] - step[i + 1][0]) == 0 and abs(step[i][1] - step[i + 1][1]) == 1) or \
                (abs(step[i][0] - step[i + 1][0]) == 1 and abs(step[i][1] - step[i + 1][1]) == 0):
            pass
        else:
            change_records.append(i + 1)

    # 然后根据这些点识别出这个点的最远回退点
    clip_nums = []
    for i in change_records:
        for j in range(i):
            if (abs(step[j][0] - step[i][0]) == 0 and abs(step[j][1] - step[i][1]) == 1) or \
                    (abs(step[j][0] - step[i][0]) == 1 and abs(step[j][1] - step[i][1]) == 0):
                break
        clip_nums.append((j, i))

    # 注意回退点之间的包含关系, 逆序处理, 是为了规避顺序对列表进行处理后下标偏移的问题
    record = []
    for i in clip_nums[::-1]:
        if not (i[0] in record or i[1] in record):
            step = step[:i[0] + 1] + step[i[1]:]
        record += list(range(i[0], i[1]))
    print(step)

step = []

def walk(mg, x, y):
    global step
    if x == 1 and y == 1:
        step.append((x, y))
        mg[x][y] = 2
        # process(step)
        print(step)
        print("Walk success!")
        print(mg)
        quit()

    if check_valid(mg, x, y):
        step.append((x, y))
        mg[x][y] = 2
        walk(mg, x, y + 1)
        walk(mg, x, y - 1)
        walk(mg, x - 1, y)
        walk(mg, x + 1, y)

主函数部分:

 #step4 迷宫求解(假设出口为(1,1),入口自己设定)
    print("\n第三步:迷宫如何求解:\n")
    mg = matrix01(final_Result)
    walk(mg, 5, 5) # 表示出发点为(5,5),终点为(1,1)

运行结果:

可惜啊,准备得再充分,临时变题,世事难料。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值