首页 文章 精选 留言 我的

精选列表

搜索[Python],共10000篇文章
优秀的个人博客,低调大师

python-pygame实现飞机大战-5-屏幕渲染绘制分数、生命数、超级炸弹数以及暂停功能

2 --> 本次添加的功能是:屏幕渲染绘制游戏分数、生命数、超级炸弹数以及暂停功能显示如图所示: 所需资源,其中文字资源font无法上传,莫得办法,可以自己去找一下,也可以下载我上面那个包的连接 然后本次在代码模块只要还是main.py的变化,如果有人从头看到这一步的话,会发现一共:main.py:渲染各个组件,运行逻辑,等等,这一步添加了渲染分数、超级炸弹数、生命数、暂停功能bullet.py:主要是子弹的控制,包括子弹各种属性、以及子弹的重置enemy.py:敌机类,包含敌机的属性、运行、重置等myplane.py:主要是玩家飞机的控制,包括玩家飞机各种属性、飞机的上下左右移动,以及飞机的重生supply.py:主要是补给的控制,包括补给的移动以及重置,其实写法都差不多 知识点(建议自己也百度看一下):1.绘制分数文字,**pygame.font.Font.render()*在一个新 Surface 对象上绘制文本pygame.font.Font.render(text, antialias, color, background=None)a. text:要显示的文字b. antialias: 为True时文本图像显示更光滑,为False时文本图像显示有锯齿状c. color:字体颜色d. background:背景颜色(可选参数),默认为小黑屏 2.paused_rect.collidepoint(event.pos)buttons – 一个含有三个数字的元组,三个值分别代表左键、中键和右键,1就是按下了。pos – 就是位置了……rel – 代表了现在距离上次产生鼠标事件时的距离 这里直接放上去main.py的代码,其他的代码就在这一步不放上来了,不然会很多(这不能直接放.py文件就很难受),需要的话可以去前面几步查看,或者去那个包里面下载全部的。 import pygame import sys import traceback from pygame.locals import * from random import * import myplane import enemy import bullet import supply # 初始化 pygame.init() # 设置窗口大小 bg_size = width, height = 400, 700 # 实际上是元组 screen = pygame.display.set_mode(bg_size) # 设置窗口 pygame.display.set_caption("飞机大战") # 窗口标题 # 加载背景图片,对于普通图像的显示效果有没有convert都是一样的,但是 使用 convert 可以转换格式,提高 blit 的速度 background = pygame.image.load("images/background.png").convert() # 设置黑、绿、红、百几种颜色对应值,后面会用到 BLACK = (0, 0, 0) GREEN = (0, 255, 0) RED = (255, 0, 0) WHITE = (255, 255, 255) # 生成敌方小型飞机 def add_small_enemy(small_enemies, enemiesGroup, num): for i in range(num): smallenemy = enemy.SmallEnemy(bg_size) # 精灵组来实现多个图像,很适合处理精灵列表,有添加,移除,绘制,更新等方法 # Group.sprites 精灵组 # Group.copy 复制 # Group.add 添加 # Group.remove 移除 # Group.has 判断精灵组成员 # Group.update 更新 # Group.draw 位块显示 # Group.clear - 绘制背景 # Group.empty 清空 # 将这一组敌机都添加上小型飞机属性,相当于统一处理,统一赋值 small_enemies.add(smallenemy) enemiesGroup.add(smallenemy) def main(): # 创建时钟对象(可以控制游戏循环频率) clock = pygame.time.Clock() # 生成玩家飞机 me = myplane.MyPlane(bg_size) # 存放所有敌方飞机,这个飞机组包含了小型飞机、中型飞机、大型飞机的各种属性,只要用于处理碰撞 # 当程序中有大量的实体的时候,操作这些实体将会是一件相当麻烦的事 # 使用pygame.sprite.Group()函数可以创建一个精灵组,从而统一管理,这里创建了一个敌机组 enemiesGroup = pygame.sprite.Group() # 生成地方小型飞机,敌方小型飞机也是一个组,进行统一处理 small_enemies = pygame.sprite.Group() add_small_enemy(small_enemies, enemiesGroup, 15) # 生成普通子弹,这里是四颗子弹循环 bullet1s = [] # 标记发生的哪颗子弹 bullet1s_index = 0 # 子弹数目 bullet1_num = 4 for i in range(bullet1_num): # 把玩家飞机的位置发给子弹类 bullet1s.append(bullet.Bullet1(me.rect.midtop)) # 生成加强子弹,这里是八颗子弹循环,左右各四颗 bulletspro = [] # 标记发生的哪颗子弹 bulletspro_index = 0 # 子弹数目 bulletspro_num = 8 # 左右各压入四颗子弹,//2表示的整除,其实用/2也一样 for i in range(bulletspro_num // 2): # 这里(me.rect.centerx - 33, me.rect.centery)是指元组位置,centerx代表x轴,centery代表y轴 bulletspro.append(bullet.Bullet2((me.rect.centerx - 33, me.rect.centery))) bulletspro.append(bullet.Bullet2((me.rect.centerx + 33, me.rect.centery))) # 初始化加强子弹补给,超级炸弹补给 bullet_supply = supply.Bullet_Supply(bg_size) bomb_supply = supply.Bomb_Supply(bg_size) # 设置无敌时间事件,pygame.USEREVENT代表事件1,pygame.USEREVENT+1代表事件2,以此类推,这里相当于定义了一个事件 invincible_event = pygame.USEREVENT # 设置补给时间事件 bullet_time_supply = pygame.USEREVENT + 1 # 设置加强子弹定时器事件,即加强子弹buff持续事件 bulletpro_time = pygame.USEREVENT + 2 # 设置定时器,8秒钟发放一次补给 pygame.time.set_timer(bullet_time_supply, 8 * 1000) # 标记是否使用超级子弹 is_double_bullet = False # 玩家三条命 life_num = 3 life_image = pygame.image.load('images/life.png').convert_alpha() life_rect = life_image.get_rect() # 玩家带有超级炸弹数量 bomb_num = 3 # 绘制超级炸弹 bomb_image = pygame.image.load('images/bomb.png').convert_alpha() # 超级炸弹图片位置 bomb_rect = bomb_image.get_rect() # 超级炸弹数量字体 bomb_font = pygame.font.Font('font/font.ttf', 48) # 游戏暂停,默认为非暂停状态 paused = False # 暂停图片 pause_nor_image = pygame.image.load('images/pause_nor.png').convert_alpha() pause_pressed_image = pygame.image.load('images/pause_pressed.png').convert_alpha() # 继续图片 resume_nor_image = pygame.image.load('images/resume_nor.png').convert_alpha() resume_pressed_image = pygame.image.load('images/resume_pressed.png').convert_alpha() # 设置默认图片 paused_image = pause_nor_image # 暂停按钮位置 paused_rect = pause_nor_image.get_rect() paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10 # 控制玩家飞机图片切换,展示突突突的效果 switch_image = True # 切换延时 delay = 100 # 游戏分数 score = 0 # 设定玩家分数字体样式,从一个字体文件创建一个 Font 对象 score_font = pygame.font.Font('font/font.ttf', 36) # 飞机爆炸的图片下标,依次为小型敌机,中型敌机,大型敌机,玩家飞机的爆炸的图片的下标,切换下标来改变爆炸图片 e1_destory_index = 0 e2_destory_index = 0 e3_destory_index = 0 me_destory_index = 0 running = True while running: # 获取事件 for event in pygame.event.get(): # 结束事件触发结束操作 if event.type == QUIT: pygame.quit() sys.exit() # 在触发碰撞的时候,写了pygame.time.set_timer(invincible_event, 3*1000) # 意思就是3秒后将会执行invincible_event事件,这里捕获了invincible_event事件,执行后,将取消这个计时器,防止循环重复执行,等待下一次触发 elif event.type == invincible_event: # 解除无敌状态 me.invincible = False pygame.time.set_timer(invincible_event, 0) # 触发补给事件 elif event.type == bullet_time_supply: # 随机进行一次判断,如果是True,就发放强化子弹补给 if choice([True, False]): # 发放强化子弹补给 bullet_supply.reset() else: # 发放超级炸弹补给 bomb_supply.reset() # 加强子弹buff到时事件 elif event.type == bulletpro_time: # 子弹切换为普通子弹 is_double_bullet = False # 事件停止循环,等待下一次触发 pygame.time.set_timer(bulletpro_time, 0) # 捕获按键操作 elif event.type == KEYDOWN: # 如果按下的是空格,触发大招,超级炸弹清空屏幕内的飞机 if event.key == K_SPACE: if bomb_num > 0: bomb_num -= 1 # 判断所有在场的敌机,是否在游戏屏幕内 for ei in enemiesGroup: if ei.rect.bottom > 0: ei.active = False # 鼠标移动事件 elif event.type == MOUSEMOTION: # 鼠标移入到暂停的矩形框内,检测鼠标是否在矩形里,是则返回True,否则返回False ; pos – 就是鼠标位置 if paused_rect.collidepoint(event.pos): # 如果是暂停状态 if paused: paused_image = resume_pressed_image else: paused_image = pause_pressed_image else: if paused: paused_image = resume_nor_image else: paused_image = pause_nor_image # 鼠标左键点击暂停按钮 elif event.type == MOUSEBUTTONDOWN: # 如果是左键而且鼠标点击位置在暂停框内 if event.button == 1 and paused_rect.collidepoint(event.pos): # 切换暂停状态 paused = not paused # 如果点击暂停按钮后,游戏是暂停状态 if paused: # 绘制暂停按钮图片 paused_image = resume_pressed_image # 暂停补给定时器 pygame.time.set_timer(bullet_time_supply, 0) # 如果点击暂停按钮后,游戏是继续状态 else: # 绘制继续按钮图片 paused_image = pause_pressed_image # 继续补给定时器 pygame.time.set_timer(bullet_time_supply, 8 * 1000) # 检测用户键盘操作,分别为上下左右 key_pressed = pygame.key.get_pressed() if key_pressed[K_w] or key_pressed[K_UP]: me.moveUp() if key_pressed[K_s] or key_pressed[K_DOWN]: me.moveDown() if key_pressed[K_a] or key_pressed[K_LEFT]: me.moveLeft() if key_pressed[K_d] or key_pressed[K_RIGHT]: me.moveRight() # 在屏幕上面绘制背景图像,并指定位置 screen.blit(background, (0, 0)) # 绘制子弹补给、炸弹补给、敌机、玩家飞机等等各种元素 # 未暂停且生命大于0 if paused == False and life_num > 0: # 绘制子弹补给,如果子弹补给状态为真,即触发子弹补给操作 if bullet_supply.active: # 子弹开始运动,并且渲染子弹子弹补给图片 bullet_supply.move() screen.blit(bullet_supply.image, bullet_supply.rect) # 下落过程中如果跟玩家飞机碰撞,说明玩家飞机拾取到子弹补给 # pygame.sprite.collide_mask:两个精灵之间的像素遮罩检测,接收两个精灵作为参数,返回值是一个bool变量 if pygame.sprite.collide_mask(bullet_supply, me): # 改变子弹补给状态,包括隐藏以及不能再拾取了 bullet_supply.active = False # 飞机子弹变为加强子弹 is_double_bullet = True # 设置加强子弹buff持续事件,这里持续4s pygame.time.set_timer(bulletpro_time, 4 * 1000) # 绘制超级炸弹补给,如果超级炸弹状态为真,即触发超级炸弹补给操作 if bomb_supply.active: # 超级炸弹补给开始运动,并且渲染补给图片 bomb_supply.move() screen.blit(bomb_supply.image, bomb_supply.rect) # 玩家飞机拾取到补给 if pygame.sprite.collide_mask(bomb_supply, me): # 改变补给状态,包括隐藏以及不能再拾取了 bomb_supply.active = False # 判断超级炸弹数量,不能大于3 if bomb_num < 3: bomb_num += 1 # 绘制小型敌机,这里是由于上面定义了小型飞机组,飞机组add了小型飞机属性(速度、位置等),这时候地图上就生成了飞机 # 如果这些飞机属于小型敌机类,即一起处理 for ei in small_enemies: # 敌机是活的,未被击毁 if ei.active == True: # 绘制小型敌机,并且敌机开始运动 screen.blit(ei.image, ei.rect) ei.samll_enemy_move() # 小型敌机被摧毁(被玩家击毁或者与玩家碰撞) else: # 这里设置delay % 4是指爆炸画面为4帧(个人猜测),理解为爆炸停留时间,可自行设置 if not (delay % 4): # 用于播放爆炸声音,每一架敌机只有一次 if e1_destory_index == 0: print("播放敌机爆炸声音") # 绘制敌机撞击爆炸画面 screen.blit(ei.destory_images[e1_destory_index], ei.rect) # 切换爆炸图片下标,从而切换爆炸图片 e1_destory_index = (e1_destory_index + 1) % 4 # 经历完一轮爆炸的敌机,可以将其销毁,也可以重生,都是不能不处理,不然会一直爆炸、爆炸 # 这里选择将其重生 if e1_destory_index == 0: ei.reset() score += 100 # 做碰撞检测,pygame.sprite.spritecollide(sprite,sprite_group,bool):一个组中的所有精灵都会逐个地对另外一个单个精灵进行冲突检测,发生冲突的精灵会作为一个列表返回。 # 第一个参数就是单个精灵,第二个参数是精灵组,第三个参数是一个bool值,最后这个参数起了很大的作用。当为True的时候,会删除组中所有冲突的精灵,False的时候不会删除冲突的精灵 # 第四个参数是:两个精灵之间的像素遮罩检测 enemy_collide = pygame.sprite.spritecollide(me, enemiesGroup, False, pygame.sprite.collide_mask) # 碰撞处理,如果不是无敌状态下发生碰撞 if enemy_collide and not me.invincible: # 玩家飞机触发摧毁状态 me.active = False # enemy_collide是一个列表,存储所有跟玩家飞机发生碰撞的敌机,然后把碰撞的敌机状态置为摧毁状态 for ei in enemy_collide: ei.active = False # 绘制玩家飞机,如果飞机为激活状态 if me.active: # 在屏幕上绘制玩家飞机,switch_image为是否切换图片 if switch_image: screen.blit(me.image1, me.rect) # 切换一下飞行图片 else: screen.blit(me.image2, me.rect) # 代表飞机遭到碰撞,激活爆炸事件 else: if not (delay % 4): # 用于播放爆炸声音,每一架敌机只有一次 if me_destory_index == 0: print("玩家飞机爆炸声音") # 绘制玩家撞击爆炸画面 screen.blit(me.destory_image[me_destory_index], me.rect) # 切换爆炸图片下标,从而切换爆炸图片 me_destory_index = (me_destory_index + 1) % 4 # 爆炸画面播放完之后飞机重生 if me_destory_index == 0: # 生命减一条,如果见到0,会自动跳过上一级循环 life_num -= 1 # 重置状态 me.reset() # 无敌时间设置为3秒,3秒后,触发无敌时间事件,pygame.time.set_timer:就是每隔一段时间(这里是3毫秒 * 1000 = 3s),去执行一些动作 pygame.time.set_timer(invincible_event, 3 * 1000) # 每10个单位时间发射一颗子弹 if not(delay % 10): # 如果是普通子弹 if is_double_bullet == False: bullets = bullet1s # 先定子弹0的位置 bullets[bullet1s_index].reset(me.rect.midtop) # 切换到下一颗子弹 bullet1s_index = (bullet1s_index + 1) % bullet1_num # 如果是超级子弹 else: # 则子弹切换为加强子弹 bullets = bulletspro # 左右加强子弹重置位置,逻辑其实跟普通子弹一样的,只是位置变了 bullets[bulletspro_index].reset((me.rect.centerx - 33, me.rect.centery)) bullets[bulletspro_index + 1].reset((me.rect.centerx + 33, me.rect.centery)) # 切换到下一组子弹 bulletspro_index = (bulletspro_index + 2) % bulletspro_num # 绘制子弹 for bul in bullets: if bul.active: # 子弹如果是激活状态的话,就可以移动加绘制了 bul.move() screen.blit(bul.image, bul.rect) # 子弹与敌机的碰撞,子弹与敌机组之间的碰撞,正常情况下其实就是1对1的碰撞 enemy_hit = pygame.sprite.spritecollide(bul, enemiesGroup, False, pygame.sprite.collide_mask) # 如果存在被子弹击中的敌机 if enemy_hit: # 击中敌机的子弹先标为未激活状态,下一次循环到这个子弹的时候其实会重置的,又会显示出来 bul.active = False for ei in enemy_hit: ei.active = False # 绘制分数文字,pygame.font.Font.render():在一个新 Surface 对象上绘制文本 # pygame.font.Font.render(text, antialias, color, background=None) # text:要显示的文字 antialias: 为True时文本图像显示更光滑,为False时文本图像显示有锯齿状 # color:字体颜色 background:背景颜色(可选参数),默认为小黑屏 score_text = score_font.render('Score : %s' % str(score), True, WHITE) screen.blit(score_text, (10, 5)) # 绘制超级炸弹图片以及数量显示 bomb_text = bomb_font.render('* %d' % bomb_num, True, WHITE) bomb_text_rect = bomb_text.get_rect() screen.blit(bomb_image, (10, height - 10 - bomb_rect.height)) screen.blit(bomb_text, (bomb_rect.width + 20, height - 5 - bomb_text_rect.height)) # 绘制玩家剩余生命数 if life_num > 0: for i in range(life_num): screen.blit(life_image, (width - 10 - (i+1)*life_rect.width, height - 10 - life_rect.height)) delay -= 1 if delay == 0: delay = 100 # 每5帧切换一下飞行图片样式 if delay % 5 == 0: switch_image = not switch_image # 绘制暂停按钮图片 screen.blit(paused_image, paused_rect) # 更新整个待显示的 Surface 对象到屏幕上,将内存中的内容显示到屏幕上 pygame.display.flip() # 通过时钟对象指定循环频率,每秒循环60次 # 帧速率是指程序每秒在屏幕山绘制图 clock.tick(60) if __name__ == "__main__": try: main() # 服务正常退出 except SystemExit: print("游戏正常退出!") # pass忽略错误并继续往下运行,其实这里以及退出了 pass # 服务出现其他的异常 except: # 直接将错误打印出来 traceback.print_exc() pygame.quit()

优秀的个人博客,低调大师

程序员用Python进行模拟

云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 2019年末,在中国武汉爆发的冠状病毒疫情冲击了整个金融市场和实体经济。这座总人口超过千万,春运期间流动人口超过500万的巨型城市的灾难在世界各地引发了一连串蝴蝶效应,也在全球普通民众中引发恐慌。 2020年1月30日,2019-nCoV已被世界卫生组织列为国际关注的突发公共卫生事件(PHEIC)。在撰写本文时,尚未发现经过医学研究验证的具体治疗方法。 此外,一些关键的流行病学指标,如基本再生数(一个感染者传染的平均人数,即R0值)仍然未知。当今时代,全球互联,这类流行病更是借势成为全球范围内的重大威胁之一。 可以推测,如果2020年全球发生灾难性事件(大致定义为导致不少于1亿人伤亡的事件),最有可能的原因恰恰是某种流行病——而不是核灾难,也不是气候灾难,等等。全球范围内的快速城市化进一步加剧了这一问题,人口密集且频繁流动的城市俨然变成了疾病扩散网络的传播节点,使得防疫系统变得极为脆弱。 武汉的这场灾难也引发了全球对于城市规划和防疫政策的思考。如果疾病不是在武汉,而是在另一座人口规模更小、人口流动也更弱的城市,它的传染性和感染人数,又会是怎样的故事? 在这篇文章中,我们将讨论当流行病袭击一个城市时会发生什么,应该立即采取什么措施,以及这对城市规划、政策制定和管理有什么影响。 我们将以亚美尼亚首都,一个人口刚过百万、以钢铁和葡萄酒著名的城市埃里温市为例进行研究,建立数学模型并模拟冠状病毒在该市的传播,研究城市流动模式如何影响疾病的传播。 城市流动性 有效、高效和可持续的城市流动性对现代城市的运作至关重要。它已经被证明会直接影响城市的宜居性和经济产出(GDP)。然而,一旦发生疫情,它就会火上浇油,扩大疾病的传播。 那么,让我们先来看看埃里温市在一个平面坐标系上的聚合OD流动网络(Origin-Destination),以了解城市流动模式的空间结构: 接着,如果我们观察网格的总流入量,我们会看到或多或少的单中心空间组织,其中一些网格的日流入量较高但位于中心之外: 现在,假设一种流行病在城市的任意地点爆发。它将如何传播?我们能做些什么来控制它? 流行病学建模 为了回答这些问题,我们将建立一个简单的房室模型来模拟传染病在城市中的传播。 当一种流行病爆发时,其传播动力会有显著变化,这取决于最初感染的地理位置及其与城市其他地区的连接性。这是最近关于城市人口流行病的数据驱动研究得出的最重要见解之一。然而,正如我们将在下文进一步看到的,各种结果都要求采取类似的措施来控制疫情,并在规划和管理城市时考虑到这种可能性。 由于我们的目标是展示城市流行病传播的一般原理,而不是建立一个实时的精确模型,我将参考《自然》杂志的一篇文章,通过简单地修改经典SIR模型即可满足我们的需求。 这个模型把人口分成三部分。在时间t的每个位置i,其三个房室如下: Si,t:尚未感染或易感的人数; Ii,t:感染疾病并有能力将疾病传播给易感人群的人数; Ri,t: 由于康复或者死亡,在被感染后从受感染组中移除的人数。这个群体中的个体没有能力再次感染该疾病或将感染病传染给他人。 在我们的模拟中,时间将是一个离散变量,因为系统的状态是以日为单位进行建模的。在t时刻j点的完全易感人群中,感染病出现的概率为: βt是t时刻的传输率; mj,k是从k地到j地的流动性, xk,t 和yk,t 代表t时刻k地和j地的感染和易感人群数,其中xk,t = Ik,t / Nk,yj,t = Sj,t / Nj,Nk和Nj代表k地和j地的人口总数。然后,我们继续模拟一个随机过程,将这种疾病引入完全易感人群所在的地区,其中Ij,t+1 是概率为h(t,j)的伯努利随机变量。 一旦感染在随机地点出现,疾病不仅会在该地点传播,还会通过携带者传播到他处。这就是以OD流矩阵为特征的城市流动模式发挥关键作用的地方。 此外,为了确定疾病是如何通过感染者传播的,我们需要考虑其R0值。此处,其中y表示的是治愈率,也可以认为是二次感染率。在撰写本文时,新型冠状病毒的基本再生数估计值在1.4到4之间。凡事做最坏的准备,因此我们假设R0值为4。需要注意的是,R0值是一个有期望值的随机变量。为了让事情更有趣一点,我们在每个地区采用不同的R0值进行模拟,其中R0值服从均值为4的伽玛分布: 现在我们来讨论所建立的模型: βk,t是t时刻k地的转移率,α是刻画出行方式倾向的参数。 上述的模型十分简洁:为了求得t + 1时刻的j地的尚未感染或易感的人数,我们需要从t时刻的j地的尚未感染或易感的人数中减去j地本地感染的人数(第一个方程的第二部分),还要减去从其他地方来到j地的感染者数,这些外来的感染者通过其传输率进行加权计算(第一个方程的第三部分)。由于总人口数Nj = Sj + Ij + Rj,我们需要将减去的部分移至感染组,同时将治愈的部分移至Rj,t+1(第二个和第三个方程)。 仿真建立 在此分析中,我们将使用由当地共乘公司gg提供的GPS数据获得的一个典型日的总OD流量矩阵作为埃里温市交通模式的代表。 接下来,我们需要每个250×250m网格单元的人口计数,通过按比例缩放提取的流量计数来近似计算,从而使不同位置的总流入量之和接近埃里温市110万人口的一半。这是一个大胆的假设,但对结果影响不大。 减少公共交通? 第一次模拟,我们将模拟背景设定为一个高度依赖公共交通的未来城市,设定流动率α=0.9: 可以看到,经过大约8-10天左右的时间感染人数比例迅速增加至70%,达到峰值,但此时仅有小部分(约10%)的人康复。至100天时,疫情逐渐缓解,康复人数比例达到了惊人的90%!现在,我们再来看一下如果将公共交通强度α降低至0.2时,是否有利于缓解传染病的传播。这可以解释为采取严厉措施来降低城市流动性(例如实施宵禁),或者增加私家车出行比例,以减少人们出行期间感染的机率。 可以发现在这种假设下,疫情在16至20天左右到达顶峰,峰值感染人数比例明显降低(约45%),并且此时康复人数为之前的两倍(约20%)。在疫情结行将结束时,易感染人群比例也是之前的两倍(约24% vs. 约12%),这意味着更多的人躲过了这场疫情。正如人们所期望的,通过实施严厉的管控措施来临时降低城市的流动性对于减少传染病传播有明显作用。 隔离热门区域? 接着,再来看另一个直观想法——隔离一些关键区域能否得到预期的效果。为了测试这一想法,先挑选人流量位于前1%的区域: 接着完全限制这些区域的进出,建立有效的隔离制度。从这张图我们可以看出,在埃里温市这些位置主要位于市中心,另两个位置是两家最大的购物商场。将α取中间值,即0.5,我们得到如下结果: 感染人数比例的峰值更小了(约35%),并且更重要的是,在疫情行将结束时,大约一半的人未被感染,说明该种方法能够帮助人们有效的降低感染风险! 如下动图显示了高度依赖公共交通场景下的结果: 结论 该实验绝不是说我们已经构建了准确的传染病模型(甚至模型中不涉及任何传染病学的基础知识),我们的目标是在传染病爆发时能够即时了解城市交通网络对传染病传播的影响。 随着人口密度、流动性和互动性的增强,我们的城市更容易发生“黑天鹅”事件,并且变得更加脆弱。例如,我们从这个模型可以发现在关键地区实施隔离制度或者采取严苛的措施来控制人员流动能够在疫情期间发挥巨大作用。 但还有一个十分重要的问题就是,如何在执行这些措施期间,使得城市功能和经济的损坏最小化? 此外,传染病传播机制也是一个活跃的研究领域,该领域的成果必须要渗透并整合到城市规划、政策制定和城市管理当中,以使我们的城市更安全更抗打击。 上述模型代码如下: import numpy as np # initialize the population vector from the origin-destination flow matrix N_k = np.abs(np.diagonal(OD) + OD.sum(axis=0) - OD.sum(axis=1)) locs_len = len(N_k) # number of locations SIR = np.zeros(shape=(locs_len, 3)) # make a numpy array with 3 columns for keeping track of the S, I, R groups SIR[:,0] = N_k # initialize the S group with the respective populations first_infections = np.where(SIR[:, 0]<=thresh, SIR[:, 0]//20, 0) # for demo purposes, randomly introduce infections SIR[:, 0] = SIR[:, 0] - first_infections SIR[:, 1] = SIR[:, 1] + first_infections # move infections to the I group # row normalize the SIR matrix for keeping track of group proportions row_sums = SIR.sum(axis=1) SIR_n = SIR / row_sums[:, np.newaxis] # initialize parameters beta = 1.6 gamma = 0.04 public_trans = 0.5 # alpha R0 = beta/gamma beta_vec = np.random.gamma(1.6, 2, locs_len) gamma_vec = np.full(locs_len, gamma) public_trans_vec = np.full(locs_len, public_trans) # make copy of the SIR matrices SIR_sim = SIR.copy() SIR_nsim = SIR_n.copy() # run model print(SIR_sim.sum(axis=0).sum() == N_k.sum()) from tqdm import tqdm_notebook infected_pop_norm = [] susceptible_pop_norm = [] recovered_pop_norm = [] for time_step in tqdm_notebook(range(100)): infected_mat = np.array([SIR_nsim[:,1],]*locs_len).transpose() OD_infected = np.round(OD*infected_mat) inflow_infected = OD_infected.sum(axis=0) inflow_infected = np.round(inflow_infected*public_trans_vec) print('total infected inflow: ', inflow_infected.sum()) new_infect = beta_vec*SIR_sim[:, 0]*inflow_infected/(N_k + OD.sum(axis=0)) new_recovered = gamma_vec*SIR_sim[:, 1] new_infect = np.where(new_infect>SIR_sim[:, 0], SIR_sim[:, 0], new_infect) SIR_sim[:, 0] = SIR_sim[:, 0] - new_infect SIR_sim[:, 1] = SIR_sim[:, 1] + new_infect - new_recovered SIR_sim[:, 2] = SIR_sim[:, 2] + new_recovered SIR_sim = np.where(SIR_sim<0,0,SIR_sim) # recompute the normalized SIR matrix row_sums = SIR_sim.sum(axis=1) SIR_nsim = SIR_sim / row_sums[:, np.newaxis] S = SIR_sim[:,0].sum()/N_k.sum() I = SIR_sim[:,1].sum()/N_k.sum() R = SIR_sim[:,2].sum()/N_k.sum() print(S, I, R, (S+I+R)*N_k.sum(), N_k.sum()) print('\n') infected_pop_norm.append(I) susceptible_pop_norm.append(S) recovered_pop_norm.append(R) 云栖号:https://yqh.aliyun.com第一手的上云资讯,不同行业精选的上云企业案例库,基于众多成功案例萃取而成的最佳实践,助力您上云决策! 原文发布时间:2020-02-20本文作者:大萌、赵吉克、武帅、钱天培本文来自:“大数据文摘公众号”,了解相关信息可以关注“大数据文摘”

优秀的个人博客,低调大师

Python爬虫入门教程 16-100 500px摄影师社区抓取摄影师数据

1. 500px摄影师社区-写在前面 今天要抓取的网站为 https://500px.me/ ,这是一个摄影社区,在一个摄影社区里面本来应该爬取的是图片信息,可是我发现好像也没啥有意思的,忽然觉得爬取一下这个网站的摄影师更好玩一些,所以就有了这篇文章的由来。 基于上面的目的,我找了了一个不错的页面 https://500px.me/community/search/user 不过细细分析之后,发现这个页面并不能抓取到尽可能多的用户,因为下拉一段时间,就不能继续了,十分糟心,难道我止步于此了么,显然不可能的,一番的努力之后(大概废了1分钟吧),我找到了突破口,任意打开一个用户的个人中心页,就是点击上述链接的任意用户头像,出现如下操作。 用户个人中心页面,竟然有关注列表唉~~,nice啊,这个好爬啊,F12分析一下。 哒哒哒,数据得到了。URL是 https://500px.me/community/res/relation/4f7fe110d4e0b8a1fae0632b2358c8898/follow?startTime=&page=1&size=10&type=json 参数分别如下,实际测试发现size可以设置为100 https://500px.me/community/res/relation/{用户ID}/follow?startTime=&page={页码}&size={每页数据}&type=json 那么我们只需要这么做就可以了 获取关注总数 关注总数除以100,循环得到所有的关注者(这个地方为什么用关注,不用粉丝,是因为被关注的人更加有价值)明确我们的目标之后,就可以开始写代码了。 2.500px摄影师社区-撸代码 基本操作,获取网络请求,之后解析页面,取得关注总数。 用户的起始,我选择的id是5769e51a04209a9b9b6a8c1e656ff9566,你可以随机选择一个,只要他有关注名单,就可以。导入模块,这篇博客,用到了redis和mongo,所以相关的基础知识,我建议你提前准备一下,否则看起来吃力。 import requests import threading from redis import StrictRedis import pymongo #########mongo部分######################### DATABASE_IP = '127.0.0.1' DATABASE_PORT = 27017 DATABASE_NAME = 'sun' client = pymongo.MongoClient(DATABASE_IP,DATABASE_PORT) db = client.sun db.authenticate("dba", "dba") collection = db.px500 # 准备插入数据 #########mongo部分######################### #########redis部分######################### redis = StrictRedis(host="localhost",port=6379,db=1,decode_responses=True) #########redis部分######################### #########全局参数部分######################### START_URL = "https://500px.me/community/v2/user/indexInfo?queriedUserId={}" # 入口链接 COMMENT = "https://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json" HEADERS = { "Accept":"application/json", "User-Agent":"你自己去找找可用的就行", "X-Requested-With":"XMLHttpRequest" } need_crawlids = [] # 待爬取的userid lock = threading.Lock() # 线程锁 #########全局参数部分######################### def get_followee(): try: res = requests.get(START_URL.format("5769e51a04209a9b9b6a8c1e656ff9566"), headers=HEADERS,timeout=3) data = res.json() if data: totle = int(data["data"]["userFolloweeCount"]) # 返回关注数 userid = data["data"]["id"] # 返回用户ID return { "userid":userid, "totle":totle } # 返回总数据 except Exception as e: print("数据获取错误") print(e) if __name__ == '__main__': start = get_followee() # 获取入口 need_crawlids.append(start) 上面代码中有一个非常重要的逻辑,就是为什么要先匹配种子地址的【关注数】和【用户ID】,这两个值是为了拼接下面的URLhttps://500px.me/community/res/relation/{}/follow?startTime=&page={}&size=100&type=json经过分析,你已经知道,这个地方第一个参数是用户id,第二个参数是页码page,page需要通过关注总数除以100得到。不会算的,好好在纸上写写吧~ 我们可以通过一个方法,获取到了种子用户的关注列表,以此继续爬取下去,完善生产者代码。关键代码都进行了注释标注。 思路如下: 死循环不断获取need_crawlids 变量中的用户,然后获取该用户的关注者列表。 爬取到的信息,写入redis方便验证重复,快速存储。 class Product(threading.Thread): def __init__(self): threading.Thread.__init__(self) self._headers = HEADERS def get_follows(self,userid,totle): try: res = requests.get(COMMENT.format(userid,totle),headers=HEADERS,timeout=3) data = res.json() if data: for item in data: yield { "userid":item["id"], "totle":item["userFolloweeCount"] } except Exception as e: print("错误信息") print(e) self.get_follows(userid,totle) # 出错之后,重新调用 def run(self): while 1: global need_crawlids # 调用全局等待爬取的内容 if lock.acquire(): if len(need_crawlids)==0: # 如果为0,无法进入循环 continue data = need_crawlids[0] # 取得第一个 del need_crawlids[0] # 使用完删除 lock.release() if data["totle"] == 0: continue for page in range(1,data["totle"]//100+2): for i in self.get_follows(data["userid"],page): if lock.acquire(): need_crawlids.append(i) # 新获取到的,追加到等待爬取的列表里面 lock.release() self.save_redis(i) # 存储到redis里面 def save_redis(self,data): redis.setnx(data["userid"],data["totle"]) #print(data,"插入成功") 由于500px无反爬虫,所以运行起来速度也是飞快了,一会就爬取了大量的数据,目测大概40000多人,由于咱是写教程的,我停止了爬取。 这些数据不能就在redis里面趴着,我们要用它获取用户的所有信息,那么先找到用户信息接口,其实在上面已经使用了一次https://500px.me/community/v2/user/indexInfo?queriedUserId={} 后面的queriedUserId对应的是用户id,只需要从刚才的数据里面获取redis的key就可以了,开始编写消费者代码吧,我开启了5个线程抓取。 class Consumer(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while 1: key = redis.randomkey() # 随机获取一个key if key: # 删除获取到的key redis.delete(key) self.get_info(key) def get_info(self,key): try: res = requests.get(START_URL.format(key),headers=HEADERS,timeout=3) data = res.json() if data['status'] == "200": collection.insert(data["data"]) # 插入到mongodb中 except Exception as e: print(e) return if __name__ == '__main__': start = get_followee() # 获取入口 need_crawlids.append(start) p = Product() p.start() for i in range(1,5): c = Consumer() c.start() 代码没有特别需要注意的,可以说非常简单了,关于redis使用也不多。 redis.randomkey() # 随机获取一个key redis.delete(key) # 删除key (⊙o⊙)…经过几分钟的等待之后,大量的用户信息就来到了我的本地。 完整代码评论留言发送。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册