最近看韩国电视剧【D.P :逃兵追缉令】里面提到一个有趣的数学概率游戏 -> 蒙提霍尔问题
意思是:参赛者会看见三扇门,其中一扇门的里面有一辆汽车,选中里面是汽车的那扇门,就可以赢得该辆汽车,另外两扇门里面则都是一只山羊,让你任意选择其中一个,然后打开其余两个门中的一个并且是山羊(去掉一个错误答案),这时,让你重新选择。那么你是会坚持原来的选择,还是换选另外一个未被打开过的门呢?
大家可以想一想如果是自己,我们是会换还是不会换?
好了,我当时看到后感觉很有意思,所以我简单写了一套代码,源码贴在下面,大家可以验证一下,先告诉大家,换赢得汽车的概率是2/3,不换赢得汽车的概率是1/3
html
<header>
<h1>请选择换不换?</h1><button class="refresh">刷新</button>
</header>
<section>
<div class="box">
<h2>1</h2>
<canvas width="300" height="100"></canvas>
<div class="prize">奖品</div>
</div>
<div class="box">
<h2>2</h2>
<canvas width="300" height="100"></canvas>
<div class="prize">奖品</div>
</div>
<div class="box">
<h2>3</h2>
<canvas width="300" height="100"></canvas>
<div class="prize">奖品</div>
</div>
</section>
<span>请选择号码牌</span>
<select name="" id="">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button class="confirm">确认</button>
<span class="confirm-text"></span>
<span class="opater">
<button class="change">换</button>
<button class="no-change">不换</button>
</span>
<p>
<strong>游戏规则:</strong>
<span>
上面有三个号码牌,其中一个号码牌的里面有汽车,选中里面是汽车的号码牌,
你就可以赢得该辆汽车,另外两个号码牌里面则都是一只山羊,
你任意选择其中一个,然后打开其余两个号码牌中的一个并且是山羊(去掉一个错误答案),
这时,你有一个重新选择的机会,你选择换还是不换?
</span>
</p>
css
.prize {
width: 300px;
height: 100px;
background-color: pink;
font-size: 36px;
line-height: 100px;
text-align: center;
position: absolute;
}
canvas {
position: absolute;
z-index: 2;
}
section {
display: flex;
}
.box {
width: 300px;
height: 200px;
cursor: pointer;
}
.box+.box {
margin-left: 8px;
}
header {
display: flex;
align-items: center;
}
header button {
margin-left: 8px;
height: 24px;
}
p {
width: 400px;
background-color: pink;
}
js
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function getRandomNumber() {
return Math.random() > 0.5 ? 1 : 2;
}
let a1 = [0, 1, 2]
let i1 = undefined
let i2 = undefined
let isChange = false
const opater = document.querySelector('.opater')
opater.style.display = 'none'
// 随机一个奖品
const prizes = document.querySelectorAll('.prize')
let a0 = [0, 1, 2]
a0 = shuffleArray(a0)
a0.forEach((v,i) => {
const innerText = !!v ? '山羊' : '汽车'
prizes[i].innerText = innerText
})
const canvas = document.querySelectorAll('canvas')
const confirmText = document.querySelector('.confirm-text')
canvas.forEach(c => {
// 使用canvas实现功能
// 1. 使用canvas绘制一个灰色的矩形
const ctx = c.getContext('2d')
ctx.fillStyle = '#ccc'
ctx.fillRect(0, 0, c.width, c.height)
// 2. 刮奖逻辑
// 鼠标按下且移动的时候,需要擦除canvas画布
let done = false
c.addEventListener('mousedown', function () {
if (i1 === undefined) return alert('请先选择号码牌,并确认!')
if (!isChange) return alert('请选择换不换!')
done = true
})
c.addEventListener('mousemove', function (e) {
if (done) {
// offsetX 和 offsetY 可以获取到鼠标在元素中的偏移位置
const x = e.offsetX - 5
const y = e.offsetY - 5
ctx.clearRect(x, y, 10, 10)
}
})
c.addEventListener('mouseup', function () {
done = false
})
})
const confirm = document.querySelector('.confirm')
const refresh = document.querySelector('.refresh')
confirm.onclick = function () {
let select = document.querySelector('select')
const options = Array.from(select.children)
confirmText.innerText = `您选择的号码牌是${select.value},请问现在换不换?`
// 选择后,去掉一个错误答案
// i1是下标
i1 = select.value - 1
// delValue是值
let delValue = undefined
// 通过下标找值
if (a0[i1] === 0) {
delValue = getRandomNumber()
} else {
delValue = a0[i1] === 1 ? 2 : 1
}
// 通过值找下标
i2 = a0.indexOf(delValue)
// 选择的是i1, 去掉的是
const ctx = canvas[i2].getContext('2d')
ctx.clearRect(0, 0, 300, 100)
options.map(v => v.disabled = true)
confirm.style.display = 'none'
opater.style.display = 'inline-block'
}
const change = document.querySelector('.change')
const noChange = document.querySelector('.no-change')
change.onclick = function () {
isChange = true
const x = a1.filter(v => v !== i1 && v !== i2)
confirmText.innerText = `您确认选择的号码牌是${x[0] + 1},请刮卡!`
opater.style.display = 'none'
}
noChange.onclick = function () {
isChange = true
confirmText.innerText = `您确认选择的号码牌是${i1 + 1},请刮卡!`
opater.style.display = 'none'
}
refresh.onclick = function () {
window.location.reload()
}