Bitcoin’s Monty Hall Problem

Put your money where your mouth is

We built a simulation of the Monty Hall problem on Bitcoin. Not only do you show off your math skills, but you also get a monetary reward if you know the correct answer to the probability puzzle. It runs completely trustlessly on-chain.

Monty Hall Question

The Monty Hall Problem is a probability puzzle named after Monty Hall, the original host of the television show Let's Make a Deal. It's a famously counter-intuitive statistical puzzle whose solution is so ridiculous that most people refuse to believe it even if it's proven to be true. Here's how it works:

Let's say you're on a game show and you have a choice of three doors: behind one is a car; behind the others, a goat. You choose a door, say No. 1, and the host, who knows what's behind it, opens another door, say No. 3, with a goat inside. Then he says to you, "Do you want to choose door number 2?" Would it be in your interest to change your choice?

Surprisingly, the odds are not 50–50. If you change doors, the probability you will win is 2/3! There are many articles/videos explaining mathematics, we won't go into them here. Some great examples are listed below.

Placement Possibilities

Possible scenarios for Stay vs. Switch

cryptographic door

In order to simulate Monty Hall in Bitcoin, we need a way to hide the car/goat like this:

  1. The player cannot see what is behind each door;
  2. Once the game has started, the host cannot move the car/goat.

Commitment schemes are the standard way to achieve both. We use a single bit 1to represent a car and a bit 0to represent a goat. As usual, we also add a random number before the bit to prevent brute force attacks.

accomplish

We implemented the Monty Hall problem in Bitcoin smart contracts using scryptTS , a TypeScript DSL. Before the game begins, both the player and the host lock an equal amount of Bitcoin into the following contract. After deploying the contract, the game will proceed as follows:

  1. The player chooses a door, such as door 0, and of course hopes that there will be a car
  2. The host opens one door and there is a goat in the other two doors
  3. The player decides whether to stick with door 0 (the initial guess) or switch to the remaining unopened doors
  4. The host announces the result: if the player selects the door with the car, he takes away all the Bitcoins in the contract; otherwise, the host takes it away.
// this contract simulates the Monty Hall problem
class MontyHall extends SmartContract {
    
    
    @prop()
    player: PubKey

    @prop()
    host: PubKey

    @prop(true)
    step: bigint

    // player's choice
    @prop(true)
    choice: bigint

    // door opened by host
    @prop(true)
    openedDoor: bigint

    // number of doors
    static readonly N: number = 3

    // what's behind each door
    @prop()
    doorHashes: FixedArray<Sha256, 3>


    constructor(
        player: PubKey,
        host: PubKey,
        doorHashes: FixedArray<Sha256, 3>
    ) {
    
    
        super(...arguments)
        this.player = player
        this.host = host
        this.step = 0n
        this.choice = -1n
        this.openedDoor = -1n
        this.doorHashes = doorHashes
    }


    // step 1: the player chooses initially a random door that s/he believes has the prize
    @method()
    public choose(choice: bigint, sig: Sig) {
    
    
        assert(++this.step == 1n, 'step number unexpected')

        this.choice = choice

        // game goes on
        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 2: host opens a goat door
    @method()
    public open(goatDoorNum: bigint, behindDoor: ByteString, sig: Sig) {
    
    
        assert(++this.step == 2n, 'step number unexpected')

        this.openedDoor = goatDoorNum
        const goatDoorHash = this.doorHashes[Number(goatDoorNum)]
        assert(sha256(behindDoor) == goatDoorHash)
        assert(!this.isCar(behindDoor), "expect goat, but got car")

        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 3: player stays or switches
    @method()
    public stay(stay: boolean, sig: Sig) {
    
    
        assert(++this.step == 3n, 'step number unexpected')

        if (!stay) {
    
    
            // switch
            this.choice = this.findUnopenedDoor()
        }

        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 4: reveal
    @method()
    public reveal(behindDoor: ByteString) {
    
    
        assert(++this.step == 4n, 'step number unexpected')

        const doorHash = this.doorHashes[Number(this.choice)]
        assert(sha256(behindDoor) == doorHash)

        // does the play choose a door, behind which is a car
        const won = this.isCar(behindDoor)
        const winner = won ? this.player : this.host

        // pay full amount to winner
        const winnerScript: ByteString = Utils.buildPublicKeyHashScript(winner)
        const payoutOutput: ByteString = Utils.buildOutput(winnerScript, this.ctx.utxo.value)
        assert(this.ctx.hashOutputs == hash256(payoutOutput))
    }

    // if last bit is set, it is a car; otherwise, a goat
    @method()
    isCar(behindDoor: ByteString): boolean {
    
    
        return unpack(behindDoor) % 2n == 1n
    }

    // find the remaining unopened door
    @method()
    findUnopenedDoor(): bigint {
    
    
        let result: bigint = -1n
        for (let i = 0n; i < MontyHall.N; i++) {
    
    
            if (i != this.choice && i != this.openedDoor)
                result = i
        }
        return result
    }
}
Montyhall Contract

On 25line , the host submits the car's location. He promised to "open" a door by opening SHA256. At the beginning of each public method, we ensure that the correct steps are executed in order. Line 1 51uses stateful contract technology.

If the game is repeated multiple times, a player who chooses to stay will win for approximately 1/3, whereas if he always switches, his odds of winning can be increased to 2/3.

What should I do if the host cheats?

There are two possible ways for a moderator to cheat:

  1. If the player 4correctly selects the car in step , he refuses to open the door;

  2. He put three goats behind the door, but no car.

To prevent (1), we can use a timed commitment scheme where the host's deposit is forfeited if the host does not open the commitment before the deadline.

(2) It can also be prevented. The host must eventually open all three doors, and if they are all goats, he loses his deposit. Or he could use a zero-knowledge proof to convince the player that there is indeed a car behind the door, without revealing which door it is behind.


[1] For the sake of illustration, we ignore transaction fees, which can be easily stated in the contract, for example, by using ANYONECANPAY .

Guess you like

Origin blog.csdn.net/freedomhero/article/details/133076547