【代码实现】数学游戏:最后一个说30就输的数学游戏

目录

游戏规则

来源

分析过程

代码实现(Golang)

结果

类似的游戏

 通用规律

 思考


游戏规则

从1开始到30结束,两个人a和b轮流说一个数或者两个数,谁先开始都可以,最后一个说出30的人就输了。

来源

岳云鹏在某综艺玩过的一个游戏,看到那个视频之后,思考了一下其中的秘诀。

并且分析了类似游戏的通用规律。

分析过程

分析:
【1】
如果某一次a说的是26或者25 26时,
那么b:27, a:28 29;或者b:27 28, a:29;最终结果都是b输,
则a一定说出26就可以赢了

【2】
为了保证a说25 26 或者 26,应该使b说23 24, 24, 24 25, 25,
如果a说了23, b只能说24, 24 25, 就可以保证a说25 26 或者 26了
则a一定说出23就可以赢了

【3】
以此类推,a只要说出以下的数,并以该数做自己说的数的结尾,就可以赢了
[29, 26, 23, 20, 17, 14, 11, 8, 5, 2] 称之为 必赢数组 [3*n-1]
说了上面的数之后,接下来需要做的就是对方说一个数,我说两个数,对方说两个数,我说一个数,
就可以以3为一轮次持续踩中上面的数,并且一直赢到最后。

如 a:14
若 b:15, a:16 17
若 b:15 16, a:17

【4】
如果a先说,就说1 2, a就可以赢了
如果b先说,
若b: 1,  a: 2, a就可以赢了
若b:1 2,
此时a说数字,之后如果b不遵守与a说的数字的数目不同的原则,a就可以踩中必赢数组中的数字并取得胜利。
换句话说,之后a说了数字之后,b若与a说的数字个数相同,b就输了。

如:b:1 2
若a:3,b:4,a:5, a就可以赢了。
若a:3 4,b:5 6,a:7 8, a就可以赢了。

// 另一个秘诀:如果b说了3的倍数的数,b就输了。因为a只需要说两个数,就可以踩中必赢数组[3*n-1]

// 在a知道规则,b不知道规则时,b赢的情况只有1种,即:b先说12,并持续踩中 必赢数组[3*n-1]

代码实现(Golang)

package main

import (
	"fmt"
	"math/rand"
	"time"
)


// 假设a 知道策略
func policy_say_a(b int) (result int) {
	winArray := [...]int{29, 26, 23, 20, 17, 14, 11, 8, 5, 2}
	for _, num := range winArray{
		if b + 1 == num || b + 2 == num{
			return num
		}
	}
	return say_a(b)

}

// 随机方法
func say_a(b int) int {
	a := b + 1 + rand.Intn(2) // 1, 2
	// fmt.Println("a:", a)
	return a
}

func say_b(a int) int {
	b := a + 1 + rand.Intn(2) // 1, 2
	// fmt.Println("b:", b)
	return b
}

func game(say string) int {
	// 将时间戳设置成种子数
	rand.Seed(time.Now().UnixNano())

	a := 0
	b := 0
	if say == "a" {		// a 先说
		for a < 30 && b < 30 {
			// a 也不知道策略
			// a = say_a(b)
			// a 知道策略
			a = policy_say_a(b)
			if a >= 30 {
				// fmt.Println("b赢了这个游戏")
				return 0
			}
			b = say_b(a)
			if b >= 30 {
				// fmt.Println("a赢了这个游戏")
				return 1
			}
		}
	} else if say == "b" {		// b 先说
		var arr_a []int
		var arr_b []int
		for a < 30 && b < 30 {
			b = say_b(a)
			arr_b = append(arr_b, b)
			if b >= 30 {
				// fmt.Println("a赢了这个游戏")
				return 1
			}
			// a 不知道策略
			// a = say_a(b)
			// a 知道策略
			a = policy_say_a(b)
			arr_a = append(arr_a, a)
			if a >= 30 {
				fmt.Println("b赢了这个游戏")
				fmt.Println("b:", arr_b)
				fmt.Println("a:", arr_a)
				return 0
			}
		}
	}

	// fmt.Printf("出问题了,a:%v,b:%v\n", a, b)
	return -1
}

func start(say string) {
	a := 0
	b := 0
	c := 0
	//  重复进行游戏 10000 次,记录输赢结果
	for i := 0; i < 10000; i++ {
		g := game(say)
		if g == 1 {
			a += 1
		} else if g == 0 {
			b += 1
		} else {
			c += 1
		}
	}
	fmt.Printf("%s先说,进行游戏%v次:\n",say, 10000)
	fmt.Println("a赢了:", a, "次,b赢了", b, "次, 出现问题", c, "次。")
}

func main() {
	// “a” a 先说  ; "b" b 先说
	start("b")
	start("a")
	// game("a")
	// game("b")
}

结果

a和b都不知道规则的时候

b先说,进行游戏10000次:
a赢了: 6955 次,b赢了 3045 次, 出现问题 0 次。
a先说,进行游戏10000次:
a赢了: 4344 次,b赢了 5656 次, 出现问题 0 次。

a知道规则,而b不知道规则时

b先说,进行游戏10000次:
a赢了: 10000 次,b赢了 0 次, 出现问题 0 次。
a先说,进行游戏10000次:
a赢了: 10000 次,b赢了 0 次, 出现问题 0 次。

类似的游戏

// 游戏规则:从1开始到100结束,两个人a和b轮流说1到7个数,谁先开始都可以,最后一个说出100的人就输了。
// 分析: 谁最后说99谁就赢了,类似得出必赢数组[2+8^n],踩中必赢数组后,保持对方说x个数,我说8-x个数就可以赢了。

 通用规律

// 通用规律:
// 游戏规则:从1开始到num结束,两个人a和b轮流说1...x个数,谁先开始都可以,最后一个说出num的人就输了。
// 分析:必赢数组的第一个数:first = (num-1) % (x+1), 必赢数组[first + (1+x)*n],之后对方说 p,我说 1+x-p,就可以赢了。

 思考

同样的游戏换成3个人来进行,如何确保自己不输呢?

(没想明白,3个人说的数之和不固定了,且每次都可以变化,1个人无法控制3个人在一轮中说的数的总和,也无法控制3个人在n轮中说的数的总和)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值