// Note: We keep the data and the states in this component class BasicStopExplain extends React.Component { constructor(props) { super(props); this.state = { // Check whether all nodes are clicked isClicked: [ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true ], // Save continuation decision in percent continuation: [ 40, 100, 100, 100, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, // 1, 1, 1, 1, 1, 1, 1 // 1, 1, 1, 1, 1, 1, 1, 1 ], pdStopDecision : {}, stopPath: [100], // Save stop along the path, necessary for bonus ball // Save outcome path drawn: [0], currentRound: 0, currentNode: 0, // Keep track of currently clicked node imagePath: '/static/img/coin_questionmark.png', imagePathGuess: '/static/img/coin.png', winningSide: "", nextCoin: false, szenario: 1, paths: { "1": [0,1,3,7, 11, 17], // Path for szenario 1 "2": [0,1,4, 7, 12, 18], // Path for szenario 2 "3": [0,1,4, 7, 12, 18], // Path for szenario 3 }, showRepetitions: true, startAnew: false, cardDrawExplain:true, cardDraw:false, showCardRequest:true, }, this.simulateCoinToss = this.simulateCoinToss.bind(this); this.winningSideUpdate = this.winningSideUpdate.bind(this); this.startAnewBtn = this.startAnewBtn.bind(this); this.nextCoin = this.nextCoin.bind(this); this.closeModal = this.closeModal.bind(this); this.cardClick = this.cardClick.bind(this); this.nextCardDraw = this.nextCardDraw.bind(this); } componentDidMount() { // Start with disabled sections // Grey background for selection section document.getElementById("pickWinningSide").classList.remove("alert-warning"); document.getElementById("pickWinningSide").classList.add("alert-secondary"); var ele = document.getElementsByName("winningSideInput"); for(var i=0;i this.simulateCoinToss(), 500 ); } simulateCoinToss(){ const {paths} = this.state; let {currentNode, szenario, drawn, currentRound, stopPath, startAnew, } = this.state; currentRound = currentRound + 1; let relPaths = paths[szenario] drawn[currentRound] = relPaths[currentRound] stopPath[currentRound] = this.state.continuation[drawn[currentRound]] // Grey background for selection section document.getElementById("pickWinningSide").classList.remove("alert-warning"); document.getElementById("pickWinningSide").classList.add("alert-secondary"); // Disable winning side buttons var ele = document.getElementsByName("winningSideInput"); for(var i=0;iwhite. White balls instruct the computer to continue risk-taking.
Although the next card deck only contains white cards, you must draw a card. ` } else if (szenario == 1 && currentRound == 5) { // Black ball - szenario 1 end document.getElementById("currentNode").innerHTML = ` This ball is black.
You are in the last column of the ball triangle and no more single risks can be taken.
If this was the result of your bonus task, your bonus would be the accumulated earnings at this ball plus the endowment. Thus, the ball is colored gold and contains a "B" for bonus.
Please click "Start anew" to practice another path through the ball triangle. ` stopPath[currentRound] = "Stop" startAnew = true } else if (szenario == 2 && currentRound == 2) { // white-black-gradient ball reached from above document.getElementById("currentNode").innerHTML = ` This ball is black.
Black balls instruct the computer to stop risk-taking.
Although the next card deck only contains black cards, you must draw a card. ` } else { // All other balls are white balls document.getElementById("currentNode").innerHTML = ` This ball is white. ` } this.setState({ currentNode: currentNode, drawn: drawn, currentRound: currentRound, szenario: szenario, stopPath: stopPath, startAnew: startAnew, }) } nextCoin() { document.getElementById("proceedAfterCard").classList.add("d-none") this.setState({ cardDraw : false, imagePath: '/static/img/coin_questionmark.png', imagePathGuess: '/static/img/coin.png', }, () => { document.getElementById("pickWinningSide").classList.add("alert-warning"); document.getElementById("pickWinningSide").classList.remove("alert-secondary"); document.getElementById("coinTossWon").classList.add("d-none") document.getElementById("coinTossLost").classList.add("d-none") document.getElementById("moveUp").classList.add("d-none") document.getElementById("moveDown").classList.add("d-none") document.getElementById("placeholderFooter").classList.remove("d-none") var ele = document.getElementsByName("winningSideInput"); for(var i=0;iblack card and risk-taking stops.
If this was the result of your bonus task, your bonus would be the accumulated earnings at this ball plus the endowment.
Please click "Start anew" to practice another path through the ball triangle. ` blackCard = clickedNum stopPath[currentRound] = "Stop" document.getElementById("startAnewBtn").classList.remove("d-none") } else if (szenario == 3 && currentRound == 0) { // Black card document.getElementById("currentNode").innerHTML = ` You drew a black card and risk-taking stops.
If this was the result of your bonus task, your bonus would be the accumulated earnings at this ball plus the endowment. ` blackCard = clickedNum stopPath[currentRound] = "Stop" // Repetition ends next showRepetitions = false this.props.simulationCompleted(); } else { // White card whiteCards.push(clickedNum) document.getElementById("currentNode").innerHTML = ` You drew a white card and risk-taking continues. ` document.getElementById("proceedAfterCard").classList.remove("d-none") } while(whiteCards.length < whiteTarget){ var r = Math.floor(Math.random() * 10); if (r == blackCard) { continue } else if (whiteCards.indexOf(r) === -1) { whiteCards.push(r); } } const cards = document .getElementsByClassName("virtualCard") for (let i=0; i < cards.length; i++){ cards[i].setAttribute("disabled","disabled") let thisNum = parseInt(cards[i].id.slice(-1)) if (whiteCards.indexOf(thisNum) === -1) { cards[i].style.background = "black" cards[i].style.color = "transparent" } else { cards[i].style.background = "white" cards[i].style.color = "transparent" } } this.setState({ stopPath:stopPath, startAnew: startAnew, showRepetitions : showRepetitions, showCardRequest: false, }) } nextCardDraw() { this.setState({ cardDraw: true, showCardRequest: true,}) document.getElementById("currentNode").innerHTML = ` Please draw a card. ` // Remove coin toss feedback from right column document.getElementById("moveUp").classList.add("d-none") document.getElementById("moveDown").classList.add("d-none") document.getElementById("placeholderFooter").classList.remove("d-none") } closeModal( clickedCard, whiteCards) { document.getElementById("currentNode").innerHTML = ` You drew a white card and risk-taking continues. ` document.getElementById("proceedAfterCard").classList.remove("d-none") this.setState({ cardDrawExplain: false, cardDraw: true}, () => { // Color cards as in popup const cards = document .getElementsByClassName("virtualCard") for (let i=0; i < cards.length; i++){ cards[i].setAttribute("disabled","disabled") let thisNum = parseInt(cards[i].id.slice(-1)) if (whiteCards.indexOf(thisNum) === -1) { cards[i].style.background = "black" cards[i].style.color = "transparent" } else { cards[i].style.background = "white" cards[i].style.color = "transparent" } } document.getElementById(clickedCard).style.border = "3px solid #2E8BC0" }) } startAnewBtn() { $("#lineSVG").empty(); document.getElementById("startAnewBtn").classList.add("d-none") // Start new szenario let currentRound = 0 let drawn = [0] // Grey background for selection section if (!this.state.cardDraw) { document.getElementById("pickWinningSide").classList.add("alert-warning"); document.getElementById("pickWinningSide").classList.remove("alert-secondary"); document.getElementById("coinTossWon").classList.add("d-none") document.getElementById("coinTossLost").classList.add("d-none") document.getElementById("moveUp").classList.add("d-none") document.getElementById("moveDown").classList.add("d-none") document.getElementById("placeholderFooter").classList.remove("d-none") var ele = document.getElementsByName("winningSideInput"); for(var i=0;inumbered. ` this.setState({ imagePath: '/static/img/coin.png', imagePathGuess: '/static/img/coin.png', drawn: drawn, currentRound: currentRound, szenario: this.state.szenario + 1, stopPath: [100], startAnew: false, cardDraw : true, }) } voidFunction() { return; } render () { return ( <>
{ !this.state.cardDraw ?
Coin toss: Win or lose?
Coin toss outcome The winning side
 
Heads Tails
this.winningSideUpdate("H")} className="largerRadio"/> this.winningSideUpdate("T")} className="largerRadio"/>
You won this single risk.
You lost this single risk.
: }
The repeated risk
You moved up.
{ this.state.showRepetitions ? <> { (!this.state.startAnew) ?
:
} : <> }
You moved down.
{ this.state.showRepetitions ? <> { (!this.state.startAnew) ?
:
} : <> }
{/* Left column with textual description of current ball */}
This ball is numbered.

Numbered balls instruct the computer to stop risk-taking with the probability displayed on the ball.
) } } class CardDeckExplain extends React.Component { constructor(props) { super(props); this.state = { explanationState:0, clickableCards: false, whiteCards:[], clickedCard:-1, } this.toggleExplanation = this.toggleExplanation.bind(this); this.cardClick = this.cardClick.bind(this); } toggleExplanation() { const {explanationState} = this.state if (explanationState == 1) { this.setState({ clickableCards: true }, () => { setTimeout( () => { this.shuffleCards() }, 500 ) }) } this.setState({ explanationState : this.state.explanationState +1 }) } cardClick(cardID) { document.getElementById(cardID).classList.add("card-grow") document.getElementById(cardID).style.zIndex = 100 document.getElementById(cardID).style.border = "3px solid #2E8BC0" //Disable another card click const cards = document .getElementById("cardContainer") .getElementsByClassName("virtualCard") const numWhiteCard = parseInt(this.props.initialProb/10) const whiteCards = [parseInt(cardID.slice(-1))] while(whiteCards.length < numWhiteCard){ var r = Math.floor(Math.random() * 10); if(whiteCards.indexOf(r) === -1) { whiteCards.push(r); } } for (var i = 0; i < cards.length; i++) { cards[i].setAttribute("disabled","disabled") let thisID = cards[i].id let cardNum = parseInt(thisID.slice(-1)) cards[i].style.color = "transparent" if(whiteCards.indexOf(cardNum) === -1) { cards[i].style.background = "black" } else { cards[i].style.background = "white" } } this.setState({ explanationState : this.state.explanationState +1, whiteCards: whiteCards, clickedCard: cardID, }, () => { setTimeout( () => { document.getElementById("verificationExplain").classList.remove("d-none") //document.getElementById("startPathExplain").classList.remove("d-none") document.getElementById("closeModalBtn").disabled = false }, 1500) } ) } shuffleCards(){ const tmpCard = document .getElementById("cardContainer") .getElementsByClassName("virtualCard") const cards = Array.from(tmpCard) let positions = [] cards.forEach( (card, idx) => { const left = card.style.left const top = card.style.top positions.push( [left, top, idx]) }) const toMiddle = () => { cards.forEach( (card, idx) => { setTimeout( () => { card.style.zIndex = 10-idx; card.style.top = '35%'; card.style.left = '35%'; }, idx * 30) }) } const shuffling = () => { // Shuffle positions 1000 times for (let i = 0; i<=1000; i++) { const rnd1 = Math.floor(Math.random() * 10) const rnd2 = Math.floor(Math.random() * 10) const tmp = positions[rnd1] positions[rnd1] = positions[rnd2] positions[rnd2] = tmp } } const cardsToNewPos = () => { cards.forEach( (card, idx) => { const newLeft = positions[idx][0] const newTop = positions[idx][1] const cardNum = positions[idx][2] setTimeout( () => { card.style.top = newTop; card.style.left = newLeft; card.innerHTML = cardNum + 1; card.id = "virtualCard_" + cardNum // Give new id to make animation correct }, idx * 30) }) } async function sequence () { await new Promise( // move cards to middle (resolve) => { toMiddle() resolve("done") } ) await new Promise(resolve => setTimeout(resolve, 800)) await new Promise( // Shuffle positions (resolve) => { shuffling() resolve("done") } ) await new Promise( // Move cards back (resolve) => { cardsToNewPos() resolve("done") } ) await new Promise(resolve => setTimeout(resolve, 500)) await new Promise( (resolve) => { document.getElementById("modalTitle").classList.add("header-grow") resolve("done") } ) } sequence() } render() { if(!this.props.show){ return null; } return ( <> )} }