手把手教你使用Python实现推箱子小游戏(附完整源码)

news2024/12/23 17:24:18

文章目录

  • 项目介绍
  • 项目规则
  • 项目接口文档
  • 项目实现过程
    • 前置方法编写
    • move核心方法编写
    • 项目收尾
    • 项目完善
  • 项目整体源码
  • 项目缺陷分析
  • 项目收获与反思

项目介绍

我们这个项目是一个基于Python实现的推箱子小游戏,名叫Sokoban:
在这里插入图片描述

这个游戏的目的是让玩家,也就是大写的P,推着箱子#,填充用小写的o标记的地面上的洞

项目规则

该版本的Sokoban的规则如下:

  • 游戏在矩形的二维网格上举行,其原点(0,0)位于左上方
  • 网格上的每个单元格可以随时包含以下内容之一:
    • 由大写字母P表示的玩家
    • 由空格字符' '表示的地砖
    • 由哈希字符#表示的箱子
    • 由星号字符*表示的墙
    • 由小写字符o表示的洞
  • 每个回合,玩家角色可以在网格上向上、向下、向左或向右移动一个单位
  • 玩家角色不能移动到墙或洞中
  • 每一回合,玩家角色都可以将箱子向他们试图移动的方向推一个单位,前提是玩家试图移动方向的箱子的下一个单元格是地砖或者是洞。如果不满足此条件,玩家和箱子都不会移动
  • 如果玩家将箱子推入到洞中,洞和箱子都会消失,并留下一块板砖。
  • 如果玩家试图离开屏幕边缘或将箱子推离屏幕边缘,如果其他规则允许,玩家或箱子应该出现在屏幕的对侧就像屏幕的两侧是连接的一样

项目接口文档

在这个项目中你需要去实现含有以下方法的Sokoban类;

  • __init__(self,board):使用给定的board创建Sokoban实例,参数board是一个二维嵌套列表,也就是我们的游戏地图
  • find_player(self):返回玩家角色在棋盘上的位置。行和列从0开始,原点(0,0)位于网格的左上角,例如在我们项目介绍中玩家的位置为 (0,0)
  • is_complete(self):判断游戏是否结束。如果地图中没有洞,则返回真,代表游戏结束,否则返回假
  • steps(self):返回玩家角色的移动次数(也就是玩家的位置发生变化的时候)
  • restart(self):将Sokoban实例进行重置,重置为玩家开始游戏之前的状态
  • undo(self):撤销玩家的上一次移动,使游戏状态恢复到上一次移动的时候,可以重复调用以撤销多次移动。如果撤销被调用的次数超过玩家的移动次数,则棋盘应保持其初始状态
  • move(self,direction):试图将玩家移动一个位置并且推动玩家面前的箱子。方向参数是一个字符串,其值为w,a,s,d,分别表示向上,向左,向下和向右。只有当玩家的位置发生更新的时候,才会计算移动次数。如果玩家的位置没有发生改变,则游戏的状态不应以任何方式改变
  • __str__(self):返回地图的字符串表示形式。记住每行中的单元格要用空格分隔

项目实现过程

前置方法编写

我们就按文档中的接口一个个实现。先来看init方法,这个方法里面我们现在能想到的只有两件事:

  • 地图初始化
  • step游戏步数的初始化
    def __init__(self,board):
        self.board = board
        self.step = 0

然后我们来实现str方法,在这里使用到的就是二维列表的遍历,我们只需要要建立一个空字符串然后把列表中的元素往里面塞就行了:

    def __str__(self):
        show = ''
        num = 0
        for i in self.board:
            num += 1
            for j in i:
                show += j + ' '
            show += '\n'
        return show[:-2]

我们每遍历完一行就使用\n来控制换行。我们最后对返回的字符串进行了切片是因为:我们如果不切片的话,我们在打印最后一行的时候末尾也会有一个换行符,这个是没有必要的!我们可以把它切去:
在这里插入图片描述
同样使用了二维列表的遍历的还有is_complete(self)方法,这个的思路也就是单纯的遍历地图看是否还有洞口存在就行,实现较简单;

    def is_complete(self):
        for i in self.board:
            for j in i :
                if j == 'o':
                    return False
        return True

接下来我们来实现find_player(self)方法,其核心思想仍然是二维列表的遍历,这里我提供两种实现方法:

实现方法1:

    def find_player(self):
        x = -1;y = -1
        for j in self.board:
            x += 1
            for k in j:
                y += 1
                if k == 'P':
                    return (x,y)
            y = -1

实现方法2:

    def find_player(self):
        for x in range(self.board_x()):
            for y in range(self.board_x()):
                if self.board[x][y] == 'P':
                    return (x,y)

move核心方法编写

我们在思考move方法的编写的时候,乍一想会发现有很多需要注意点,有非常非常多的限制、判断,可能想着想着一下子就迷失了方向。其实我们可以思考一下,我们每执行一次move指令其实就进行了两个步骤:

  • 判断能否移动
  • 如果可以移动,则变动玩家(可能还有箱子)的位置

也就是说我们现在将一个指令进行了分解,让他稍微具体了一些。换句话说我们想要实现move这个方法,只需要我们完成这两个功能就可以了,这里我想了一下如果我们将这两个功能都堆叠在move方法中,会显得代码非常的乱,而且涉及if的层层嵌套,会让思维容易混乱。所以这里我们可以把判断能否移动这个功能抽象出来,令作为一个方法,我们把它命名为check。将实际的移动功能留在move方法中。

因为涉及到的四个方向,其实我们知道一个方向怎么实现之后,其他的方向实现也就是照葫芦画瓢,所以这里我只对check以及move方法中的w方向进行讲解,然后为了方便我们可以将地图的长度和宽度的获取抽象成一个方法,方便后面的使用:

    def board_x(self):
        return len(self.board)

    def board_y(self):
        return len(self.board[0])

接下来我们开工!

check()

首先我们先拿到玩家的具体位置,直接调用find_player方法即可,其位置可以通过如下坐标系来理解:
在这里插入图片描述

在w方向上来说,他的移动有两种情况:

  • 情况一:w方向上与它相邻的位置有箱子(也就是说玩家要推着箱子走)
  • 情况二:只有玩家自己移动

而情况一下面又有两种情况:

  • 在w方向上,箱子的前面一个是墙

    • 这种情况下就不能移动
      在这里插入图片描述
  • 箱子前面没有墙

    • 这种情况下可以移动
      在这里插入图片描述

这里有人会说应该还有一种情况箱子前面是洞口。这说明还没有完全弄清我们单独抽象出这个check方法的目的,我们的check方法只做一件事,那就是箱子或者箱子和人能不能移动。而箱子前面是洞口这种情况属于可以移动的情况,不需要单拿出来讨论。至于箱子与洞口的相消与地砖的填充不是我们check方法的功能,我们应该把他们放到move方法中去处理。
在这里插入图片描述

考虑完这些情况之后我们还不能开始写代码,因为有一点我们不能忽略,那就是项目规则中的最后一条:

  • 如果玩家试图离开屏幕边缘或将箱子推离屏幕边缘,如果其他规则允许,玩家或箱子应该出现在屏幕的对侧就像屏幕的两侧是连接的一样

这个地方如果再去加加减减的,然后弄出一大堆情况非常麻烦且容易出现角标越界等问题。我们其实可以想象一下,当我们的玩家一直在w方向上前进(假设整列没有墙不会阻碍前进),到达顶点之后,又从当前列的下方出现,这种情景有点类似于循环列表。我们可以借用取余的思想,这样就不需要进行繁杂的讨论,也可以避免角标越界等错误。

接下来我们来写代码:

    def check(self,direction):
        # 此时玩家的位置
        x = self.find_player()[0]
        y = self.find_player()[1]
        if direction not in "wasd":
            return -1
        #每个方向上的处理
        # 先考虑在你的移动方向上没有箱子的情况
        # 再考虑在你的移动方向上有箱子的情况
        # 返回正整数代表可以移动 返回1说明有箱子   返回0说明没箱子    返回负数代表不能移动
        if direction == 'w':
            # 代表方向上没有箱子
            if self.board[(x-1)%self.board_x()][y] != '#':
                if self.board[(x-1)%self.board_x()][y] not in '*o':
                    return 0
                else:
                    return -1
            # 代表方向上有箱子
            else:
                if self.board[(x-2)%self.board_x()][y] not in '*':
                    return 1
                else:
                    return -1

这里我们的返回值;

  • 正整数代表可以移动
    • 0代表不需要推箱子,只有玩家移动
    • 1代表需要推箱子,玩家和箱子均需要移动
  • 负数代表不能移动

其他方向同理

move

同样还是先拿到玩家的坐标,然后调用check方法,如果check返回的是一个负数那么直接return不用处理。我们重点来讨论如果返回的是正整数的时候的情况:

以w方向为例进行讨论

  • 如果check返回的是0(也就是说只有玩家移动):
    • 我们只需要将当前玩家所处的方格以地砖替代,将前一个方格使用P替代
  • 如果check返回的是非零整数(也就是说玩家和箱子都要移动),这里再分为两种情况:
    • 箱子前面是洞
      • 箱子和洞口相消,玩家前移
    • 箱子前面是地砖
      • 箱子和玩家均前移一个单位

代码如下:

    def move(self,direction):
        # 此时玩家的位置
        x = self.find_player()[0]
        y = self.find_player()[1]
        ans = self.check(direction)
        if direction == 'w':
            if ans < 0:
                return
            else:
                self.board[x][y] = ' '
                if ans == 0:
                    self.board[(x-1)%self.board_x()][y] = 'P'
                else:
                    if self.board[(x-2)%self.board_x()][y] == 'o':
                        self.board[(x-2)%self.board_x()][y] = ' '
                        self.board[(x-1)%self.board_x()][y] = 'P'
                    else:
                        self.board[(x-2)%self.board_x()][y] = '#'
                        self.board[(x-1)%self.board_x()][y] = 'P'

项目收尾

截至目前我们还有下面三个方法没有实现:

  • steps(self)
  • restart(self)
  • undo(self)

steps方法记录玩家的移动步数,而在我们当前项目中,所有的移动操作都与move的方法有关,我们可以直接在move方法中对step进行计数:
在这里插入图片描述

    def steps(self):
        return self.step

注意只有当我们的check方法返回非负数的时候我们才会去计数。

接下来我们看看restart(self)和undo(self)方法,这两个方法一个用来重新开始,一个用来回退。他们都有一个特点那就是状态的回溯。那么我们就可以把他们用同一种思想处理,因为他们的区别无非就是一个回溯到开头状态,一个回溯到上一步的状态。

具体的做法就是:只要玩家的位置(状态) 发生了变化,我们就将变化前的地图状态进行储存。在代码层面上来讲就是将变化前的board存储到一个专门的列表中,这里我们就把这个列表命名为history:
在这里插入图片描述
在这里插入图片描述
这里要非常注意,像下面这样存入列表是不行:

self.history.append(self.board)

你最后会发现存入history中的所有元素都一样并且与当前的board是一致的。这是因为列表在Python中是可变数据类型,即使发生变化其地址值不会发生改变。使用上面的方法我们存入history的一个个元素都有着同样的地址值,也就是说它们是同一个对象。所以这里为了避免这种问题,我们应该使用深拷贝,而普通的深拷贝对我们的多维嵌套列表是没有用的。

这里我尝试了网上最常见的几种办法都没有用:

  • 列表的copy方法
  • list()方法
  • [:]切片方法

我们可以使用Python内置模块copy中的deepcopy方法,代码如下:

import copy

···
self.history.append(copy.deepcopy(self.board))

接下来我们只用在对应的方法中从history里取出不同的状态即可:

    def restart(self):
        self.board = self.history[0]
        self.step = 0
        self.history.clear();


    def undo(self):
        self.board = self.history[-1]
        self.step -= 1
        self.history.pop()

注意:

  • 我们restart之后要将history列表清空
  • 在我们回退时,除了返回history最后的元素,还要把它从列表中删除,否则在二次或者多次回退时会出错

项目完善

我们在编写代码的时候其实还忽略了几个点:

  • 如果撤销被调用的次数超过玩家的移动次数,则棋盘应保持其初始状态

也就是说我们不能一直回退,按照我们的代码,一直回退下去会出现以下两种情况:

  • history的列表长度问题,会衍生出角标出错
  • 我们的step会变为负数

改进:

    def undo(self):
        if self.step == 0:
            return
        self.board = self.history[-1]
        self.step -= 1
        self.history.pop()
  • 如果我们一开始就restart,或者说连续多次restart也会报错

其本质也是因为history列表为空导致的角标出错

改进:

    def restart(self):
        if len(self.history) == 0:
            return
        self.board = self.history[0]
        self.step = 0
        self.history.clear();

项目整体源码

'''
 推箱子
 P代表玩家 o代表洞  #代表箱子 空字符代表地砖
 项目要求:
 1)二维网格的元原点位于左上方
 2)每回合只能上下左右移动一格
 3)玩家不能移动到墙或者洞中
 4)只有当玩家推动箱子移动的下一个单位是地砖或着洞的时候才能移动成功  否则箱子不会移动
 5)箱子进入洞中之后  洞和箱子都会消失   使用地砖进行替代
 6)如果离开屏幕边缘 在规则允许的情况下(也就是第4条)  允许出现在对侧
'''


import copy

class Sokoban:
    def __init__(self,board):
        self.board = board
        self.step = 0
        self.history = []
    def __str__(self):
        show = ''
        num = 0
        for i in self.board:
            num += 1
            for j in i:
                show += j + ' '
            show += '\n'
        return show[:-2]
    def find_player(self):
        for x in range(self.board_x()):
            for y in range(self.board_x()):
                if self.board[x][y] == 'P':
                    return (x,y)

    def is_complete(self):
        for i in self.board:
            for j in i :
                if j == 'o':
                    return False
        return True
    def steps(self):
        return self.step

    def restart(self):
        if len(self.history) == 0:
            return
        self.board = self.history[0]
        self.step = 0
        self.history.clear();


    def undo(self):
        if self.step == 0:
            return
        self.board = self.history[-1]
        self.step -= 1
        self.history.pop()

    def move(self,direction):
        # 此时玩家的位置
        x = self.find_player()[0]
        y = self.find_player()[1]
        ans = self.check(direction)
        if direction == 'w':
            if ans < 0:
                return
            else:
                self.step += 1
                self.history.append(copy.deepcopy(self.board))
                self.board[x][y] = ' '
                if ans == 0:
                    self.board[(x-1)%self.board_x()][y] = 'P'
                else:
                    if self.board[(x-2)%self.board_x()][y] == 'o':
                        self.board[(x-2)%self.board_x()][y] = ' '
                        self.board[(x-1)%self.board_x()][y] = 'P'
                    else:
                        self.board[(x-2)%self.board_x()][y] = '#'
                        self.board[(x-1)%self.board_x()][y] = 'P'
        elif direction == 'a':
            if ans < 0:
                return
            else:
                self.step += 1
                self.history.append(copy.deepcopy(self.board))

                self.board[x][y] = ' '

                if ans == 0:
                    self.board[x][(y - 1)%self.board_y()] = 'P'
                else:
                    if self.board[x][(y - 2)%self.board_y()] == 'o':
                        self.board[x][(y - 2)%self.board_y()] = ' '
                        self.board[x][(y - 1)%self.board_y()] = 'P'
                    else:
                        self.board[x][(y - 2)%self.board_y()] = '#'
                        self.board[x][(y - 1)%self.board_y()] = 'P'
        elif direction == 's':
            if ans < 0:
                return
            else:
                self.step += 1
                self.history.append(copy.deepcopy(self.board))

                self.board[x][y] = ' '
                if ans == 0:
                    self.board[(x + 1)%self.board_x()][y] = 'P'
                else:
                    if self.board[(x + 2)%self.board_x()][y] == 'o':
                        self.board[(x + 2)%self.board_x()][y] = ' '
                        self.board[(x + 1)%self.board_x()][y] = 'P'
                    else:
                        self.board[(x + 2)%self.board_x()][y] = '#'
                        self.board[(x + 1)%self.board_x()][y] = 'P'
        elif direction == 'd':
            if ans < 0:
                return
            else:
                self.step += 1
                self.history.append(copy.deepcopy(self.board))

                self.board[x][y] = ' '
                if ans == 0:
                    self.board[x][(y + 1)%self.board_y()] = 'P'
                else:
                    if self.board[x][(y + 2)%self.board_y()] == 'o':
                        self.board[x][(y + 2)%self.board_y()] = ' '
                        self.board[x][(y + 1)%self.board_y()] = 'P'
                    else:
                        self.board[x][(y + 2)%self.board_y()] = '#'
                        self.board[x][(y + 1)%self.board_y()] = 'P'

    def check(self,direction):
        # 此时玩家的位置
        x = self.find_player()[0]
        y = self.find_player()[1]
        if direction not in "wasd":
            return -1
        #每个方向上的处理
        # 先考虑在你的移动方向上没有箱子的情况
        # 再考虑在你的移动方向上有箱子的情况
        # 返回正整数代表可以移动 返回1说明有箱子   返回0说明没箱子    返回负数代表不能移动
        if direction == 'w':
            # 代表方向上没有箱子
            if self.board[(x-1)%self.board_x()][y] != '#':
                if self.board[(x-1)%self.board_x()][y] not in '*o':
                    return 0
                else:
                    return -1
            # 代表方向上有箱子
            else:
                if self.board[(x-2)%self.board_x()][y] not in '*':
                    return 1
                else:
                    return -1
        elif direction == 'a':
            # 代表方向上没有箱子
            if self.board[x][(y - 1)%self.board_y()] != '#':
                if self.board[x][(y - 1)%self.board_y()] not in '*o':
                    return 0
                else:
                    return -1
            # 代表方向上有箱子
            else:
                if self.board[x][(y - 2)%self.board_y()] not in '*':
                    return 1
                else:
                    return -1
        elif direction == 's':
            # 代表方向上没有箱子
            if self.board[(x + 1)%self.board_x()][y] != '#':
                if self.board[(x + 1)%self.board_x()][y] not in '*o':
                    return 0
                else:
                    return -1
            # 代表方向上有箱子
            else:
                if self.board[(x + 2)%self.board_x()][y] not in '*':
                    return 1
                else:
                    return -1
        elif direction == 'd':
            # 代表方向上没有箱子
            if self.board[x][(y + 1)%self.board_y()] != '#':
                if self.board[x][(y + 1)%self.board_y()] not in '*o':
                    return 0
                else:
                    return -1
            # 代表方向上有箱子
            else:
                if self.board[x][(y + 2)%self.board_y()] not in '*':
                    return 1
                else:
                    return -1

    def board_x(self):
        return len(self.board)

    def board_y(self):
        return len(self.board[0])

# 竖着是x轴  横着是y轴
board = [
    ['*', '*', ' ', '*', '*'],
    ['*', 'o', ' ', ' ', '*'],
    ['#', ' ', 'P', '#', 'o'],
    ['*', ' ', ' ', ' ', '*'],
    ['*', '*', ' ', '*', '*'],
]


game = Sokoban(board)
move = str()
print(game)
print(game.steps(), ':', game.is_complete())
while not game.is_complete():
    move = input('move:')
    if move == 'u':
        game.undo()
    elif move == 'r':
        game.restart()
    else:
        game.move(move)
    print(game)
    print(game.steps(), ':', game.is_complete())

运行效果;
在这里插入图片描述

直接cv在IDE中就可以玩,地图可以自己自定义,记得箱子和洞口数量要一样多否则永远过不了关。

项目缺陷分析

  • 项目中使用的数据结构较为单一,列表一用用到底。其实很多地方都可以用栈、队列、链表等数据结构进行相关的优化
  • 有些地方的代码些许冗杂,可以进行语法上的优化
  • 因为接口文档的束缚,其实有很多方法可以更加细化。例如move方法或者说check方法代码逻辑还是有点多。有一些逻辑两个方法可以共用,我们可以抽象出来新建一个方法。
  • 既然在wasd四个方向上逻辑相似,那么我们是否可以考虑二次抽象,而不是将四种情况均放在check和move方法中。

项目收获与反思

这个推箱子的小游戏是校内老师布置的一次小作业。因为自己平时都是使用一些前端还有java后端方面的东西,python长时间不用忘得差不多了。我写的时候面向对象的方面的语法以及一些列表相关方法都是边查文档边写的。这就导致代码方面不是非常的成熟健壮。

当然收获也非常的多,一个是复习了python,然后就是取余的思想。平时可能刷算法题的时候可能会遇见,开发的时候基本没怎么用过,这个项目让我见识到了取余在实际开发中发挥的作用:在优化了代码的同时还能减少出错。一开始没想到取余的时候,一个个情况的分类讨论简直让人抓狂。

还有另外非常重要的一点,就是写代码之前打草稿的必要性

其实在平时我们进行不管是前端开发、后端开发,更多的思考的是:用什么、怎么用,那种很严格的逻辑思考其实并不是很频繁。这就导致一台电脑一个文档基本就可以解决问题。而涉及到算法或者说严格的情况分类与考虑这就需要我们打草稿整理思路再去写代码。直接一股脑地去写代码,或者说不打草稿非常的影响效率以及质量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jfow-代码分析

jfow-代码分析目录概述需求&#xff1a;设计思路实现思路分析1.代码&#xff1a;2.代码2&#xff1a;3.CashFrmTemplate4.chartType5.DataColumnData:参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xf…

Vue实战第1章:学习和使用vue-router

学习和使用vue-router 前言 本篇在讲什么 简单讲解关于vue-router的使用 仅介绍简单的应用&#xff0c;仅供参考 本篇适合什么 适合初学Vue的小白 适合想要自己搭建网站的新手 适合没有接触过vue-router的前端程序 本篇需要什么 对Html和css语法有简单认知 对Vue有…

2023/1/14 js基础学习

1 js基础学习-基本数据类型基本语法 请参考 https://blog.csdn.net/m0_48964052?typeblog https://gitee.com/hongjilin/hongs-study-notes/blob/master/%E7%BC%96%E7%A8%8B_%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/HTMLCSSJS%E5%9F%BA%E…

Arthas 入门到实战(二)在线热更新

1. 结合 jad/mc 命令在线修改使用 jad 命令: 将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码&#xff0c;便于你理解业务逻辑&#xff1b; mc命令&#xff1a;Memory Compiler/内存编译器&#xff0c;编译.java文件生成.class。 redefine命令&#xff1a;加载…

unix进程控制及进程环境--自APUE

文章目录概述1、孤儿进程和僵尸进程进程终止进程的编译和启动进程终止的步骤进程8种终止方式进程退出函数1&#xff1a;exit进程退出函数2&#xff1a;_exit进程退出函数3&#xff1a;_Exit注册终止处理程序&#xff1a;atexit环境变量通过main函数传参全局的环境变量表&#x…

uni-app跨端自定义指令实现按钮权限

前言 初看这个标题可能很迷&#xff0c;uni-app明明不支持自定义指令&#xff0c;这文章是在搞笑吗&#xff0c;本文对于uni-app自定义指令实现按钮权限的方式也有可能是多余&#xff0c;但为了给业务部门更友好的开发体验&#xff0c;还是做了一些可能没意义的操作&#xff0…

回顾2022,展望 2023

个人相关&#xff1a; PMP 因为疫情多次延期的PMP终于搞定&#xff0c;光环的PMP就是妥妥。基本只要认真做题和思考都会过。但是考试不仅仅是考试&#xff0c;有时候更多的是对项目发展和项目管理的思考&#xff1a;风险&#xff0c;里程碑&#xff0c;相关方&#xff0c;敏捷&…

红日内网渗透靶场2

目录 环境搭建&#xff1a; Web渗透&#xff1a; weblogic漏洞利用 java反序列化漏洞利用、哥斯拉获取shell 上线msf msf派生shell到cs 内网信息收集 mimikatz获取用户密码 cs横向移动 PTT攻击&#xff08;票据传递&#xff09; 方法2&#xff1a;通过msf利用永恒之蓝…

测试之分类【测试对象、是否查看代码、开发】

文章目录1. 按测试对象分类2. 按照是否查看代码划分3. 按照开发阶段划分1. 按测试对象分类 可靠性测试容错性测试安装卸载测试内存泄露测试弱网测试 &#xff08;1&#xff09;可靠性测试 可靠性 正常运行时间 / (正常运行时间 非正常运行时间) * 100% &#xff08;最高 10…

Servlet的实战用法(表白墙前后端)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 服务器版本的表白墙 创建项目 约定前后端交互接口 获取全部留言 发表新的留言 服务端代码 创建Message类 创建DBUtil类 创建MessageServlet…

双指针合集

87合并两个有序的数组 import java.util.*; public class Solution {public void merge(int A[], int m, int B[], int n) { int i m-1;int j n-1;for(int k nm-1;k>0;k--){if(j<0) A[k] A[i--];else if(i<0) A[k] B[j--];else if(A[i]>B[j]) A[k] A[i--]…

六道数据结构算法题详解

目录 1.力扣350题. 两个数组的交集 II 2.力扣121题. 买卖股票的最佳时机 3.力扣566题. 重塑矩阵 4.力扣118题. 杨辉三角 5.牛客BM13 判断一个链表是否为回文结构 6.牛客BM14 链表的奇偶重排 1.力扣350题. 两个数组的交集 II 题目&#xff1a;给你两个整数数组 nums1 和 n…

2022年终总结---权衡好工作和生活

2022总结 【校园】2022年6月研究生顺利毕业&#xff0c;让下文的一切才变的有机会。感谢师弟送学长毕业&#xff0c;感谢在最后时刻各位舍友帮忙送材料&#xff0c;怀念最后一个月一起打球的时光。 【工作】2022年6月入职阿里&#xff0c;成为打工人。在这个大的平台&#xf…

Goland项目使用gomod配置

Goland 项目创建 goland2020.3 及以上 IDE&#xff0c;默认创建的 go 项目 就是使用 gomod 管理&#xff01; goland2020.3 及以下的 IDE&#xff0c;创建项目时需要选择 带小括号 vgo 的才是 gomod 管理模式 下图为使用 goland2021.3 版本创建使用 gomod 管理的 go 项目&…

14种可用于时间序列预测的损失函数

在处理时间序列预测问任务时&#xff0c;损失函数的选择非常重要&#xff0c;因为它会驱动算法的学习过程。以往的工作提出了不同的损失函数&#xff0c;以解决数据存在偏差、需要长期预测、存在多重共线性特征等问题。本文工作总结了常用的的 14 个损失函数并对它们的优缺点进…

线段树(Segment tree)

线段树 线段树是一种二叉树形数据结构,用以储存区间或线段,并且允许快速查询结构内包含某一点的所有区间。 视频讲解 线段树主要实现两个方法:「求区间和」&「修改区间」,且时间复杂度均为 O(logn)。 nums = [1, 2, 3, 4, 5] 对应的线段树如下所示: 使用数组表示线段…

【阶段三】Python机器学习33篇:机器学习项目实战:医学病症关联规则分析

本篇的思维导图: 医学病症关联规则分析 项目背景 本项目演示一个医学领域的有趣应用——病症关联规则分析,同时利用apyori库和mlxtend库来编写代码,从数据分析的角度去研究病症背后的关联规则。假设有一种医学理论认为,五脏和一些病症之间存在关联关系,见下表。例…

4.线性神经网络

4.线性神经网络 目录 线性回归 线性回归的基本元素 线性模型损失函数解析解随机梯度下降 矢量化加速正态分布与平方损失 优化方法 梯度下降选择学习率小批量随机梯度下降选择批量大小总结 线性回归的从零开始实现 生成数据集读取数据集初始化模型参数定义模型定义损失函数定义…

磨金石教育摄影技能干货分享|优秀摄影作品欣赏——世界掠影

这世上很多地方都在发生着有趣的事&#xff0c;很多地方不同的人与物&#xff0c;都在不同的时间和环境下展现着不同的状态。让我们跟随摄影师的镜头去欣赏这些精彩的画面吧。1 悬而未定想象一下这张照片是什么角度拍的&#xff1f;是不是看上去很像俯拍&#xff1f;无论怎么看…

【Python】groupby操作后不把列作为索引单独提出

这是一个困了我几天的问题。 一开始的搜索方向错了&#xff0c;按照groupby的key column搜索&#xff0c;没有搜到。 最近悟出的一个技巧是&#xff0c;没有头绪时看看数据类型和数据内容。如果思路是没问题的情况下。 问题描述 date_date.groupby([XXXX]) poi_date.groupby(…