Created
July 23, 2018 20:07
-
-
Save Perlkonig/72e41996e4b4938556c556ae3111f85d to your computer and use it in GitHub Desktop.
Practice scoring duplicate bridge contracts as per ACBL rules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html lang="en"> | |
<head> | |
<title>Brdige Scoring Drills</title> | |
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script> | |
<style type="text/css"> | |
.hidden { | |
display: none; | |
} | |
.red { | |
color: red; | |
} | |
#contract { | |
font-size: x-large; | |
} | |
</style> | |
<script type="text/javascript"> | |
var c; | |
function toggleAlgo() { | |
$("#scoringRules").toggleClass("hidden"); | |
} | |
function getRandomIntInclusive(min, max) { | |
var min = Math.ceil(min); | |
var max = Math.floor(max); | |
return Math.floor(Math.random() * (max - min + 1)) + min; //The maximum is inclusive and the minimum is inclusive | |
} | |
var suits = ["♣", "♦", "♥", "♠", "NT"]; | |
var mults = ["", "", "", "", "", "", "", "X", "X", "XX"]; | |
function genContract() { | |
var contract = new Object(); | |
contract.num = getRandomIntInclusive(1,7); | |
contract.suit = suits[getRandomIntInclusive(0,suits.length-1)]; | |
contract.mult = mults[getRandomIntInclusive(0, mults.length-1)]; | |
contract.vulnerable = getRandomIntInclusive(0,1); | |
var results = []; | |
for (let i=(-6 - contract.num); i<=7-contract.num; i++) { | |
results.push(i); | |
} | |
//These extra loops try to make more common final contracts more...common | |
for (let j=0; j<2; j++) { | |
for (let i=(-2); i<=7-contract.num; i++) { | |
results.push(i); | |
} | |
for (let k=0; k<2; k++) { | |
for (let i=0; i<=7-contract.num; i++) { | |
results.push(i); | |
} | |
} | |
} | |
contract.result = results[getRandomIntInclusive(0, results.length-1)]; | |
return contract; | |
} | |
function refresh() { | |
c = genContract(); | |
$("#num").html(c.num); | |
$("#suit").html(c.suit); | |
if ( (c.suit == "♦") || (c.suit == "♥") ) { | |
$("#suit").addClass("red"); | |
} else { | |
$("#suit").removeClass("red"); | |
} | |
$("#mult").html(c.mult); | |
$("#result").html(c.result >= 0 ? '+' + c.result : c.result); | |
$("#vnv").html(c.vulnerable ? "vulnerable" : "not vulnerable"); | |
} | |
function score() { | |
var score = 0; | |
var isGrandSlam = false; | |
var isSmallSlam = false; | |
if (c.num === 7) { | |
isGrandSlam = true; | |
} else if (c.num === 6) { | |
isSmallSlam = true; | |
} | |
var isGame = false; | |
var minMinor = 5; | |
var minMajor = 4; | |
var minNT = 3; | |
if (c.mult === "X") { | |
minMinor = 3; | |
minMajor = 2; | |
minNT = 2; | |
} else if (c.mult === "XX") { | |
minMinor = 2; | |
minMajor = 1; | |
minNT = 1; | |
} | |
if ( | |
( (c.num >= minMinor) && ( (c.suit === "♦") || (c.suit === "♣") ) ) || | |
( (c.num >= minMajor) && ( (c.suit === "♥") || (c.suit === "♠") ) ) || | |
( (c.num >= minNT) && (c.suit === "NT") ) | |
) { | |
isGame = true; | |
} | |
var bonusPart = 50; | |
var bonusGame = 300; | |
var bonusSSlam = 500; | |
var bonusGSlam = 1000; | |
var bonusOver = 100; | |
var penaltyUnder = 50; | |
var penaltyDownDoubled = [100, 300, 500]; | |
while (penaltyDownDoubled.length < 13) { | |
penaltyDownDoubled.push(penaltyDownDoubled[penaltyDownDoubled.length-1]+300); | |
} | |
if (c.vulnerable) { | |
bonusGame = 500; | |
bonusSSlam = 750; | |
bonusGSlam = 1500; | |
bonusOver = 200; | |
penaltyUnder = 100; | |
penaltyDownDoubled = [200, 500, 800]; | |
while (penaltyDownDoubled.length < 13) { | |
penaltyDownDoubled.push(penaltyDownDoubled[penaltyDownDoubled.length-1]+300); | |
} | |
} | |
//contract made | |
if (c.result >= 0) { | |
var trickscore = 0; | |
if (c.suit === "NT") { | |
trickscore += 10; | |
} | |
if ( (c.suit == "♦") || (c.suit == "♣") ) { | |
trickscore += 20 * c.num; | |
} else { | |
trickscore += 30 * c.num; | |
} | |
score += trickscore; | |
//standard game/slam/partscore bonus | |
if (isGrandSlam) { | |
score += bonusGSlam; | |
} else if (isSmallSlam) { | |
score += bonusSSlam; | |
} | |
if (isGame) { | |
score += bonusGame; | |
} else { | |
score += bonusPart; | |
} | |
//doubled | |
if (c.mult === "X") { | |
score += trickscore; | |
score += bonusOver * c.result; | |
score += 50; | |
//redoubled | |
} else if (c.mult === "XX" ) { | |
score += 3*trickscore; | |
score += (bonusOver * 2) * c.result; | |
score += 100; | |
} else { | |
if ( (c.suit == "♦") || (c.suit == "♣") ) { | |
score += 20 * c.result; | |
} else { | |
score += 30 * c.result; | |
} | |
} | |
//got set | |
} else { | |
//doubled | |
if (c.mult === "X") { | |
score -= penaltyDownDoubled[Math.abs(c.result)-1]; | |
//redoubled | |
} else if (c.mult === "XX" ) { | |
score -= penaltyDownDoubled[Math.abs(c.result)-1] * 2; | |
//no multiplier | |
} else { | |
score -= penaltyUnder * Math.abs(c.result); | |
} | |
} | |
return score; | |
} | |
function checkScore() { | |
if (score() == $("#score").val()) { | |
window.alert("CORRECT!"); | |
$("#score").val(""); | |
refresh(); | |
} else { | |
window.alert("Sorry. Try again."); | |
} | |
} | |
window.onload = refresh; | |
</script> | |
</head> | |
<body> | |
<h1>Bridge Scoring Drills</h1> | |
<p id="contract"> | |
<span id="num"></span><span id="suit"></span><span id="mult"></span> <span id="result"></span> (<span id="vnv"></span>) | |
</p> | |
<form id="drill" action="#" onsubmit="checkScore(); return false;"> | |
<p> | |
<label for="score">Score:</label> | |
<input id="score" name="score" autofocus="autofocus" type="number"> | |
</p> | |
<input class="submit" type="submit" id="btn_check" value="Check Answer"> | |
</form> | |
<p> | |
<button id="btn_answer" onclick="window.alert('Score: '+score());">Reveal Answer</button> | |
<button id="btn_refresh" onclick="refresh();">New Contract</button> | |
</p> | |
<hr> | |
<p> | |
<button id="btn_togglealgo" onclick="toggleAlgo();">Show/Hide Scoring Rules</button> | |
</p> | |
<div id="scoringRules" class="hidden"> | |
<p><a href="https://www.acbl.org/learn_page/how-to-play-bridge/how-to-keep-score/">As per ACBL.</a></p> | |
<h2>Trick Score</h2> | |
<p>You earn 40 points for the first notrump trick scored and 30 points thereafter; 30 points for each spade and heart trick; 20 points for each club and diamond trick.</p> | |
<p>Trick values double in doubled contracts and are doubled again for redoubled contracts.</p> | |
<h2>Bonuses</h2> | |
<p>Whenever one side scores a slam, or a game, or a partscore, the side collects, in addition to the trick score, an immediate bonus. For instance:</p> | |
<ul> | |
<li>For making a vulnerable grand slam 1,500</li> | |
<li>For making a non-vulnerable grand slam 1,000</li> | |
<li>For making a vulnerable small slam 750</li> | |
<li>For making a non-vulnerable small slam 500</li> | |
<li>For making a vulnerable game 500</li> | |
<li>For making a non-vulnerable game 300</li> | |
<li>For making a partscore50</li> | |
<li>For making a doubled contract 50</li> | |
<li>For making a redoubled contract 100</li> | |
</ul> | |
<p>Note that the slam bonuses <em>stack on top of</em> the game bonus. But the game bonus <em>does not</em> stack with the partscore bonus.</p> | |
<h2>Overtricks</h2> | |
<p>If the declaring side makes one or more overtricks, the side collects per overtrick:</p> | |
<ul> | |
<li>For an undoubled contract, non-vulnerable Trick Value</li> | |
<li>For a doubled contract, non-vulnerable 100</li> | |
<li>For a redoubled contract, non-vulnerable 200</li> | |
<li>For an undoubled contract, vulnerable Trick Value</li> | |
<li>For a doubled contract, vulnerable 200</li> | |
<li>For a redoubled contract, vulnerable 400</li> | |
</ul> | |
<h2>Undertricks</h2> | |
<p>When the contract is defeated, the opponents collect:</p> | |
<ul> | |
<li>For each non-vulnerable trick 50</li> | |
<li>For each vulnerable trick 100</li> | |
<li>Not vulnerable doubled 100,300,500 for down 1, 2 and 3 (300 more for each additional trick)</li> | |
<li>Vulnerable doubled 200,500,800 for down 1, 2 and 3 (300 more for each additional trick)</li> | |
<li>Not vulnerable redoubled 200, 600, 1000 for down 1, 2 and 3 (600 more for each additional trick)</li> | |
<li>Vulnerable redoubled 400, 1000, 1600 for down 1, 2 and 3 (600 more for each additional trick)</li> | |
</ul> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment