让AI玩一千万次贪吃蛇

news2024/12/28 3:02:42

如果让人工智能来玩贪吃蛇游戏,会发生什么?

 图源:DALL·E   

目录

贪吃蛇实现

游戏规则

游戏实现

Q学习算法实现

Q学习简介

Q表和Q值

Q学习更新规则

Q学习在贪吃蛇游戏中的应用

整体项目完整代码

运行过程截图

代码分析

环境设置

蛇的行为定义

Q学习代理实现

Q学习代理实现

小结


贪吃蛇实现

        在深入探讨人工智能如何掌握贪吃蛇游戏之前,让我们先回顾一下贪吃蛇游戏的基本设计和规则。贪吃蛇是一款经典的电子游戏,其简单的规则和直观的游戏玩法使其成为了历史上最受欢迎的游戏之一。

游戏规则

        在贪吃蛇游戏中,玩家控制一条不断移动的蛇,游戏目标是吃掉出现在屏幕上的食物,每吃掉一个食物,蛇的长度就会增加。游戏的挑战在于蛇不能触碰到屏幕边缘或自己的身体,否则游戏结束。随着蛇的不断增长,避免撞到自己变得越来越难,这就需要玩家有较高的策略和反应能力。

游戏实现

        在我们的Python实现中,游戏界面使用Pygame库创建,设置了固定的宽度和高度,以及基本的颜色定义,如黑色背景、绿色蛇身和红色食物。游戏中的蛇和食物都以方块的形式表示,每个方块的大小由block_size变量定义。游戏的主体是SnakeGame类,它封装了游戏的所有基本逻辑,包括蛇的初始化、移动、食物的生成以及碰撞检测等。

width, height = 640, 480  # 游戏窗口的宽度和高度
block_size = 20  # 每个方块的大小,包括蛇的每一部分和食物
class SnakeGame:
    def __init__(self, width, height, block_size):
        self.width = width
        self.height = height
        self.block_size = block_size
        self.reset()

        在reset方法中,游戏被重置到初始状态,蛇回到屏幕中心,长度为3个方块,方向向上。同时,食物被随机放置在屏幕上的某个位置。

def reset(self):
    initial_position = [self.width // 2, self.height // 2]
    self.snake = [
        initial_position,
        [initial_position[0] - self.block_size, initial_position[1]],
        [initial_position[0] - 2 * self.block_size, initial_position[1]]
    ]
    self.direction = 'UP'
    self.food = [random.randrange(1, self.width // self.block_size) * self.block_size,
                 random.randrange(1, self.height // self.block_size) * self.block_size]
    self.score = 0
    self.done = False
    return self.get_state()

        蛇的移动是通过在蛇头前面添加一个新的方块,并在蛇尾去掉一个方块来实现的。如果蛇吃到了食物,就不去掉蛇尾的方块,从而使蛇的长度增加。

        在游戏的每一步,step方法都会被调用,它接收一个动作(上、下、左、右),然后更新游戏状态,包括蛇的位置、游戏得分和游戏是否结束。这个方法是连接游戏逻辑和AI代理的桥梁,AI代理将根据游戏的当前状态决定下一步的最佳动作。

完整的游戏类:

class SnakeGame:
    def __init__(self, width, height, block_size):
        self.width = width
        self.height = height
        self.block_size = block_size
        self.reset()

    def reset(self):
        initial_position = [self.width // 2, self.height // 2]
        self.snake = [
            initial_position,
            [initial_position[0] - self.block_size, initial_position[1]],
            [initial_position[0] - 2 * self.block_size, initial_position[1]]
        ]
        self.direction = 'UP'
        self.food = [random.randrange(1, self.width // self.block_size) * self.block_size,
                     random.randrange(1, self.height // self.block_size) * self.block_size]
        self.score = 0
        self.done = False
        return self.get_state()

    def step(self, action):
        directions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
        if self.direction != 'UP' and action == 1:
            self.direction = 'DOWN'
        elif self.direction != 'DOWN' and action == 0:
            self.direction = 'UP'
        elif self.direction != 'LEFT' and action == 3:
            self.direction = 'RIGHT'
        elif self.direction != 'RIGHT' and action == 2:
            self.direction = 'LEFT'

        # 计算食物的距离以判断是否靠近食物
        distance_to_food_before = self.distance(self.snake[0], self.food)

        # 移动蛇
        x, y = self.snake[0]
        if self.direction == 'UP':
            y -= block_size
        elif self.direction == 'DOWN':
            y += block_size
        elif self.direction == 'LEFT':
            x -= block_size
        elif self.direction == 'RIGHT':
            x += block_size
        new_head = [x, y]


        if x < 0 or x >= width or y < 0 or y >= height:
            self.done = True
            reward = -500  # 撞墙的惩罚
            return self.get_state(), reward, self.done
        if new_head in self.snake:
            self.done = True
            reward = -200  # 撞到自身的严重惩罚
            return self.get_state(), reward, self.done


        self.snake.insert(0, new_head)
        if new_head == self.food:
            self.score += 1
            reward = 500  # 吃到食物的奖励
            self.food = [random.randrange(1, width // block_size) * block_size,
                         random.randrange(1, height // block_size) * block_size]
        else:
            self.snake.pop()


            distance_to_food_after = self.distance(new_head, self.food)
            if distance_to_food_after < distance_to_food_before:
                reward = 30  # 靠近食物的奖励
            else:
                reward = -15  # 无进展的小惩罚

        # 检查是否长时间直线移动
        if len(set([part[0] for part in self.snake])) == 1 or len(set([part[1] for part in self.snake])) == 1:
            if len(self.snake) > 5:  # 如果蛇的长度超过一定阈值
                reward -= 5  # 长时间直线移动的小惩罚

        return self.get_state(), reward, self.done

    def distance(self, point1, point2):
        return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** 0.5

    def get_state(self):
        head = self.snake[0]
        point_l = [head[0] - self.block_size, head[1]]
        point_r = [head[0] + self.block_size, head[1]]
        point_u = [head[0], head[1] - self.block_size]
        point_d = [head[0], head[1] + self.block_size]

        state = [
            head[0] / self.width, head[1] / self.height,  # 蛇头的相对位置
            self.food[0] / self.width, self.food[1] / self.height,  # 食物的相对位置
            int(self.direction == 'LEFT'), int(self.direction == 'RIGHT'),
            int(self.direction == 'UP'), int(self.direction == 'DOWN'),  # 蛇头的方向
            int(self.is_collision(point_l)), int(self.is_collision(point_r)),
            int(self.is_collision(point_u)), int(self.is_collision(point_d))  # 周围是否会发生碰撞
        ]

        return np.array(state, dtype=float)

    def is_collision(self, point):
        return point[0] < 0 or point[0] >= self.width or point[1] < 0 or point[1] >= self.height or point in self.snake

    def display(self, screen):
        screen.fill(black)
        for part in self.snake:
            pygame.draw.rect(screen, green, pygame.Rect(part[0], part[1], self.block_size, self.block_size))
        pygame.draw.rect(screen, red, pygame.Rect(self.food[0], self.food[1], self.block_size, self.block_size))
        pygame.display.flip()

Q学习算法实现

        Q学习是一种无模型的强化学习算法,广泛应用于各种决策过程,包括我们的贪吃蛇游戏。它使代理能够在与环境交互的过程中学习,从而确定在给定状态下采取哪种动作以最大化未来的奖励。接下来,我们将深入探讨Q学习的核心概念和工作原理,并结合前文提到的贪吃蛇游戏代码进行说明。

Q学习简介

        Q学习的目标是学习一个策略,告诉代理在特定状态下应该采取什么动作以获得最大的长期奖励。这种策略通过一个叫做Q函数的东西来表示,它为每个状态-动作对分配一个值(Q值)。这个值代表了在给定状态下采取某个动作,并遵循当前策略的情况下,预期能获得的总奖励。

Q表和Q值

        在实践中,Q函数通常通过一个表格(Q表)来实现,表中的每一行对应一个可能的状态,每一列对应一个可能的动作,表中的每个元素表示该状态-动作对的Q值。在我们的贪吃蛇游戏中,状态可以是蛇头的位置、食物的位置以及蛇头的方向等信息的组合,动作则是蛇的移动方向(上、下、左、右)。

Q学习更新规则

        Q学习的核心是其更新规则,它定义了如何根据代理的经验逐步调整Q值。更新规则如下:

Q学习在贪吃蛇游戏中的应用

        在贪吃蛇游戏的实现中,我们首先定义了一个QLearningAgent类,它包含了学习率、折扣率和探索率等参数,以及一个空的Q表来存储Q值。

class QLearningAgent:
    def __init__(self, learning_rate=0.5, discount_rate=0.8, exploration_rate=0.45):
        self.learning_rate = learning_rate
        self.discount_rate = discount_rate
        self.exploration_rate = exploration_rate
        self.q_table = {}

代理通过get_action方法根据当前状态选择动作,这里使用了ϵ-贪婪策略来平衡探索和利用:

def get_action(self, state):
    state_key = str(state)
    if state_key not in self.q_table:
        self.q_table[state_key] = np.zeros(4)

    if np.random.rand() < self.exploration_rate:
        return random.randint(0, 3)  # 探索
    else:
        return np.argmax(self.q_table[state_key])  # 利用

在每一步之后,update_q_table方法会根据Q学习的更新规则来调整Q值:

def update_q_table(self, state, action, reward, next_state, done):
    state_key = str(state)
    next_state_key = str(next_state)

    if next_state_key not in self.q_table:
        self.q_table[next_state_key] = np.zeros(4)

    next_max = np.max(self.q_table[next_state_key])
    self.q_table[state_key][action] = (1 - self.learning_rate) * self.q_table[state_key][action] + \
                                      self.learning_rate * (reward + self.discount_rate * next_max)

        通过这种方式,Q学习代理能够在与环境的交互中逐渐学习到在各种状态下应该采取的最佳动作,从而在贪吃蛇游戏中获得尽可能高的分数。随着训练的进行,代理会变得越来越熟练,最终能够展示出高水平的游戏技巧。

整体项目完整代码

 import time
import pygame
import random
import numpy as np


width, height = 640, 480


black = (0, 0, 0)
green = (0, 255, 0)
red = (255, 0, 0)


block_size = 20
speed = 15

class SnakeGame:
    def __init__(self, width, height, block_size):
        self.width = width
        self.height = height
        self.block_size = block_size
        self.reset()

    def reset(self):
        initial_position = [self.width // 2, self.height // 2]
        self.snake = [
            initial_position,
            [initial_position[0] - self.block_size, initial_position[1]],
            [initial_position[0] - 2 * self.block_size, initial_position[1]]
        ]
        self.direction = 'UP'
        self.food = [random.randrange(1, self.width // self.block_size) * self.block_size,
                     random.randrange(1, self.height // self.block_size) * self.block_size]
        self.score = 0
        self.done = False
        return self.get_state()

    def step(self, action):
        directions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
        if self.direction != 'UP' and action == 1:
            self.direction = 'DOWN'
        elif self.direction != 'DOWN' and action == 0:
            self.direction = 'UP'
        elif self.direction != 'LEFT' and action == 3:
            self.direction = 'RIGHT'
        elif self.direction != 'RIGHT' and action == 2:
            self.direction = 'LEFT'

        # 计算食物的距离以判断是否靠近食物
        distance_to_food_before = self.distance(self.snake[0], self.food)

        # 移动蛇
        x, y = self.snake[0]
        if self.direction == 'UP':
            y -= block_size
        elif self.direction == 'DOWN':
            y += block_size
        elif self.direction == 'LEFT':
            x -= block_size
        elif self.direction == 'RIGHT':
            x += block_size
        new_head = [x, y]


        if x < 0 or x >= width or y < 0 or y >= height:
            self.done = True
            reward = -500  # 撞墙的惩罚
            return self.get_state(), reward, self.done
        if new_head in self.snake:
            self.done = True
            reward = -200  # 撞到自身的严重惩罚
            return self.get_state(), reward, self.done


        self.snake.insert(0, new_head)
        if new_head == self.food:
            self.score += 1
            reward = 500  # 吃到食物的奖励
            self.food = [random.randrange(1, width // block_size) * block_size,
                         random.randrange(1, height // block_size) * block_size]
        else:
            self.snake.pop()


            distance_to_food_after = self.distance(new_head, self.food)
            if distance_to_food_after < distance_to_food_before:
                reward = 30  # 靠近食物的奖励
            else:
                reward = -15  # 无进展的小惩罚

        # 检查是否长时间直线移动
        if len(set([part[0] for part in self.snake])) == 1 or len(set([part[1] for part in self.snake])) == 1:
            if len(self.snake) > 5:  # 如果蛇的长度超过一定阈值
                reward -= 5  # 长时间直线移动的小惩罚

        return self.get_state(), reward, self.done

    def distance(self, point1, point2):
        return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** 0.5

    def get_state(self):
        head = self.snake[0]
        point_l = [head[0] - self.block_size, head[1]]
        point_r = [head[0] + self.block_size, head[1]]
        point_u = [head[0], head[1] - self.block_size]
        point_d = [head[0], head[1] + self.block_size]

        state = [
            head[0] / self.width, head[1] / self.height,  # 蛇头的相对位置
            self.food[0] / self.width, self.food[1] / self.height,  # 食物的相对位置
            int(self.direction == 'LEFT'), int(self.direction == 'RIGHT'),
            int(self.direction == 'UP'), int(self.direction == 'DOWN'),  # 蛇头的方向
            int(self.is_collision(point_l)), int(self.is_collision(point_r)),
            int(self.is_collision(point_u)), int(self.is_collision(point_d))  # 周围是否会发生碰撞
        ]

        return np.array(state, dtype=float)

    def is_collision(self, point):
        return point[0] < 0 or point[0] >= self.width or point[1] < 0 or point[1] >= self.height or point in self.snake

    def display(self, screen):
        screen.fill(black)
        for part in self.snake:
            pygame.draw.rect(screen, green, pygame.Rect(part[0], part[1], self.block_size, self.block_size))
        pygame.draw.rect(screen, red, pygame.Rect(self.food[0], self.food[1], self.block_size, self.block_size))
        pygame.display.flip()

class QLearningAgent:
    def __init__(self, learning_rate=0.5, discount_rate=0.8, exploration_rate=0.45):
        self.learning_rate = learning_rate
        self.discount_rate = discount_rate
        self.exploration_rate = exploration_rate
        self.q_table = {}

    def get_action(self, state):
        state_key = str(state)
        if state_key not in self.q_table:
            self.q_table[state_key] = np.zeros(4)

        if np.random.rand() < self.exploration_rate:
            return random.randint(0, 3)
        else:
            return np.argmax(self.q_table[state_key])

    def update_q_table(self, state, action, reward, next_state, done):
        state_key = str(state)
        next_state_key = str(next_state)

        if next_state_key not in self.q_table:
            self.q_table[next_state_key] = np.zeros(4)

        next_max = np.max(self.q_table[next_state_key])
        self.q_table[state_key][action] = (1 - self.learning_rate) * self.q_table[state_key][action] + \
                                          self.learning_rate * (reward + self.discount_rate * next_max)

        if done:
            self.exploration_rate *= 0.9999
            if self.exploration_rate < 0.1:
                self.exploration_rate = 0.3

game = SnakeGame(width, height, block_size)
agent = QLearningAgent()
num_episodes = 10000000
visualization_interval = 10000
for episode in range(num_episodes):
    if episode % visualization_interval == 1:
        pygame.init()
        screen = pygame.display.set_mode((width, height))
        visualize = True
    else:
        visualize = False

    state = game.reset()
    done = False
    total_reward = 0

    while not done:
        if visualize:
            game.display(screen)
            clock = pygame.time.Clock()
            clock.tick(12)

        action = agent.get_action(state)
        next_state, reward, done = game.step(action)
        agent.update_q_table(state, action, reward, next_state, done)

        state = next_state
        total_reward += reward

    if visualize:
        pygame.quit()

    print(f"轮次: {episode}, 奖励分数: {total_reward}, 探索率: {agent.exploration_rate}, {agent}")

运行过程截图

代码分析

环境设置

游戏环境是通过Pygame库来创建和管理的。首先,我们初始化Pygame并设置游戏窗口的尺寸。接着,定义了几种基本颜色用于绘制游戏元素,如蛇身和食物。

import pygame
import random

width, height = 640, 480  # 游戏窗口的宽度和高度
black = (0, 0, 0)  # 背景颜色
green = (0, 255, 0)  # 蛇的颜色
red = (255, 0, 0)  # 食物的颜色
block_size = 20  # 每个方块的大小

蛇的行为定义

SnakeGame类封装了蛇的行为和游戏逻辑。蛇的初始状态是位于屏幕中心,长度为3个方块,方向向上。蛇的每一部分都是一个方块,我们通过一个列表来维护这些方块的坐标。

Q学习代理实现

QLearningAgent类实现了Q学习算法。它使用一个Q表来存储和更新状态-动作对的Q值,并根据ϵ-贪婪策略来选择动作。

Q学习代理实现

QLearningAgent类实现了Q学习算法。它使用一个Q表来存储和更新状态-动作对的Q值,并根据ϵ-贪婪策略来选择动作。

game = SnakeGame(width, height, block_size)
agent = QLearningAgent(learning_rate=0.5, discount_rate=0.8, exploration_rate=0.45)

for episode in range(num_episodes):
    state = game.reset()
    done = False

    while not done:
        action = agent.get_action(state)
        next_state, reward, done = game.step(action)
        agent.update_q_table(state, action, reward, next_state, done)
        state = next_state

        通过这个过程,Q学习代理逐渐学会了如何在贪吃蛇游戏中做出更好的决策,从而获得更高的分数。随着训练的进行,我们可以观察到代理的性能逐渐提高,这表明它正在学习和适应游戏环境。

小结

        本文通过结合Python和Pygame库实现了一个经典的贪吃蛇游戏,并引入了Q学习算法,使得人工智能代理能够自主学习如何玩游戏并提高其性能。通过详细解析游戏设计、Q学习的核心原理以及代码实现的每个步骤,我们展示了如何将强化学习应用于实际问题中,快把代码拿走试试看吧

-----------------

以上,欢迎点赞收藏、评论区交流

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

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

相关文章

SORA技术报告

文档链接&#xff1a;https://openai.com/research/video-generation-models-as-world-simulators 文章目录 Video generation models as world simulatorsTurning visual data into patchesVideo compression networkSpacetime latent patchesScaling transformers for video …

Linux使用C语言获取进程信息

Linux使用C语言获取进程信息 Author: OnceDay Date: 2024年2月22日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档: Linux proc目录详解_/proc/mounts-CSDN博客Linux下/proc目录介绍 - 知乎 (zhihu.com)Linux内…

该如何选择适合的服务器

服务器&#xff0c;简单来说&#xff0c;就是一个专门用来为其他计算机提供服务的计算机。 我们熟悉的网站、应用和各种在线服务&#xff0c;绝大多数都运行在一台或多台服务器中&#xff0c;所以说服务器是整个网络世界的基石。 服务器一般具有高速的CPU运算、高数据吞吐、可扩…

CrossOver虚拟机软件2024有哪些功能?最新版本支持哪些游戏?

CrossOver由codewaver公司开发的类虚拟机软件&#xff0c;目的是使linux和Mac OS X操作系统和window系统兼容。CrossOver不像Parallels或VMware的模拟器&#xff0c;而是实实在在Mac OS X系统上运行的一个软件。CrossOvers能够直接在Mac上运行Windows软件与游戏&#xff0c;而不…

算法练习-组合【回溯算法】(思路+流程图+代码)

难度参考 难度&#xff1a;困难 分类&#xff1a;回溯算法 难度与分类由我所参与的培训课程提供&#xff0c;但需 要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0…

Code-Audit(代码审计)习题记录6-7

介绍&#xff1a; 自己懒得搭建靶场了&#xff0c;靶场地址是 GitHub - CHYbeta/Code-Audit-Challenges: Code-Audit-Challenges为了方便在公网练习&#xff0c;可以随地访问&#xff0c;本文所有的题目均来源于网站HSCSEC-Code Audit 6、习题6 题目内容如下&#xff1a; 源代…

Python+Flask低代码数据融合引擎工具

我用了2年多时间开发了一个低代码数据融合引擎工具 1.整体界面 2.主要功能 1)通过excel文件生成mysql数据表结构及数据保存 说明:功能细节包括(excel文件上传,文件内容预览,建表导入数据),难点在于对excel数据类型判断,并与mysql数据类型对应 2)建立数据表结构并批量导入数据 …

python程序设计基础:字符串与正则表达式

第四章&#xff1a;字符串与正则表达式 4.1字符串 最早的字符串编码是美国标准信息交换码ASCII&#xff0c;仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASCII码采用1个字节来对字符进行编码&#xff0c;最多只能表示256个符号。 随着信息技…

Ubuntu20.04开启/禁用ipv6

文章目录 Ubuntu20.04开启/禁用ipv61.ipv62. 开启ipv6step1. 编辑sysctl.confstep2. 编辑网络接口配置文件 3. 禁用ipv6&#xff08;sysctl&#xff09;4. 禁用ipv6&#xff08;grub&#xff09;附&#xff1a;总结linux网络配置 Ubuntu20.04开启/禁用ipv6 1.ipv6 IP 是互联网…

openssl

最新版本3.0 使用 生成自签名的根证书 openssl req -x509 -new -key rootCA.key -days 3650 -out rootCA.crt -subj "/CCA/STCA/LCA/OCA/OUCA/CNCA" pem格式 BASE64&#xff0c;会有PUBLIC KEY表示公钥&#xff0c;PRIVATE KEY表示私钥 根据私钥生成公钥 openss…

工业信息安全的神秘武器——德迅卫士(主机安全)

前言&#xff1a; 服务器作为承载公司业务及内部运转的底层平台&#xff0c;其稳定、安全地运行是公司的正常发展的前提保障。由于主机上运行着各种各样的业务&#xff0c;会存在着各类漏洞及安全问题。攻击者以此为目标&#xff0c;通过对服务器的攻击来获利&#xff0c;给公司…

英文输入法(C 语言)

题目来自于博主算法大师的专栏&#xff1a;最新华为OD机试C卷AB卷OJ&#xff08;CJavaJSPy&#xff09; https://blog.csdn.net/banxia_frontend/category_12225173.html 题目 主管期望你来实现英文输入法单词联想功能&#xff0c;需求如下&#xff1a; 依据用户输入的单词前…

Java智慧工地云综合管理平台SaaS源码 助力工地实现精细化管理

目录 智慧工地系统介绍 1、可视化大屏 2、视频监控 3、Wi-Fi安全教育 4、环境监测 5、高支模监测 6、深基坑监测 7、智能水电监测 8、塔机升降安全监测 智慧工地系统功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监…

三分钟快速搭建家纺行业小程序商城:轻松实现电子商务梦想

随着互联网的普及和移动设备的广泛使用&#xff0c;越来越多的商业活动正在向数字化转型。在这个过程中&#xff0c;小程序商城作为一种新型的电子商务模式&#xff0c;正逐渐受到商家的青睐。本文将通过具体步骤&#xff0c;指导读者如何开发一个纺织辅料小程序商城。 一、选择…

Capto 一款适用Mac屏幕录制编辑软件

Capto 是一款功能强大的 Mac 屏幕录制和编辑软件&#xff0c;能够满足用户的多种录制和编辑需求。无论是个人还是专业用户&#xff0c;都可以通过 Capto 实现高质量的屏幕录制和编辑。 首先&#xff0c;Capto 提供了全面的屏幕录制功能&#xff0c;包括全屏、选中区域、甚至是摄…

Nest.js权限管理系统开发(三)环境变量与配置文件

一般来说数据库的配置包含了一些敏感信息&#xff0c;不宜写在代码中提交到远程仓库&#xff0c;所以我们可以将配置写在配置文件中,然后提交 git 时候将生产环境的配置文件其忽略。我们可以新建.env和.env.prod两个文件分别存放开发与生产环境配置&#xff0c;也可以使用YAML等…

Linux【动静态库】

目录 1.软硬链接 1.1软硬链接的语法 1.2理解软硬链接 1.3目录文件的硬链接 1.4应用场景 1.5ACM时间 2.动静态库 2.1认识库 3.制作静态库 3.1静态库打包 3.2静态库的使用 4.制作动态库 4.1动态库打包 4.2动态库的链接使用 4.3动态库的链接原理 总结&#xff1…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--强化学习等

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 分类: 大语言模型LLM视觉模型VLM扩散模型视觉…

Kotlin 基本语法5 继承,接口,枚举,密封

1.继承与重写的Open关键字 open class Product(val name:String ) {fun description() "Product: $name"open fun load() "Nothing .."}class LuxuryProduct:Product("Luxury"){//继承需要调用 父类的主构造函数override fun load(): String {…

热点参数流控(Sentinel)

热点参数流控 热点流控 资源必须使用注解 @SentinelResource编写接口 以及 热点参数流控处理器 /*** 热点流控 必须使用注解 @SentinelResource* @param id* @return*/ @RequestMapping("/getById/{id}") @SentinelResource(value = "getById", blockHand…