2021深圳杯数学建模D题---基于DDPG算法的微分博弈问题(思路及代码)

article/2025/9/27 19:31:50

文章目录

    • 前言
    • 思路
    • 代码
      • gym环境
      • DDPG算法
      • 测试代码
    • 结果
      • 一只犬一只羊的情况
        • 回报收敛的趋势图
        • 羊的逃逸路径
        • 犬的追捕极角
        • 羊的逃逸极角
        • 羊的逃逸半径
      • 两只犬一只羊的情况
        • 回报收敛的趋势图
        • 羊的逃逸路径
        • 羊的逃逸极角
        • 羊的逃逸半径
        • 犬1的追捕极角
        • 犬2的追捕极角
    • conda环境配置

前言

此次拿深圳杯作为数学建模国赛的模拟测试,感觉对于国赛本身来说是没有任何帮助的(笑死)
但是在这个过程中感觉还是学到了非常多的知识,主要是强化学习和运动学建模这一块
下面就简单的分享一下吧

思路

思路就是利用DDPG算法(可以处理连续动作空间)来对羊进行强化学习训练,使得羊领悟出逃出圆形草地的方法

具体思路看代码就懂了(talk is cheap,show you code)

这是整个算法的流程图
在这里插入图片描述

代码

gym环境

'''
自己设置的环境类
智能体:羊
环境:羊、犬和圆形草地,犬采用最优围堵策略围堵羊,若羊在一段时间内逃出圈则胜利,这段时间内没逃出或者被犬抓到则失败;
状态空间:整个圆组成的点集,是二维的;
动作空间:羊每一步可采取的动作的集合
回报的设计:参照pendulum-v0游戏环境源码中的回报的设计方案。
'''
import gym
from gym import spaces
import numpy as np
import math
import random
from gym.envs.classic_control import renderingsigma=10# 将弧度转换为角度
def trans(tmp):return 360*(tmp/(2*np.pi))# 更新犬的状态
def change_dog_state(thetaP,thetaE,delta_theta):new_thetaP=thetaPclockwise = (thetaP - delta_theta + 2 * np.pi) % (2 * np.pi)  # 顺时针counterclockwise = (thetaP + delta_theta + 2 * np.pi) % (2 * np.pi)  # 逆时针if thetaE > thetaP:if thetaE - thetaP >= np.pi:new_thetaP = clockwiseelse:new_thetaP = counterclockwiseelif thetaE < thetaP:if thetaP - thetaE >= np.pi:new_thetaP = counterclockwiseelse:new_thetaP = clockwisereturn new_thetaP# 计算夹角
def cal_angel(theta1,theta2):ans=0if theta1 > theta2:ans = theta1 - theta2if ans > np.pi:ans = 2 * np.pi - ans  # (补)角else:ans = theta2 - theta1if ans > np.pi:ans = 2 * np.pi - ansreturn ans# 判断羊是否给抓住
def catch(R,theta1,theta2,theta3):x=R*np.cos(theta1)y=R*np.sin(theta1)a=R*np.cos(theta2)b=R*np.sin(theta2)A=R*np.cos(theta3)B=R*np.sin(theta3)len1=math.sqrt((x-a)*(x-a)+(y-b)*(y-b))len2=math.sqrt((x-A)*(x-A)+(y-B)*(y-B))if len1 <= sigma and len2 <= sigma:return Trueelse:return Falseclass dogSheepEnv(gym.Env):def __init__(self):# self.dt = 0.2  # 采样时间self.dt=0.2# self.thetaP=np.pi/2# 狗的极坐标self.thetaP = random.uniform(0, 2 * np.pi)# 狗1的极坐标self.wP=np.pi/5# 狗的角速度self.thetaP2=random.uniform(0, 2 * np.pi)# 狗1的极坐标self.vE=32# 羊的速度self.thetaE=np.pi/2# 羊的极坐标self.radiusE=0# 羊的极坐标半径self.R=100# 圆的半径self.state=np.array([self.thetaE,self.radiusE,self.thetaP,self.thetaP2])# 环境的初始状态self.viewer = rendering.Viewer(400, 400)# 画板self.lambda1=0.07# reward的参数1self.lambda2=3.1# reward的参数2self.lambda3=3.1self.lambda4=6.2# 自定义动作空间,观察空间self.action_space = spaces.Box(# 羊的动作空间即为转动的角度,会根据当前位置进行变化# 由于怕出现low比high还大的情况,我们的action_space就不做周期处理,用的时候取余2pi就行low=0, high=2*np.pi, shape=(1,), dtype=np.float32)self.observation_space = spaces.Box(# 状态空间为 theta_E,R_E,theta_Plow=np.array([0,0,0,0]),high=np.array([2*np.pi,self.R,2*np.pi,2*np.pi]),dtype=np.float32)'''羊接受一个动作进行位移: 使用PG算法的choose_action犬沿劣弧进行位移接着判断游戏是否结束评价这个动作的回报'''def step(self, action):# u为action# print('action: ',action)# 根据action(即θ_E'来计算新的状态)self.state = self._get_observation(action)reward = self._get_reward()done = self._get_done()if done:# 如果逃脱失败,给予惩罚if catch(self.R,self.state[0],self.state[2],self.state[3]):reward=reward-1000print('be catched')else:reward=0print('no be catched')return self.state,reward,done# 获取reward,根据action作用之后的state来计算rewarddef _get_reward(self):# thetaP=self.state[2]# thetaP2=self.state[3]# thetaE=self.state[0]thetaE,thetaP,thetaP2=self.state[0],self.state[2],self.state[3]delta_theta1=cal_angel(thetaE,thetaP)# 羊与犬1的夹角delta_theta2=cal_angel(thetaE,thetaP2)# 羊与犬2的夹角delta_theta3=cal_angel(thetaP,thetaP2)# 两犬之间的夹角# a=self.state[1]# b=self.R# distance=math.sqrt(a*a+b*b-2*a*b*np.cos(delta_theta))# 羊距圆周越近越好(radiusE越大越好),羊与犬的夹角越大越好,羊离犬越远越好# print('r1: ',self.lambda1 * abs(self.R - self.state[1]))# print('r2: ',self.lambda2 * abs(np.pi-delta_theta1))# print('r3: ',self.lambda3 * abs(np.pi-delta_theta2))# print('r4: ',self.lambda4 * abs(delta_theta3))return -(# 想要趋近于零self.lambda1 * abs(self.R - self.state[1])# 范围 [0-2*R(200)]+ self.lambda2 * abs(np.pi-delta_theta1) # 范围 [0-100]+ self.lambda3 * abs(np.pi-delta_theta2) # 范围 [0-100]+ self.lambda4 * abs(delta_theta3)   # 范围 [0-100])# 判断游戏是否结束def _get_done(self):if self.state[1]>=self.R:return Trueelse:return False# 根据action修改环境,改变状态def _get_observation(self,action):# 已知现在的位置,首先计算位移后羊的极坐标xb=self.state[1]*np.cos(self.state[0])+self.vE*self.dt*np.cos(action)yb=self.state[1]*np.sin(self.state[0])+self.vE*self.dt*np.sin(action)new_radiusE=math.sqrt(xb*xb+yb*yb)# 由xb和yb进行θ转换,# 返回弧度pinew_thetaE=math.atan2(yb,xb)new_thetaE=(new_thetaE+2*np.pi)%(2*np.pi)# 根据羊的action,选择狼的位移方向并位移delta_theta=self.wP*self.dtthetaE = self.state[0]# 修改犬1的状态thetaP = self.state[2]# 犬1的原状态new_thetaP=change_dog_state(thetaP,thetaE,delta_theta)# 犬1的新状态# 修改犬2的状态thetaP2 = self.state[3]  # 犬1的原状态new_thetaP2 = change_dog_state(thetaP2, thetaE, delta_theta)  # 犬1的新状态# 相等的话就保持原状态return np.array([new_thetaE,new_radiusE,new_thetaP,new_thetaP2])# 重置羊和犬的状态def reset(self):thetaE=random.uniform(0, 2 * np.pi)thetaE2=(thetaE+np.pi)%(2*np.pi)self.state=np.array([0,0,thetaE,thetaE2],dtype=float)return np.array(self.state)# 画画显示犬和羊的状态def render(self):# 清空轨迹# self.viewer.geoms.clear()# 绘制大圆ring = rendering.make_circle(radius=self.R,res=50,filled=False)transform1 = rendering.Transform(translation=(200, 200))  # 相对偏移ring.add_attr(transform1)# 让圆添加平移这个属性self.viewer.add_geom(ring)# 绘制犬1xP,yP=self.R*np.cos(self.state[2]),self.R*np.sin(self.state[2])ringP = rendering.make_circle(radius=2, res=50, filled=True)ringP.set_color(0,0,1)transform_P = rendering.Transform(translation=(200+xP, 200+yP))  # 相对偏移ringP.add_attr(transform_P)  # 让圆添加平移这个属性self.viewer.add_geom(ringP)# 绘制犬2xP2, yP2 = self.R * np.cos(self.state[3]), self.R * np.sin(self.state[3])ringP2 = rendering.make_circle(radius=2, res=50, filled=True)ringP2.set_color(0, 0, 1)transform_P2 = rendering.Transform(translation=(200 + xP2, 200 + yP2))  # 相对偏移ringP2.add_attr(transform_P2)  # 让圆添加平移这个属性self.viewer.add_geom(ringP2)# 绘制羊xE, yE = self.state[1] * np.cos(self.state[0]), self.state[1] * np.sin(self.state[0])ringE = rendering.make_circle(radius=2, res=50, filled=True)ringE.set_color(1, 0, 0)transform_E = rendering.Transform(translation=(200+xE, 200+yE))  # 相对偏移ringE.add_attr(transform_E)  # 让圆添加平移这个属性self.viewer.add_geom(ringE)return self.viewer.render()# env = dogSheepEnv()
# while True:
#     env.reset()
#     for _ in range(2000):
#         env.render()
#         action=random.uniform(0,2*np.pi)
#         action=np.clip(action,env.state[0]-np.pi/2,env.state[0]+np.pi/2)
#         action=(action+2*np.pi)%(2*np.pi)
#         state, reward, done = env.step(action) # 和环境交互
#         if done:
#             break

DDPG算法

import tensorflow as tf
import numpy as np#####################  超参数 ####################LR_A = 0.001    # learning rate for actor
LR_C = 0.001    # learning rate for critic
GAMMA = 0.9     # reward discount
TAU = 0.01      # soft replacement
MEMORY_CAPACITY = 10000
BATCH_SIZE = 32class DDPG(object):def __init__(self, a_dim, s_dim, a_bound,):self.memory = np.zeros((MEMORY_CAPACITY, s_dim * 2 + a_dim + 1), dtype=np.float32)self.pointer = 0self.memory_full = Falseself.sess = tf.Session()self.a_replace_counter, self.c_replace_counter = 0, 0# self.a_dim, self.s_dim, self.a_bound = a_dim, s_dim, a_bound[1]self.a_dim, self.s_dim, self.a_bound = a_dim, s_dim, a_boundself.S = tf.placeholder(tf.float32, [None, s_dim], 's')self.S_ = tf.placeholder(tf.float32, [None, s_dim], 's_')self.R = tf.placeholder(tf.float32, [None, 1], 'r')with tf.variable_scope('Actor'):self.a = self._build_a(self.S, scope='eval', trainable=True)a_ = self._build_a(self.S_, scope='target', trainable=False)with tf.variable_scope('Critic'):# assign self.a = a in memory when calculating q for td_error,# otherwise the self.a is from Actor when updating Actorq = self._build_c(self.S, self.a, scope='eval', trainable=True)q_ = self._build_c(self.S_, a_, scope='target', trainable=False)# networks parametersself.ae_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/eval')self.at_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Actor/target')self.ce_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/eval')self.ct_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='Critic/target')# target net replacementself.soft_replace = [[tf.assign(ta, (1 - TAU) * ta + TAU * ea), tf.assign(tc, (1 - TAU) * tc + TAU * ec)]for ta, ea, tc, ec in zip(self.at_params, self.ae_params, self.ct_params, self.ce_params)]q_target = self.R + GAMMA * q_# in the feed_dic for the td_error, the self.a should change to actions in memorytd_error = tf.losses.mean_squared_error(labels=q_target, predictions=q)self.ctrain = tf.train.AdamOptimizer(LR_C).minimize(td_error, var_list=self.ce_params)a_loss = - tf.reduce_mean(q)    # maximize the qself.atrain = tf.train.AdamOptimizer(LR_A).minimize(a_loss, var_list=self.ae_params)self.sess.run(tf.global_variables_initializer())def choose_action(self, s):return self.sess.run(self.a, {self.S: s[None, :]})[0]def learn(self):# soft target replacementself.sess.run(self.soft_replace)indices = np.random.choice(MEMORY_CAPACITY, size=BATCH_SIZE)bt = self.memory[indices, :]bs = bt[:, :self.s_dim]ba = bt[:, self.s_dim: self.s_dim + self.a_dim]br = bt[:, -self.s_dim - 1: -self.s_dim]bs_ = bt[:, -self.s_dim:]self.sess.run(self.atrain, {self.S: bs})self.sess.run(self.ctrain, {self.S: bs, self.a: ba, self.R: br, self.S_: bs_})def store_transition(self, s, a, r, s_):transition = np.hstack((s, a, [r], s_))index = self.pointer % MEMORY_CAPACITY  # replace the old memory with new memoryself.memory[index, :] = transitionself.pointer += 1if self.pointer > MEMORY_CAPACITY:      # indicator for learningself.memory_full = Truedef _build_a(self, s, scope, trainable):with tf.variable_scope(scope):net = tf.layers.dense(s, 100, activation=tf.nn.relu, name='l1', trainable=trainable)a = tf.layers.dense(net, self.a_dim, activation=tf.nn.tanh, name='a', trainable=trainable)return tf.multiply(a, self.a_bound, name='scaled_a')def _build_c(self, s, a, scope, trainable):with tf.variable_scope(scope):n_l1 = 100w1_s = tf.get_variable('w1_s', [self.s_dim, n_l1], trainable=trainable)w1_a = tf.get_variable('w1_a', [self.a_dim, n_l1], trainable=trainable)b1 = tf.get_variable('b1', [1, n_l1], trainable=trainable)net = tf.nn.relu(tf.matmul(s, w1_s) + tf.matmul(a, w1_a) + b1)return tf.layers.dense(net, 1, trainable=trainable)  # Q(s,a)def save(self):saver = tf.train.Saver()saver.save(self.sess, './params', write_meta_graph=False)def restore(self):saver = tf.train.Saver()saver.restore(self.sess, './params')

测试代码

import mathimport numpy as npfrom env import dogSheepEnv
from rl import DDPG
import matplotlib.pyplot as plt
import timeMAX_EPISODES = 200# 比赛次数
MAX_EP_STEPS = 2000# 每把比赛的步数
ON_TRAIN = False# 控制程序是进行训练还是进行测试
sigma=10 # 碰撞精度# reward_list=[]# 准备画图
# ep_reward_list=[]
thetaP_list=[]
thetaP2_list=[]
thetaE_list=[]
rE_list=[]# 设置环境
env = dogSheepEnv()
# 设置维度
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.shape[0]
action_bound = env.action_space.high# 设置强化学习模型
rl = DDPG(action_dim, state_dim, action_bound)# 判断羊是否给抓住
def catch(R,theta1,theta2,theta3):x=R*np.cos(theta1)y=R*np.sin(theta1)a=R*np.cos(theta2)b=R*np.sin(theta2)A=R*np.cos(theta3)B=R*np.sin(theta3)len1=math.sqrt((x-a)*(x-a)+(y-b)*(y-b))len2=math.sqrt((x-A)*(x-A)+(y-B)*(y-B))if len1 <= sigma and len2 <= sigma:return Trueelse:return Falsedef trans(tmp):return 360*(tmp/(2*np.pi))# def dis(R,theta1,theta2):
#     x=R*np.cos(theta1)
#     y=R*np.sin(theta1)
#     a=R*np.cos(theta2)
#     b=R*np.sin(theta2)
#     len=math.sqrt((x-a)*(x-a)+(y-b)*(y-b))
#     if len <= sigma:
#         return False
#     else:
#         return True# 训练过程
'''
env和算法的交互
传state
将一次学习的经历装进记忆库rl模型一直将学习经历填进记忆库,直到记忆库满了才开始学习
填充记忆库的过程中,环境不断地交互
'''
def train():for i in range(MAX_EPISODES):print('i: ',i)state = env.reset()ep_reward = 0.# 单局比赛的总rewardfor j in range(MAX_EP_STEPS):env.render()# 画图action = rl.choose_action(state)# 算法预测下一个动作action=np.random.normal(action,scale=0.01) # 随机一下# 这里限制一下动作空间action=np.clip(action,env.state[0]-np.pi/2,env.state[0]+np.pi/2)action=(action+2*np.pi)%(2*np.pi)_state, reward, done = env.step(action) # 和环境交互# reward_list.append(reward)# print('reward: ',reward)# print('i: ',i,' choose_action: ', trans(action[0]),' reward: ',reward,' state: ',_state)rl.store_transition(state, action, reward, _state)# 把这次经历装进记忆库ep_reward += reward# 记忆模块填完之后算法开始学习if rl.memory_full:rl.learn()state = _state# time.sleep(0.2)if done or j == MAX_EP_STEPS-1: # 结束# if env.state[1] >= env.R and dis(env.R,env.state[0],env.state[2]):if (env.state[1] >= env.R) and (not catch(env.R, env.state[0], env.state[2],env.state[3])):print('sheep win')else:print('dog win')# ep_reward_list.append(ep_reward)print('Ep: %i | %s | ep_r: %.1f | steps: %i' % (i, '---' if not done else 'done', ep_reward, j))breakrl.save() # 保存模型# 测试
def eval():rl.restore()# 提取模型# env.render()# env.viewer.set_vsync(True)# while True:#     # print('新的一次')#     state = env.reset()#     for _ in range(1000):#         env.render()#         action = rl.choose_action(state)#         action = np.random.normal(action, scale=0.01)  # 随机一下#         # 这里限制一下动作空间#         action = np.clip(action, env.state[0] - np.pi / 2, env.state[0] + np.pi / 2)#         action = (action + 2 * np.pi) % (2 * np.pi)#         # print('choose action: ',action,'state: ',env.state)#         state, reward, done = env.step(action)#         thetaE_list.append(state[0])#         rE_list.append(state[1])#         thetaP_list.append(state[2])#         if done:#             if env.state[1] >= env.R and dis(env.R,env.state[0],env.state[2]):#                 print('sheep win')#             else:#                 print('dog win')#             breakstate = env.reset()print('thetaP: ',state[2])print('thetaP2: ', state[3])for _ in range(1000):env.render()action = rl.choose_action(state)# 这里限制一下动作空间action = np.clip(action, env.state[0] - np.pi / 2, env.state[0] + np.pi / 2)action = (action + 2 * np.pi) % (2 * np.pi)state, reward, done = env.step(action)thetaE_list.append(state[0])rE_list.append(state[1])thetaP_list.append(state[2])thetaP2_list.append(state[3])# print('choose action: ', action,' reward: ',reward, 'state: ', env.state)if done:breakinput('input: ')if ON_TRAIN:train()
else:eval()# 画reward图
# plt.figure()
# len2=len(ep_reward_list)
# plt.plot(list(range(len2)),ep_reward_list)
# plt.title('reward convergence trend ')
# plt.xlabel('steps')
# plt.ylabel("reward")
# plt.show()# 画犬1的图
plt.figure()
plt.plot(list(range(len(thetaP_list))),thetaP_list)
plt.title('pursuer1 theta')
plt.xlabel('steps')
plt.ylabel("theta")
plt.show()# 画犬2的图
plt.figure()
plt.plot(list(range(len(thetaP2_list))),thetaP2_list)
plt.title('pursuer2 theta')
plt.xlabel('steps')
plt.ylabel("theta")
plt.show()# 画羊的极角
plt.figure()
plt.plot(list(range(len(thetaE_list))),thetaE_list)
plt.title('escaper theta')
plt.xlabel('steps')
plt.ylabel("theta")
plt.show()# 画羊的极径
plt.figure()
plt.plot(list(range(len(rE_list))),rE_list)
plt.title('escaper radius')
plt.xlabel('steps')
plt.ylabel("radius")
plt.show()

结果

一只犬一只羊的情况

回报收敛的趋势图

在这里插入图片描述

羊的逃逸路径

在这里插入图片描述

犬的追捕极角

在这里插入图片描述

羊的逃逸极角

在这里插入图片描述

羊的逃逸半径

在这里插入图片描述

两只犬一只羊的情况

回报收敛的趋势图

在这里插入图片描述

羊的逃逸路径

在这里插入图片描述

羊的逃逸极角

在这里插入图片描述

羊的逃逸半径

在这里插入图片描述

犬1的追捕极角

在这里插入图片描述

犬2的追捕极角

在这里插入图片描述

conda环境配置

absl-py                   0.13.0                   pypi_0    pypi
astor                     0.8.1                    pypi_0    pypi
astunparse                1.6.3                    pypi_0    pypi
atari-py                  0.2.9                    pypi_0    pypi
ca-certificates           2021.5.30            h5b45459_0    conda-forge
cached-property           1.5.2                    pypi_0    pypi
cachetools                4.2.2                    pypi_0    pypi
certifi                   2021.5.30        py37h03978a9_0    conda-forge
charset-normalizer        2.0.4                    pypi_0    pypi
clang                     5.0                      pypi_0    pypi
cloudpickle               1.6.0                    pypi_0    pypi
cycler                    0.10.0                   pypi_0    pypi
flatbuffers               1.12                     pypi_0    pypi
gast                      0.4.0                    pypi_0    pypi
google-auth               1.35.0                   pypi_0    pypi
google-auth-oauthlib      0.4.5                    pypi_0    pypi
google-pasta              0.2.0                    pypi_0    pypi
grpcio                    1.39.0                   pypi_0    pypi
gym                       0.18.3                   pypi_0    pypi
h5py                      3.1.0                    pypi_0    pypi
idna                      3.2                      pypi_0    pypi
importlib-metadata        4.6.4                    pypi_0    pypi
joblib                    1.0.1                    pypi_0    pypi
keras                     2.6.0                    pypi_0    pypi
keras-applications        1.0.8                    pypi_0    pypi
keras-preprocessing       1.1.2                    pypi_0    pypi
kiwisolver                1.3.1                    pypi_0    pypi
markdown                  3.3.4                    pypi_0    pypi
matplotlib                3.4.3                    pypi_0    pypi
mpi4py                    3.1.1                    pypi_0    pypi
numpy                     1.19.5                   pypi_0    pypi
oauthlib                  3.1.1                    pypi_0    pypi
opencv-python             4.5.3.56                 pypi_0    pypi
openssl                   1.1.1k               h8ffe710_0    conda-forge
opt-einsum                3.3.0                    pypi_0    pypi
pandas                    1.3.2                    pypi_0    pypi
pillow                    8.2.0                    pypi_0    pypi
pip                       21.2.1             pyhd8ed1ab_0    conda-forge
protobuf                  3.17.3                   pypi_0    pypi
pyasn1                    0.4.8                    pypi_0    pypi
pyasn1-modules            0.2.8                    pypi_0    pypi
pyglet                    1.5.15                   pypi_0    pypi
pyparsing                 2.4.7                    pypi_0    pypi
python                    3.7.10          h7840368_100_cpython    conda-forge
python-dateutil           2.8.2                    pypi_0    pypi
python_abi                3.7                     2_cp37m    conda-forge
pytz                      2021.1                   pypi_0    pypi
requests                  2.26.0                   pypi_0    pypi
requests-oauthlib         1.3.0                    pypi_0    pypi
rsa                       4.7.2                    pypi_0    pypi
scipy                     1.7.0                    pypi_0    pypi
setuptools                49.6.0           py37h03978a9_3    conda-forge
six                       1.15.0                   pypi_0    pypi
sqlite                    3.36.0               h8ffe710_0    conda-forge
stable-baselines          2.10.0                   pypi_0    pypi
tensorboard               1.14.0                   pypi_0    pypi
tensorboard-data-server   0.6.1                    pypi_0    pypi
tensorboard-plugin-wit    1.8.0                    pypi_0    pypi
tensorflow                1.14.0                   pypi_0    pypi
tensorflow-estimator      1.14.0                   pypi_0    pypi
termcolor                 1.1.0                    pypi_0    pypi
typing-extensions         3.7.4.3                  pypi_0    pypi
ucrt                      10.0.20348.0         h57928b3_0    conda-forge
urllib3                   1.26.6                   pypi_0    pypi
vc                        14.2                 hb210afc_5    conda-forge
vs2015_runtime            14.29.30037          h902a5da_5    conda-forge
werkzeug                  2.0.1                    pypi_0    pypi
wheel                     0.36.2             pyhd3deb0d_0    conda-forge
wincertstore              0.2             py37h03978a9_1006    conda-forge
wrapt                     1.12.1                   pypi_0    pypi
zipp                      3.5.0                    pypi_0    pypi

http://chatgpt.dhexx.cn/article/gOvQCUoN.shtml

相关文章

代码质量管理 阿里Java插件 + Upsource

代码审查的方式 代码审查主要有两种方式: 1. pre-push:在提交合并代码之前,先进行审查,通过和才能合并。这是一种非常严格的审查方式,可以确保每个发布的代码都是已经被审查过的。这种放到在github上维护的开源项目极其合适,代码的所有者可以确保代码是在自己…

windows10安装upsource后更改访问IP地址

前两天办公室网络总是断开&#xff0c;我电脑的ip就从原来的192.168.2.7 变更为 192.168.2.14&#xff0c;在此之前我安装了upsource&#xff0c;访问的ip地址一直是192.168.2.7 &#xff0c;自从ip变更后&#xff0c;启动upsource系统自动还是会去访问192.168.2.7这个旧地址&a…

代码Review工具upsourse的部署

第1步 解压压缩包找到Upsource目录下的bin目录下的upsource.bat文件&#xff0c;双击启动 进入bin目录 第2步 运行命令行工具&#xff0c;直接把upsource.bat文件拖入命令行工具后空格输入start回车&#xff0c;等待系统安装完即可 第3步 start执行完毕后会打开默认设置的…

Upsource集成Gitlab的身份验证

第一步 打开Upsource&#xff0c;进入到Hub 第二步 进入到Auth Modules 第三步 New module -> Gitlab 第四步 复制下这个Redirect URL&#xff0c;后面有用 第五步 使用管理员账号登录到Gitlab&#xff0c;并打开Settings 第六步 看图 第七步 得到我们的…

Mac看源码时,idea插件RESTfultook居然可以这样用?

安装插件 IntelliJ IDEA --> Preferences --> Plugins&#xff0c;输入restfultoolkit&#xff0c;本地没搜到&#xff0c;就可以点击Search in repositories&#xff08;或直接点击Browse repositories进入搜索&#xff09;&#xff0c;搜到Upsource后选择Install进行安…

docker环境下upsource的安装与配置教程

启动docker&#xff1a;systemctl start docker pull拉取镜像&#xff1a;pull jetbrains/upsource 2017.1.1922 docker iamges 查看下载镜像 运行镜像&#xff1a; 进入命令行模式&#xff0c; ./run.sh 启动upsource&#xff08;已启动则不需要&#xff09; 启动前配…

upsource初探

在JetBrains 的官网上&#xff0c;看到codereview的工具 upsource &#xff0c;https://www.jetbrains.com/upsource/ 官方的英文文档 来看下博客园上有博主简单的中文介绍 upsource的来源 upsource是JetBrains公司在2014年推出的一款通过浏览器查看代码达到团队协作功能的工具…

upyun

upyun 更新时间: 2021-12-31 19:12:21 标签: &#x1f604;Upyun 启 前段时间折腾存储空间&#xff0c;折腾一圈还是又拍云最香&#xff0c;免费。但是自己不小心把一个文件夹删了&#xff0c;想要找回&#xff0c;却没有回收站这个功能&#xff0c;很遗憾&#xff0c;它就这…

docker搭建upsource代码审查工具,通过gitlab检出项目

docker搭建upsource代码审查工具&#xff0c;通过gitlab检出项目 机器配置docker搭建upsource代码审查工具&#xff0c;通过gitlab检出项目拉取镜像创建挂载目录启动容器配置账号密码等信息基于gitlab创建项目Gitlab http协议创建项目基于码云官方Gitlab https创建项目基于私有…

upsource idea gitlab代码评审环境搭建

此文借鉴了两个csdn: 1.https://blog.csdn.net/nikobelic8/article/details/54897314 2.https://blog.csdn.net/qijiqiguai/article/details/78321498 搭建upsource服务器 1.获取zip压缩包&#xff08;upsource的版本可以自己选&#xff09;&#xff1a; wget https://dow…

Upsource的安装和与IDEA产品的配置

Upsource的安装和与JetBrains产品的集成 下载和安装 ## 设置 JetBrains的工具一直都是我开发和学习的好帮手&#xff0c;本人工作主要是PHP开发&#xff0c;使用的是PhpStrom&#xff0c;而这里主要介绍下JetBrains的代码审查工具Upsource。我用的是windows&#xff0c;话不多说…

Upsource的初步使用

2019独角兽企业重金招聘Python工程师标准>>> 市场上有品类繁多的CR工具&#xff0c;今天装了一下Upsource&#xff0c;在此做个记录。 CR工具&#xff1a;https://alili.tech/archive/cf2c83a/ Upsource的安装和使用&#xff1a;http://ju.outofmemory.cn/entry/366…

CodeReview工具:UpSource+SVN+Idea搭建与使用

1 下载、安装、配置 1.1 官网主页下载zip包 https://www.jetbrains.com/upsource/features/ 免费版可以创建10个用户&#xff0c;admin guest 8 user 1.2 安装 配置要求&#xff1a;内存建议8G以上Linux系统配置/etc/security/limits.conffile:&#xff08;可选操作&…

IDEA系列:插件:Upsource【团队代码审核】的具体介绍与使用

我是 ABin-阿斌&#xff1a;写一生代码&#xff0c;创一世佳话&#xff0c;筑一揽芳华。 如果小伙伴们觉得我的文章有点 feel &#xff0c;那就点个赞再走哦。 文章目录 公告前言Upsource是什么主要功能便捷的查看自己的项目不同的Review角色简单方便的Review视图社交化的Revi…

Upsource的下载安装使用

一&#xff0c;下载 下载地址&#xff1a; https://www.jetbrains.com/upsource/用户手册地址 https://jetbrains.com.zh.xy2401.com/help/upsource/creating-managing-users.html下载并解压到指定的文件夹 ├── api ├── apps ├── backups # 备份目录 ├── bin #…

使用Jetbrains Upsource进行Code Review

一、简介 一般的 code review 都是对代码有问题的地方进行标注&#xff0c;Upsource 也有这样的功能。但是 Upsource 可以通过像是聊天或者社区互动的模式&#xff0c;根据代码进行交流。当有人 review 你的代码之后&#xff0c;你的 IDEA 右下角就会弹出聊天框&#xff0c;及…

upsource

1 upsource 1.1 upsource简介: Code review, team collaboration, project analytics(代码审查&#xff0c;团队协作&#xff0c;项目分析) 1.2 upsource官网: https://www.jetbrains.com/upsource/ 1.3 upsource能为代码审查提供哪些便利 对多种类型的代码库与软件开发语言…

代码审查工具Upsource的使用和整合 Intellij IDEA

Upsource主要功能描述 ① 便捷查看自己的项目 Upsource主要基于版本管理软件&#xff0c;因此&#xff0c;只要项目已经交给Upsource管理&#xff0c;就可以方便的看到你所参与的项目&#xff0c;以及最近相关的Feeds。从一个中心位置探索和监测所有的VCS库&#xff0c;使用友…

详解Jetbrains Upsource各平台部署

一、简介 Upsource 是 Jetbrains 公司出品的一款 Code Review 与 Project Analytics 工具&#xff0c;通过与版本管理软件结合&#xff0c;通过社交化的形式&#xff0c;将代码予以团队成员或其他人分享、讨论。Upsource 是一款跨平台工具&#xff0c;支持部署在 Windows、mac…

Upsource——对已签入的代码进行分享、讨论和审查代码

Upsource 一、Upsource简介 Upsource &#xff0c;这是一个专门为软件开发团队所设计的源代码协作工具。Upsource能够与多种版本控制工具进行集成&#xff0c;包括Git、Mercurial、Subversion或Perforce&#xff0c;开发者可以使用这一工具对已签入的代码进行浏览和审查。 您可…