概述
本项目效果如图
动画过程已投稿b站:https://www.bilibili.com/video/av88671119
目录
一、思路分析
二、手动拼图
三、自动拼图
四、动画展示
======================= 大爽歌作,made by big shuang =======================
四、动画展示
1、介绍
动画视频已投稿到我的b站,点击观看视频
动画只展示拼图结果,不展示结果的求解方法
结果的求解方法见之前的二三部分
这里为了好看,简单修改了下颜色和样式
最后展示后的结果如最上方的图
本部分代码是在第二部分手动拼图的代码基础上完成的
感兴趣的可以两个对照看看
其中新增py文件:
puzzle_show.py: 主入口,展示绘制动画
修改py代码:
drawer.py: 用于绘制的画板类
constants.py: 记录要用到的常量
results.py: 拼图结果
未修改的代码和文件
util.py: 用于绘制的画板类
love3.txt: 迷宫文本
2、代码
各个文件的代码如下
puzzle_show.py:
# usr/bin/env python
# -*- coding:utf-8- -*-
import tkinter as tk
import time
import turtle
from drawer import Drawer
from util import *
from constants import CELL_SIZE, C, R, SHAPE_LIST, SHAPES, FPS
from results import *
class PuzzleApp:
def __init__(self, c, r, txt_path, res):
self.win = tk.Tk()
self.love_list = read_love_from_txt(txt_path)
# 获取love_list 的长宽
self.love_r = len(self.love_list)
self.love_c = len(self.love_list[0])
self.r = r
self.c = c
self.pr = r - self.love_r
self.pc = (c - self.love_c) // 2
self.generate_board()
self.drawer = Drawer(self.win, self.c, self.r, CELL_SIZE)
self.drawer.draw_background(self.board)
self.block_id = -1 # 记录是第几个俄罗斯方块
self.block = {} # 俄罗斯方块的信息
self.block_list = [] # 记录已经着陆的俄罗斯方块
self.res = res
self.show_over = False
def print_block_list(self, event):
if self.block_list:
print('[')
for block in self.block_list:
print(block)
print(']')
def generate_board(self):
# 生成全空的二维列表 board
self.board = [
['' for ci in range(self.c)] for ri in range(self.r)
]
# 生成全空的二维列表 block_blard ,用于记录俄罗斯方块的存储情况
self.block_board = [
['' for ci in range(self.c)] for ri in range(self.r)
]
# 二维列表 board 中记录 love_list,将里面的粉红色方格记录为'R'
for ri in range(len(self.love_list)):
for ci in range(len(self.love_list[0])):
if self.love_list[ri][ci] == "1":
self.board [ri+self.pr][ci + self.pc] = "R"
def generate_new_block(self):
self.block_id += 1
cr = [self.pc + self.love_c // 2, 2]
_kind = SHAPE_LIST[0]
self.block = {
'cr': cr,
'kind': _kind,
'cell_list': SHAPES[_kind],
'angle': 0, # 角度
}
self.drawer.draw_block(self.block, self.block_id)
def check_move(self, cr, cell_list, direction):
# 判断某个俄罗斯方块的方格能否在某个位置摆放
cc, cr = cr
cell_list = cell_list
for cell in cell_list:
cell_c, cell_r = cell
c = cell_c + cc + direction[0]
r = cell_r + cr + direction[1]
# 判断该位置是否超出左右边界,以及下边界
# 一般不判断上边界,因为俄罗斯方块生成的时候,可能有一部分在上边界之上还没有出来
if c < 0 or c >= self.c or r >= self.r:
return False
# 必须要判断r不小于0才行,具体原因你可以不加这个判断,试试会出现什么效果
if r >= 0 and self.block_board[r][c] not in ['', 'R']:
return False
return True
def move_block(self, direction):
"""
向指定方向移动俄罗斯方块
"""
cr = self.block['cr']
cell_list = self.block['cell_list']
if self.check_move(cr, cell_list, direction):
# 先清除原有的
self.drawer.clean_by_block_id(self.block_id)
# 再绘制新的
new_cr = [cr[0]+direction[0], cr[1]+direction[1]]
self.block['cr'] = new_cr
self.drawer.draw_block(self.block, self.block_id)
self.win.update()
def rotate_block(self):
angle = self.block['angle']
angle += 1
angle %= 4 # 除4取余数,避免角度超过4
cell_list = self.block['cell_list']
rotate_list = get_cell_list_by_angle(cell_list, 1)
if self.check_move(self.block['cr'], rotate_list, [0, 0]):
# 先清除原有的
self.drawer.clean_by_block_id(self.block_id)
# 再绘制新的
self.block['angle'] = angle
self.block['cell_list'] = rotate_list
self.drawer.draw_block(self.block, self.block_id)
self.win.update()
def change_block(self):
kind_index = SHAPE_LIST.index(self.block['kind'])
next_kind = SHAPE_LIST[(kind_index + 1) % len(SHAPE_LIST)]
if self.check_move(self.block['cr'], SHAPES[next_kind], [0, 0]):
# 先清除原有的
self.drawer.clean_by_block_id(self.block_id)
# 再绘制新的
self.block['angle'] = 0
self.block['kind'] = next_kind
self.block['cell_list'] = SHAPES[next_kind]
self.drawer.draw_block(self.block, self.block_id)
self.win.update()
def land(self):
# 俄罗斯方块直接着陆
c, r = self.block['cr']
cell_list = self.block['cell_list']
new_r = self.get_land_r(cell_list, c)
while r < new_r:
# 先清除原有的
self.drawer.clean_by_block_id(self.block_id)
# 再绘制新的
r += 1
self.block['cr'] = [c, r]
self.drawer.draw_block(self.block, self.block_id)
self.win.update()
time.sleep(0.01)
self.drawer.draw_block_line(self.block, self.block_id)
self.block_list.append(self.block)
self.refresh_block_board()
self.win.update()
def get_land_r(self, cell_list, ci):
# 获取当前俄罗斯方块降落后的行位置
ri = 0
for ri in range(2, self.r):
# 从上到下依次尝试能否移动该行,如果这行移动不到,则说明上一行是降落的着陆点
if not self.check_move((ci, ri), cell_list, (0, 0)):
return ri - 1
return self.r - 1
def refresh_block_board(self):
self.block_board = [
['' for ci in range(self.c)] for ri in range(self.r)
]
for block in self.block_list:
shape_type = block['kind']
cc, cr = block['cr']
cell_list = block['cell_list']
for cell in cell_list:
cell_c, cell_r = cell
c = cell_c + cc
r = cell_r + cr
self.block_board[r][c] = shape_type
def back(self, event):
if self.block_id>0:
# 先隐藏当前的俄罗斯方块
self.drawer.clean_by_block_id(self.block_id)
# 再回退到上一个俄罗斯方块
self.block = self.block_list.pop()
self.block['cr'][1] = 2
self.drawer.clean_by_block_id(self.block_id-1)
self.block_id -= 1
self.drawer.draw_block(self.block, self.block_id)
self.refresh_block_board()
self.win.update()
def game_loop(self):
if self.show_over:
return
elif self.block:
self.move_block_to_res()
else:
self.get_next_block()
self.win.after(FPS, self.game_loop)
def move_block_to_res(self):
if self.block['kind'] != self.block['res_kind']:
self.change_block()
elif self.block['angle'] != self.block['res_angle']:
self.rotate_block()
elif self.block['cr'][0] != self.block['res_cr'][0]:
c = self.block['cr'][0]
rc = self.block['res_cr'][0]
if c < rc:
# 右移
self.move_block([1, 0])
elif c > rc:
self.move_block([-1, 0])
elif self.block['cr'][1] != self.block['res_cr'][1]:
self.land()
self.block = {}
def get_next_block(self):
# 从已保存的结果中取出下一个block
self.block_id += 1
if self.block_id >= len(self.res):
# 所有block均被取出,演示完毕
self.show_over = True
return
self.block = self.res[self.block_id]
self.block['res_angle'] = self.block['angle']
self.block['angle'] = 0
c, r = self.block['cr']
self.block['res_cr'] = [c+self.pc, r + self.pr]
self.block['cr'] = [self.pc + self.love_c // 2, 2]
self.block['res_kind'] = self.block['kind']
self.block['kind'] = SHAPE_LIST[0]
self.block['cell_list'] = SHAPES[SHAPE_LIST[0]]
self.drawer.draw_block(self.block, self.block_id)
if __name__ == '__main__':
txt_path = "love3.txt"
app = PuzzleApp(C, R, txt_path, res2)
app.game_loop()
app.win.mainloop()
drawer.py:
# usr/bin/env python
# -*- coding:utf-8- -*-
import tkinter as tk
from constants import ALL_COLORS, DIRECTION
class Drawer(tk.Canvas):
def __init__(self, master, c, r, cell_size):
self.c = c
self.r = r
self.cell_size = cell_size
height = r * cell_size
width = c * cell_size
super().__init__(master, width=width, height=height)
self.pack()
def draw_background(self, board):
for ri in range(self.r):
for ci in range(self.c):
color = ALL_COLORS[board[ri][ci]]
self.draw_cell_by_cr(ci, ri, color)
def draw_cell_by_cr(self,c, r, color, tag=None):
x0 = c * self.cell_size
y0 = r * self.cell_size
x1 = c * self.cell_size + self.cell_size
y1 = r * self.cell_size + self.cell_size
# tag用于在后面删除指定tag的方格
if tag is None:
# 没有tag代表的是背景色
self.create_rectangle(x0, y0, x1, y1, fill=color, outline="white", width=2)
else:
# 有tag 代表的是俄罗斯方块
_tag = "b%s" % tag
self.create_rectangle(x0, y0, x1, y1, fill=color,
outline=color, tag=_tag)
def draw_block(self, block, block_id):
c, r = block['cr']
shape_type = block['kind']
cell_list = block['cell_list']
for cell in cell_list:
cell_c, cell_r = cell
ci = cell_c + c
ri = cell_r + r
# 判断该位置方格在画板内部(画板外部的方格不再绘制)
if 0 <= c < self.c and 0 <= r < self.r:
self.draw_cell_by_cr(ci, ri, ALL_COLORS[shape_type], block_id)
def clean_by_block_id(self, block_id):
_tag = "b%s" % block_id
self.delete(_tag)
def draw_line(self, c, r, d, color, block_id):
if d == "W":
x0 = c * self.cell_size
y0 = r * self.cell_size
x1 = c * self.cell_size + self.cell_size
y1 = y0
elif d == "S":
x0 = c * self.cell_size
y0 = r * self.cell_size + self.cell_size
x1 = c * self.cell_size + self.cell_size
y1 = y0
elif d == "A":
x0 = c * self.cell_size
y0 = r * self.cell_size
x1 = x0
y1 = r * self.cell_size + self.cell_size
elif d == "D":
x0 = c * self.cell_size + self.cell_size
y0 = r * self.cell_size
x1 = x0
y1 = r * self.cell_size + self.cell_size
# tag用于在后面删除指定的线
_tag = "b%s" % block_id
self.create_line(x0, y0, x1, y1, fill=color, width=2, tag=_tag)
def draw_block_line(self, block, block_id):
c, r = block['cr']
shape_type = block['kind']
cell_list = block['cell_list']
for cell in cell_list:
for d in DIRECTION:
dcr = DIRECTION[d]
d_cell = (cell[0] + dcr[0], cell[1] + dcr[1])
if d_cell not in cell_list:
# draw line
self.draw_line(c+cell[0], r++cell[1], d, ALL_COLORS["line"], block_id)
constants.py
# usr/bin/env python
# -*- coding:utf-8- -*-
C = 20
R = 20
CELL_SIZE = 30
FPS = 100
# 定义各种形状
SHAPES = {
"O": [(-1, -1), (0, -1), (-1, 0), (0, 0)],
"S": [(-1, 0), (0, 0), (0, -1), (1, -1)],
"T": [(-1, 0), (0, 0), (0, -1), (1, 0)],
"I": [(0, 1), (0, 0), (0, -1), (0, -2)],
"L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
"J": [(-1, 0), (0, 0), (0, -1), (0, -2)],
"Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
}
# 定义各种颜色,用于给第二第三阶段拼图上色
# ALL_COLORS = {
# # 七种俄罗斯方块的颜色
# "O": "#d25b6a",
# "S": "#d2835b",
# "T": "#e5e234",
# "I": "#83d05d",
# "L": "#2862d2",
# "J": "#35b1c0",
# "Z": "#5835c0",
#
# # 其他颜色
# "": "#CCCCCC",
# "R": "#ffcccc",
# "D": "#ff3366",
# "line": "red"
# }
# 绘制动画时将七种俄罗斯方块全部换成深红色
ALL_COLORS = {
# 七种俄罗斯方块的颜色
"O": "#ff3366",
"S": "#ff3366",
"T": "#ff3366",
"I": "#ff3366",
"L": "#ff3366",
"J": "#ff3366",
"Z": "#ff3366",
# 其他颜色
"": "#CCCCCC",
"R": "#ffcccc",
"D": "#ff3366",
"line": "red"
}
SHAPE_LIST = ["O", "S", "T", "I", "L", "J", "Z"]
DIRECTION = {
"W": (0, -1),
"S": (0, 1),
"A": (-1, 0),
"D": (1, 0),
}
result.py
#usr/bin/env python
#-*- coding:utf-8- -*-
res1 = [
{'cr': [10, 18], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [10, 16], 'kind': 'I', 'cell_list': [(0, 1), (0, 0), (0, -1), (0, -2)], 'angle': 0},
{'cr': [9, 17], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [12, 17], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [7, 15], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [13, 15], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [9, 14], 'kind': 'S', 'cell_list': [(0, 1), (0, 0), (-1, 0), (-1, -1)], 'angle': 1},
{'cr': [12, 14], 'kind': 'Z', 'cell_list': [(-1, 1), (-1, 0), (0, 0), (0, -1)], 'angle': 1},
{'cr': [13, 14], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [7, 13], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [5, 13], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [15, 13], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [4, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [17, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [14, 12], 'kind': 'S', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, -1)], 'angle': 0},
{'cr': [6, 12], 'kind': 'Z', 'cell_list': [(-1, -1), (0, -1), (0, 0), (1, 0)], 'angle': 0},
{'cr': [10, 13], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [9, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [12, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [10, 10], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [13, 10], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [7, 10], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [13, 8], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [7, 9], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [16, 10], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [4, 10], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [6, 9], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [15, 9], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
]
res2 = [
{'cr': [10, 18], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [10, 16], 'kind': 'I', 'cell_list': [(0, 1), (0, 0), (0, -1), (0, -2)], 'angle': 0},
{'cr': [9, 17], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [12, 17], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [7, 16], 'kind': 'L', 'cell_list': [(0, -1), (0, 0), (1, -1), (2, -1)], 'angle': 3},
{'cr': [13, 15], 'kind': 'J', 'cell_list': [(0, 1), (0, 0), (-1, 0), (-2, 0)], 'angle': 1},
{'cr': [6, 14], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [14, 14], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [8, 14], 'kind': 'Z', 'cell_list': [(-1, -1), (0, -1), (0, 0), (1, 0)], 'angle': 0},
{'cr': [12, 14], 'kind': 'S', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, -1)], 'angle': 0},
{'cr': [10, 13], 'kind': 'T', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, 0)], 'angle': 0},
{'cr': [16, 12], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [4, 13], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [13, 11], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [7, 12], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [12, 11], 'kind': 'S', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, -1)], 'angle': 0},
{'cr': [8, 11], 'kind': 'Z', 'cell_list': [(-1, -1), (0, -1), (0, 0), (1, 0)], 'angle': 0},
{'cr': [10, 10], 'kind': 'T', 'cell_list': [(1, 0), (0, 0), (0, 1), (-1, 0)], 'angle': 2},
{'cr': [6, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [15, 12], 'kind': 'O', 'cell_list': [(-1, -1), (0, -1), (-1, 0), (0, 0)], 'angle': 0},
{'cr': [17, 11], 'kind': 'T', 'cell_list': [(0, 1), (0, 0), (-1, 0), (0, -1)], 'angle': 1},
{'cr': [3, 11], 'kind': 'T', 'cell_list': [(0, -1), (0, 0), (1, 0), (0, 1)], 'angle': 3},
{'cr': [6, 9], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [5, 9], 'kind': 'S', 'cell_list': [(-1, 0), (0, 0), (0, -1), (1, -1)], 'angle': 0},
{'cr': [13, 8], 'kind': 'L', 'cell_list': [(0, 1), (0, 0), (-1, 1), (-2, 1)], 'angle': 1},
{'cr': [7, 9], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [14, 10], 'kind': 'J', 'cell_list': [(0, -1), (0, 0), (1, 0), (2, 0)], 'angle': 3},
{'cr': [15, 9], 'kind': 'Z', 'cell_list': [(-1, -1), (0, -1), (0, 0), (1, 0)], 'angle': 0},
]
剩下的util.py和love3.txt未做修改,和之前是一样的
util.py:
# usr/bin/env python
# -*- coding:utf-8- -*-
def read_love_from_txt(txt_path):
# 从txt中读取二维爱心列表,并返回
with open(txt_path, 'r') as f:
fl = f.readlines()
love_list = []
for line in fl:
line = line.strip('n')
new_line = line.split(' ')
love_list.append(new_line)
return love_list
def get_cell_list_by_angle(cell_list, angle):
# 将当前的 cell_list旋转指定的角度
angle_dict = {
0: (1, 0, 0, 1),
1: (0, 1, -1, 0),
2: (-1, 0, 0, -1),
3: (0, -1, 1, 0),
}
a, b, c, d = angle_dict[angle]
if angle == 0:
return cell_list
rotate_cell_list = []
for cell in cell_list:
cc, cr = cell
rc, rr = a * cc + b * cr, c*cc+d*cr
rotate_cell_list.append((rc, rr))
return rotate_cell_list
love3.txt:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0
0 0 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
最后
以上就是稳重香烟为你收集整理的【python+情人节】玩个俄罗斯方块都是爱你的形状——四、动画展示的全部内容,希望文章能够帮你解决【python+情人节】玩个俄罗斯方块都是爱你的形状——四、动画展示所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复