0109编程-基于Plotly实现的简单智能体思路

点击这里进入人工智能嘚吧嘚目录,观看全部文章


人工智能是研究什么的?
—— 智能体Agent。

研究智能体的什么?
——感知能力、思维能力、行动能力。

假设有一种极其简单的单细胞病毒生物,它可以感知到周边环境中糖分的浓度,如果浓度低于上一位置它就后退,如果浓度高于上一位置它就前进。

  • 感知能力就是对周边糖分的分辨能力。
  • 思维能力就是根据糖分变化决定如何行动。
  • 行动能力就是实现前进或后退。

更多智能体相关的讨论可以参考经典人工智能教材《人工智能:一种现代方法》。

下面用代码模拟一个简单的扫地机器人智能体:

  • 感知能力:查找当前位置的灰尘dust。
  • 思维能力:找到周边上下左右四个位置的中的随机一个。
  • 行动能力:清理当前位置的灰尘和上下左右行进。

创建地图和灰尘

dusts和bot都是一个列表的列表,[[],[],...],bot其实使用单层[x,y]也可以。
dusts是所有灰尘的实际位置列表,[[32,11,1],[87,22,1]...],三个数字前两个是x,y坐标,第三个1表示未被清理。

mapGrid是地图每个方格单元列表,二维嵌套,[[{},{},...],[{},{},...],...],以便于通过横列col和行row索引到,比如mapGrid[col][row]获得一个单元。
mapGrid的每个单元是一个dict,可以包含很多信息,其中'dusts'属性是灰尘在dusts中的序号的列表。{'dusts':[34,21]}表示这个位置有两个灰尘,分别是dusts[34]和dusts[21]。

import plotly.offline as py
import plotly.graph_objs as go
import time
import random
import math

py.init_notebook_mode()

dusts = [[random.randint(0, 99), random.randint(0, 99), 1] for i in range(100)]
bot = [[random.randint(0, 9), random.randint(0, 9)]]

#尘土放入地图
mapGrid = [[{'dusts': []} for x in range(10)] for y in range(10)]
for i in range(len(dusts)):
    col = math.floor(dusts[i][0] / 10)
    row = math.floor(dusts[i][1] / 10)
    mapGrid[col][row]['dusts'].append(i)

fig = go.Figure()
bot_data = dict(
    x=[bot[0][0] * 10 + 5],
    y=[bot[0][1] * 10 + 5],
    mode='markers',
    name='bot',
    marker={
        'color': 'red',
        'size': 25,
        'symbol': 'circle'
    })
dust_data = dict(
    x=[d[0] for d in dusts if d[2] == 1],
    y=[d[1] for d in dusts if d[2] == 1],
    mode='markers',
    name='dust',
    marker={
        'color': 'gray',
        'size': 5,
        'symbol': 'circle'
    })

layout = go.Layout(
    title='TEST',
    autosize=False,
    width=500,
    height=500,
    xaxis=dict(
        autorange=False,
        range=(0, 100),
        dtick=10,
        showline=True,
        mirror='ticks',
    ),
    yaxis=dict(
        autorange=False,
        range=(0, 100),
        dtick=10,
        showline=True,
        mirror='ticks',
    ))

f = go.FigureWidget([dust_data, bot_data], layout)

清理当前位置灰尘的函数

在这里def的函数并没有使用位置参数,而是直接针对bot的位置进行清理,并且清理后直接更新了plotly数据。这只是为了偷懒。
注意mapGrid[bot[0][0]][bot[0][1]]['dusts']获得当前位置灰尘索引的列表,如[34,21]。
[d[0] for d in dusts if d[2] == 1]这两句是重建plotly的数据。

#清理当前位置
def clean():
    cell_dusts = mapGrid[bot[0][0]][bot[0][1]]['dusts']
    for d in cell_dusts:
        dusts[d][2] = 0
    f.data[0]['x'] = [d[0] for d in dusts if d[2] == 1]
    f.data[0]['y'] = [d[1] for d in dusts if d[2] == 1]    

clean()

移动机器人的函数

canto是可能的移动方向,上下左右四个x,y构成的方向向量。
moveto = canto[random.randint(0, len(canto) - 1)],是随机一个方向,注意random.randint(a,b)的时候,a和b都可能取到,所以要减1。
对nextpos进行0~9的约束,防止超出地图范围。
最终返回的bot[0] != orgpos表示是否bot真的被移动了,因为有可能移动超出0~9范围导致被自动重置回来,这种情况下应该不计算步数。

#移动机器人
def bot_move():
    canto = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    moveto = canto[random.randint(0, len(canto) - 1)]
    orgpos = [bot[0][0], bot[0][1]]
    nextpos = [bot[0][0] + moveto[0], bot[0][1] + moveto[1]]
    if nextpos[0] < 0:
        nextpos[0] = 0
    if nextpos[0] > 9:
        nextpos[0] = 9
    if nextpos[1] < 0:
        nextpos[1] = 0
    if nextpos[1] > 9:
        nextpos[1] = 9
    bot[0] = [nextpos[0], nextpos[1]]
    
    f.data[1]['x'] = [bot[0][0] * 10 + 5]
    f.data[1]['y'] = [bot[0][1] * 10 + 5]
    
    return bot[0] != orgpos

显示游戏

用f做变量很不合理,但懒就不改了...
直接f在Notebook中显示图像。

f

进行50次并统计剩余灰尘数量

step是实际步数,run是循环执行次数,由于有些时候bot超出范围被重置回来就没有形成实际步数,所以run>=step。
注意只在形成实际移动的情况下才time.sleep,没实际移动就不停顿等待。

step = 0
run = 0
for i in range(1000):
    if step < 50:
        domove = bot_move()
        run += 1
        if domove:
            step += 1
            
            time.sleep(0.1)
            clean()
            

print(run, step, len([d for d in dusts if d[2] == 1]))

更智能的思维能力

一般情况这个结果都很糟糕,行动50步,但只能清理掉1/3左右的灰尘,而实际我们知道如果按照某个顺序逐个位置清理,不重叠的路径,那么平均应该可以清理掉50个灰尘才对。

下面的代码改变了移动策略,bot先判断上下左右四个位置的灰尘数量,然后向灰尘最多的方向前进(如果同样多就随机选一个)。

使用了三个cell代码实现这个策略。

把范围约束定义为函数备用。

#如果超出范围就重置
def rerange(n):
    if n < 0:
        n = 0
    if n > 9:
        n = 9
    return n

直接根据bot的位置计算上下左右四个格子灰尘数量,返回最多灰尘的方向。

#计算上下左右四个格子的粒子数,返回最多一格的方向
def evaluate():
    pos = bot[0]
    canto = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    posli = [[pos[0] + offset[0], pos[1] + offset[1]] for offset in canto]
    countli = []
    for n in range(len(posli)):
        p = posli[n]
        if p[0] == rerange(p[0]) and p[1] == rerange(p[1]):
            cell_dusts=[d for d in mapGrid[p[0]][p[1]]['dusts'] if dusts[d][2]==1]
            countli.append(len(cell_dusts))
        else:
            countli.append(-1)
    maxn = max(countli)
    gotoli = [i for (i, v) in enumerate(countli) if v == maxn]
    randgoton = gotoli[random.randint(0, len(gotoli)-1)]
    return canto[randgoton]

evaluate()

改写原有的移动机器人的函数。

#移动机器人
def bot_move():
    orgpos = [bot[0][0], bot[0][1]]
    offset = evaluate()
    nextpos = [orgpos[0] + offset[0], orgpos[1] + offset[1]]
    nextpos[0]=rerange(nextpos[0])
    nextpos[1]=rerange(nextpos[1])
    bot[0] = [nextpos[0], nextpos[1]]

    f.data[1]['x'] = [bot[0][0] * 10 + 5]
    f.data[1]['y'] = [bot[0][1] * 10 + 5]

    return bot[0] != orgpos

这样的bot的清理效率要远高于随机的情况,有时候会明显高于50%,但有些情况bot陷入空白区域也会乱转导致低于预期。
当然还可以考虑预测两步的情况,上下左右四个位置,以及每个位置周边3个位置,共4组4个位置分别求灰尘总数,然后向此方向前进。当然还有有其他的算法,比如考虑[1,0][2,0]这样的更远的位置。总之,扩大智能体的感知能力肯定可以明显提高清理效率。

这是极其简陋的智能体案例,其实主要用来帮助新手熟悉python语法用的,尤其是数组的操作。如果你有更好的想法请留言分享给大家~


点击这里进入人工智能DBD嘚吧嘚目录,观看全部文章


每个人的智能新时代

如果您发现文章错误,请不吝留言指正;
如果您觉得有用,请点喜欢;
如果您觉得很有用,欢迎转载~


END

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容