10

套路博弈背后的代码

 3 years ago
source link: https://kymjs.com/stickies/2018/05/06/01/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

套路博弈背后的代码

cleardot.gif
2018-05-06 By 张涛 | 本文已被访问2485次

版权声明:本文是开源实验室原创文章,如您转载必须以链接形式注明原文地址:https://kymjs.com/stickies/2018/05/06/01
每个人都会沉迷在自己的戏里,就看什么时候观众会看不下去而叫醒你。——《说故事的人》
对本文有任何问题,可加我的个人微信询问:kymjs123

前段时间在微博上看到一个有意思的视频,叫:【股市暴跌,为啥散户炒股票总赔钱】视频地址在这里:http://my.tv.sohu.com/us/209546370/101342155.shtml

文中讲了一个游戏。美女和男人每人拿一个硬币,一人把硬币出一面,你出一面我出一面,之后打开看一看,如果这两个硬币都是正面,那美女就给男人三块钱,男人的收益就是三块;如果都是反面 那就给一块,男人的收益就是一块钱;如果两个硬币一正一反,男人就给美女两块钱,所以男人的收益就是输两块。
于是美女问男人玩不玩,男人说他肯定玩对不对。为什么,首先因为你是个美女,跟美女玩会有什么,其次呢,是因为从概率上讲,两个正面的概率是1/4,两个反的概率也是1/4,玩四把,一次两正一次两反,还有两把是一正一反的,算下来不赚也不亏。这样一来的看起来是公平的。

但是玩了很长时间后,发现,男人总是在输钱,女人赚了很多钱。

根据前面的描述,首先列出一个表格

女人↓男人→ 正 反 正 3 -2 反 -2 1

假设男人出正面的概率是x,反面的概率就是1-x;
女人出正面的概率是y,反面的概率就是1-y;

那么男人赚钱的期望就是:

E = 3xy+1*(1-x)(1-y)-2*[x(1-y)+y(1-x)]
  = 8xy-3x-3y+1 

其中因为x和y都是概率值,所以取值范围在[0-1]。
如果女人想让男人一直输钱,那么也就是在这个式子中,E永远为负数。

所以解不等式0 < 8xy-3x-3y+1
最终结果y的取值范围在(1/3,2/5)

也就是说,只要玩15把,女人出五到六次正,就可以一直赢钱。

如果你也听说

我知道,如果你也是第一次听说这个故事,一定想迫切的找个人试一试。
没错,我按照文中的说法试了这个游戏,很可惜,即便按照故事中女人的出法依然输的很惨。

不甘心的我拿代码模拟了一次这样的游戏,然后发现了其中的原因。

代码上的模拟

用GO语言实现这个游戏(语言无所谓,你也可以自己试试)

const MAX = 10000

func main() {
    profit := 0
    for i := 0; i < MAX; i++ {
        boyResult := boyPlan1()
        girlResult := girlPlan1()
        current := referee(boyResult, girlResult)
        profit += current
    }
    println(profit)
}

func boyPlan1() bool {
    num := getRandom() % 2
    if num == 0 {
        return true
    } else {
        return false
    }
}

func girlPlan1() bool {
    num := getRandom()
    const max = rondom_max * 2 / 5
    const min = rondom_max * 1 / 3
    if num < max && num > min {
        return true
    } else {
        return false
    }
}

func getRandom() int {
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    return r.Intn(rondom_max)
}

我把这段代码执行了一百遍,最后发现每次结果男人都会输4000元左右,也就是说,上文讲的思路与结果都是正确的,可是为什么我在和朋友玩的时候就不行了。

其实如果代码是你自己写的,在写的时候就能意识到了。在这段代码中,女人出硬币的策略是经过精细计算的,而男人的策略却只是简单的random,没有丝毫的策略可言。而在实际玩的时候,毕竟我的对手不是一个低智商的计算机random。可理论上来说尽管我的对手和random有区别,但最后我也不会输那么多。

其实再回想这个故事,男人要做的就是跟女人出的硬币一样就可以了,那么从概率上来讲就是,男人出正面的概率跟女人保持一致,就能达到收益最大化。
那最简单的就是,重复上一次女人的结果就能达到最大收益了。

用代码模拟一下

const MAX = 10000
var girlPreviousResult = getRandom()%2 == 0

func main() {
    profit := 0
    for i := 0; i < MAX; i++ {
        boyResult := boyPlan2()
        girlResult := girlPlan1()
        girlPreviousResult = girlResult
        current := referee(boyResult, girlResult)
        profit += current
    }
    println(profit)
}

func boyPlan2() bool {
    return girlPreviousResult
}

func girlPlan1() bool {
    num := getRandom()
    const max = rondom_max * 2 / 5
    const min = rondom_max * 1 / 3
    if num < max && num > min {
        return true
    } else {
        return false
    }
}

func getRandom() int {
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    return r.Intn(rondom_max)
}

果然,男人最简单的策略,只要重复女人上一次的结果,就能赚到最高。
在上面的代码运行后,每次男人都能净赚6000以上。

所以在这个例子中,女人就像股市里的庄家一样,它可以拉升股价,也可以打压股价,对应着故事里面硬币的正和反。而男人就像散户一样,可以买多也可以买空。如果庄家拉升股价,而我们做多,就可以有很高的收益;如果庄家打压股价,我们做空也会有受益;但是如果庄家拉升股价,我们却做空,我们就输了。表面上看好像有涨有跌,我们是可以赚到的。但如果庄家通过一定策略,让你一直赚不到钱,你就要想办法了。

了解更多有深度技术的文章,与移动端、大前端未来方向的认知,前往订阅 开源实验室小专栏。
张涛-qrcode


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK