User:Brian Schott/code/BridgeScoring
A simplistic example using JHS to create a formatted input and output screen for an application which scores contract bridge.
Features
This application was originally designed in the jconsole IDE and as such the user of the original application has to use all-numerical inputs like the following examples.
2 3 1 1 bridgescore 0 NB. 2(2) Spades(3) vulnerable(1), doubled(1), and making the contract(0) 670 5 1 1 2 bridgescore _8 NB. 5(5) Diamonds(1) vulnerable(1), redoubled(2), and going down 8(_8) _4600
But the current design represents an extension which requires no text entry and only clicks. This the primary feature of the application.
The application maintains a pair of backups, one in memory that only lasts during a rubber, one that is in a time-stamp named file for each rubber. Both backups are created identically, regardless of the IDE. The in-memory backup grows after each bridge hand, but the previous backups are all kept totally intact so that undo's and redo's can be simply by using j rotates |. on the sequence of backup histories.
Actually there is another in-memory backup of the outputs called annotations or echoes. An echo is a textual sentence repeating each bridge hand's status because the We/They score sheet only shows the scoring numbers. A feature enabled by the textarea environment of the echoes, is that the players can manually add to or edit the echoes.
Also, the original application required that team vulnerability, and another feature called a leg, must be entered by the user. These two inputs are computed automatically in the current application, but could also have been done in the original IDE.
Usage of the application is somewhat explained by the following excerpted comments from the application.
NB. Before each hand is scored, you must at least enter the following NB. by clicking radio buttons. NB. Bid: the number of tricks NB. Suit: clubs,..., no trump NB. Double: no click is needed if there was no double or redouble NB. Honors: no click is needed if there were no honors NB. WeThey: whether We or They contracted for the Bid NB. After each hand, a selection from the Made selector triggers the NB. scoring. Positive numbers indicate the number of tricks taken. NB. Often, negative numbers are used or needed for failed contracts. NB. If an entry error is detected, the Undo button at the top NB. of the page can be employed. NB. Click the New Rubber button to initiate a new rubber. NB. The rubber totals are maintained at the bottom of the yellow NB. text area. The two totals are separated by a TAB character NB. to facilitate pasting into adjacent columns of a spreadsheet.
Screen shot
Also a short screencast is available: youtu.be/SXJGoAbkvXA
Challenges
This application begs to be on a portable device like a tablet or mobile phone. But in my case only iOS is available. So I cannot easily use JHS except on my home's local wireless network. Android portable devices may support JHS, though. Currently I am experimenting using the basic version of this application on the iPad version of J.
Using CSS with JHS has been quite a challenge, perhaps because I have not learned how to use the style feature even on native html. There is an additional hurdle of using CSS with JHS because the j library facilities for constructing html tables and input controls are not designed with CSS in mind. Perhaps, div's could be used for this but I am not fluent with using div's. I would really like to get help with using CSS on this application. (Update: using table coloring in the CSS has remediated this problem.) Another possibility would be to get help designing the application around jqt, but I don't know if that improves the access of portable devices.
I am unable to use the attractive "Windows" box drawing characters on JHS. Which is weird because the attractive characters are available in the jijx window, but not in the html window. (Update: This problem has been overcome now, using the J script htmlboxchar .)
Javascript is a foreign language for me and I found that debugging and learning how to access object properties is very time consuming. Perhaps jquery would be better than javascript, but I don't know how to use jquery and the j html libary.
Installation
Download the two files #bridge.ijs and #bridgejhs.ijs and place the two files in a subdirectory named bridge in your user directory which I assume here is named j64-804-user .
Launch JHS on your computer. When launched your browser will be opened to the following address. If for some reason this does not happen, open your browser to a new window and type in the following address and press enter.
http://127.0.0.1:65001/jijx
Type the following load command into the opened browser window and press enter.
load'~user/bridge/bridgejhs.ijs'
Open a new browser window and type in the following address and press enter.
http://127.0.0.1:65001/bridge
You should see the app's user interface page opened and ready for inputs but with empty output textarea regions.
bridgejhs.ijs
This is the script for the JHS extension of the application. Some comments are provided.
coclass'bridge' coinsert'jhs' PATH=: jpath'~user/bridge/' require PATH,'bridge.ijs' HBS=: 0 : 0 NB. 2 vertically adjacent html tables are used to organize the screen view. NB. Look below for "Table 1" and "Table 2". NB. In JHS's supplied library "jhtablea" and "jhtablez" NB. correspond to html's "<table>" and "</table>". NB. 3 buttons here (created using "jhb") but the main buttons are below, NB. in Table 2: look for ('we' jhb'We') and ('they' jhb'They') . 'start' jhb 'New rubber' 'undo' jhb 'Undo previous hand' 'redo' jhb 'Redo previous hand' jhbr NB. The 3 hidden "result"s receive the 3 "output"s from JS NB. For example see them "getv"ed in ev_we_click, below. 'result1' jhhidden '' 'result2' jhhidden '' 'result3' jhhidden '' NB. Before each hand is scored, you must at least enter the following NB. by clicking radio buttons. NB. Bid: the number of tricks NB. Suit: clubs,..., no trump NB. Double: no click is needed if there was no double or redouble NB. Honors: no click is needed if there were no honors NB. WeThey: whether We or They contracted for the Bid NB. After each hand, a selection from the Made selector triggers the NB. scoring. Positive numbers indicate the number of tricks taken. NB. Often, negative numbers are used or needed for failed contracts. NB. If an entry error is detected, the Undo button at the top NB. of the page can be employed. NB. Click the New Rubber button to initiate a new rubber. NB. The rubber totals are maintained at the bottom of the yellow NB. text area. The two totals are separated by a TAB character NB. to facilitate pasting into adjacent columns of a spreadsheet. NB. each line between a jhtablea and jhtablez here is a table row NB. Table 1 jhtablea jhtr ;:'Bid Suit Double Honors WeThey' jhtr ('bg1'jhradio'one';0;'bidgroup');('sg4'jhradio'NT';0;'suitgroup');('dg0'jhradio'not';1;'dblgroup');('hg0'jhradio'none';1;'honorgroup');('wt0'jhradio'We';0;'wetheygroup') jhtr ('bg2' jhradio'two';0;'bidgroup');('sg3' jhradio'♠';0;'suitgroup');('dg1' jhradio'double';0;'dblgroup');('hg100' jhradio'100';0;'honorgroup');('wt1'jhradio'They';0;'wetheygroup') jhtr ('bg3' jhradio'three';0;'bidgroup');('sg2' jhradio'♥';0;'suitgroup');('dg2' jhradio'redouble';0;'dblgroup');('hg150' jhradio'150';0;'honorgroup') jhtr ('bg4' jhradio'four';0;'bidgroup');('sg1' jhradio'♦';0;'suitgroup') jhtr ('bg5' jhradio'five';0;'bidgroup');('sg0' jhradio'♣';0;'suitgroup') jhtr <('bg6' jhradio'six';0;'bidgroup') jhtr <('bg7' jhradio'seven';0;'bidgroup') jhtablez NB. Table 2 NB. There are two (jh)textarea's below where results are displayed for the user(s). NB. Although both are "edittable", that function is not useful except in NB. rare occasions for the second textarea. jhtablea NB. jhtr (;:'Made Results'),<'Edit the area below, as desired' jhtr (;:'Made'),a:,<'Edit the area below, as desired' jhtr ('made'jhselect Choices);('output1' jhtextarea '';25;20);('output2' jhtextarea '';30;50) jhtablez ) NB. This jev_get and create combination is obligatory in all JHS applications NB. that interact with their own html pages. jev_get=: create create=: 3 : 0 'bridge'jhr'' 9!:7 boxstd 9!:7 boxorig ev_start_click'' ) NB. Although in this application there are routinely 3 blocks of text NB. that are passed around, only 2 such blocks are required NB. here at the start. NB. Notice the JASEP that separates the blocks in the j code. NB. There are 3 buttons and 1 selector which are clicked by the user NB. and that require unique j attention. You see them just below. NB. The workhorse routine is the last one: ev_made_change. NB. All of the radio button inputs are handled routinely by JHS NB. utility code. ev_start_click=: 3 : 0 Text =: i. 0 rubber'' jhrajax ('no results, yet'),JASEP,Text ) ev_made_change=: 3 : 0 ". getv 'result1' Text =: (getv 'result3'),LF,". getv 'result2' if. 1<#Scores do. jhrajax (show >{:Scores),JASEP,Text,JASEP,'' else. jhrajax 'no results, yet',JASEP,Text,JASEP,'' end. ) ev_undo_click=: 3 : 0 u '' if. 1<#Scores do. jhrajax (show >{:Scores),JASEP,Text,JASEP,'' else. jhrajax 'no results, yet',JASEP,Text,JASEP,'' end. jhrajax ('no results, yet'),JASEP,Text ) ev_redo_click=: 3 : 0 u 1 if. 1<#Scores do. jhrajax (show >{:Scores),JASEP,Text,JASEP,'' else. jhrajax 'no results, yet',JASEP,Text,JASEP,'' end. jhrajax ('no results, yet'),JASEP,Text ) NB. The CSS is woefully empty because I cannot NB. determine how to use CSS techniques with my NB. app that is based on j's library of html code NB. generators. I would like guidance on how to NB. make better use of CSS. CSS=: 0 : 0 body{margin:10px;} #output1{background:yellow;font-family:"Courier New","Courier New";font-size:14px;} #output2{background:aqua;font-family:"Monaco","Courier New";font-size:12px;} h1 {background:gold;} table {background: lightgray; border:8px double red; border-collapse: collapse;} td {border:4px single red; border-style: none solid none solid; border-collapse: collapse;} th {text-align: middle;} ) JS=: 0 : 0 NB. javascript // Originally, this app was written around a We button and a They button // triggering the scoring calculations. But because We vs They can be // readily known before play begins, the triggering action was // made to be the Made selector. But the code already worked well // for the we_click and they_click events, so the function // ev_made_change() just calls the remnants of the earlier functions. function ev_made_change() { var WT = checkRadio(document.j.wetheygroup); if (WT == 0) {ev_we();} if (WT == 1) {ev_they();} } function ev_we(){ // Collect the users selections via 4 radio button sets // and 1 selection list/menu. var selectedBidgroup = checkRadio(document.j.bidgroup); var selectedSuitgroup = checkRadio(document.j.suitgroup); var selectedDblgroup = checkRadio(document.j.dblgroup); var selectedHonorgroup = checkRadio(document.j.honorgroup); var temp = selectedBidgroup+" "+selectedSuitgroup+" "+selectedDblgroup+" "+selectedHonorgroup; // The 2 key calculation verbs, b and e, require identical left and right arguments. // Their left arguments are collected into the var temp. // Their right arguments are derived from the selection list/menu "made". result1.value = temp+" b "+document.j.made.options[jbyid("made").selectedIndex].text; result2.value = temp+" e "+document.j.made.options[jbyid("made").selectedIndex].text; // The third block of data passed around are the "echoes" produce by the verb e // and are maintained in the hidden "result3". result3.value = document.getElementById("output2").value; // The next lines reset the radio button selections and the "made" selection // to their default or more neutral settings. (Considerable research // was required to achieve these resets.) document.getElementById("made").selectedIndex=document.getElementById("made").size - 14; var oForm = document.getElementById('j'); window.scrollTo(0, 0); clearForm(oForm); // Finally jdoajax is used to pass results from j ("the server") back to the "client". jdoajax(['result1','result2','result3'],""); } // Those results have to be received properly by the client. In this application // the last two chunks are concatenated with javascript "+". function ev_made_change_ajax(ts){ output1.value=ts[0]; output2.value=ts[1]+ts[2]; } // ev_they is almost identical to ev_we_click, above // The only difference is the require "_" prepending the bid producing // result1 and result2. This distinguishes They from We. function ev_they(){ var selectedBidgroup = checkRadio(document.j.bidgroup); var selectedSuitgroup = checkRadio(document.j.suitgroup); var selectedDblgroup = checkRadio(document.j.dblgroup); var selectedHonorgroup = checkRadio(document.j.honorgroup); var temp = selectedBidgroup+" "+selectedSuitgroup+" "+selectedDblgroup+" "+selectedHonorgroup; result1.value = "_"+temp+" b "+document.j.made.options[jbyid("made").selectedIndex].text; result2.value = "_"+temp+" e "+document.j.made.options[jbyid("made").selectedIndex].text; result3.value = document.getElementById("output2").value; document.getElementById("made").selectedIndex=document.getElementById("made").size - 14; var oForm = document.getElementById('j'); window.scrollTo(0, 0); clearForm(oForm); jdoajax(['result1','result2','result3'],""); } // Each ev_..._click has a partner ev_..._click_ajax // which is pretty boring, here. function ev_they_click_ajax(ts){ output1.value=ts[0]; output2.value=ts[1]+ts[2]; } function ev_start_click(){jdoajax(['result1','result2','result3'],"");} function ev_undo_click(){jdoajax(['result1','result2','result3'],"");} function ev_undo_click_ajax(ts){ output1.value=ts[0]; output2.value=ts[1]+ts[2]; } function ev_redo_click(){jdoajax(['result1','result2','result3'],"");} function ev_redo_click_ajax(ts){ output1.value=ts[0]; output2.value=ts[1]+ts[2]; } function ev_start_click_ajax(ts){ output1.value='no results, yet'; output2.value='no results, yet'; } // Next ev_..._click()s are for change in jhs805 jevdo() function ev_bg1_click(){return true;} function ev_bg2_click(){return true;} function ev_bg3_click(){return true;} function ev_bg4_click(){return true;} function ev_bg5_click(){return true;} function ev_bg6_click(){return true;} function ev_bg7_click(){return true;} function ev_sg4_click(){return true;} function ev_sg3_click(){return true;} function ev_sg2_click(){return true;} function ev_sg1_click(){return true;} function ev_sg0_click(){return true;} function ev_dg0_click(){return true;} function ev_dg1_click(){return true;} function ev_dg2_click(){return true;} function ev_hg0_click(){return true;} function ev_hg100_click(){return true;} function ev_hg150_click(){return true;} function ev_wt0_click(){return true;} function ev_wt1_click(){return true;} // This utility function clearForm() resets radio buttons. // http://www.javascript-coder.com/javascript-form/javascript-reset-form.phtml // thank you function clearForm(oForm) { var elements = oForm.elements; for(i=0; i<elements.length; i++) { field_type = elements[i].type.toLowerCase(); switch(field_type) { case "radio": if (elements[i].checked) { elements[i].checked = false; } if (elements[i].name=="dblgroup" && elements[i].id=="dg0"){ elements[i].checked = true; } if (elements[i].name=="honorgroup" && elements[i].id=="hg0"){ elements[i].checked = true; } break; default: break; } } } // taken from http://www.homeandlearn.co.uk/JS/radio_buttons.html function checkRadio(group){ var Group = ""; var len = group.length; var i; for (i=0; i<len; i++) { if (group[i].checked){ Group = group[i].id; return Group.slice(2); break; } } } )
bridge.ijs
This is the script for the basic j application.
NB. revised from bridgeHenry.ijs NB. which was created by Henry Rich NB. thank you, Henry coclass'bridge' createfile =: monad define fn =: <jpath'~temp/','bridge','.txt',~(<@:":@{.;@,<@(_2&({.!.'0'))@":"0@(1 2 3&{))6!:0'' LF 1!:2 fn ) Note 'examples' rubber'' NB. creates a new backup file which b updates NB. required to start plain bridge.ijs successfully ********* '2 s' r 0 NB. followed by entering the result, or changing b to e first NB. 0 means we just made contract '2 C' r -1 NB. -1 means we are down 1 '-6 n d 150' r 0 NB. they, doubled with 150 honors ' 4 s n 100' r 1 NB. n is required "not doubled" bc honors must be 4th show >{:Scores NB. displays current rubber u '' NB. undoes last b entry by changing history NB. examples below work with Henry's bridgescore, not used here 5 1 1 2 bridgescore _8 NB. The biggest number I ever collected _4600 2 3 1 1 bridgescore 0 NB. 2S sawed, making, vul 670 ) NB. main verb is bridgescore, but it is revised here in NB. the verb bs. The verb b calculates inputs to bs NB. b calculates vulnerability and legs inputs NB. automatically from the history in Scores. NB. r enables the user to enter alpha characters into b instead NB. of coded integers for suits and ddubling (d or r).! NB. (btw, the x inputs to b and e are also resequenced NB. relative to bridgescore and echoinput) W =: 6 NB. width of column S =: SubtractForMe =: 1 NB. set back to 0 if you want Henry's "made" 3 : 0 '' if. S do. Choices =: (":each ;/6}.i: _13);21;7 else. Choices =: (a:,":each ;/7}.i: _13);21;0 end. ) rem0 =: -.&0 rubber =: monad define Scores =: <4$a: createfile'' ) boxorig =: '┌┬┐├┼┤└┴┘│─' boxorig =: a.{~16+i.11 boxvert =: 2|.11 {. '|' boxstd =: 2|.11({.!.'+')'|-' 9!:7 boxorig bs =: 4 : 0 NB. bridgescore tricked up 'level suit dbl honors vul leg' =. x , (#x) }. 0 0 0 0 0 0 psb=. 0 if. S do. if. y>0 do. y =. y - level end. end. if. y < 0 do. if. dbl do. (-honors),~dbl * 100 + (y * 300) - 100 * ((y * -.vul) >. _2) else. (-honors),~y * vul { 50 100 end. else. 'bb aa' =. (2^dbl) * (10 0 * suit=4) + (level,y) * suit { 2 3 # 20 30 pts =. (insult =. dbl * 50) + bb + game =.(100 <: leg+bb) { psb , vul { 300 500 pts =. pts + slam =. (<vul,level) { _8 {."1 ] 500 1000 ,: 750 1500 pts =. honors+pts + over =. dbl { aa , (>:vul) * y * 100 200 bb, rem0 slam, game, over, insult, honors end. ) tab =: TAB&([`(i.&' '@])`]}) lf =: ,@(,.&LF) NB. This is a revised version of the verb "show" NB. especially for JHS. The "standalone" NB. "show" is in the required file: NB. bridge.ijs . NB. The revision does not use smoutput to send NB. intermediate results to the user NB. console. Instead, the intermediate NB. results are collected into the noun "out". show =: monad define pairs =. _2]\y out =. lf }:}.2 2":W&":@,.@rem0 each {.pairs below =. 0 2":W&":@,.@rem0 each }.pairs 'wb tb' =. {:pairs if. wb +.&(100<:(+/)) tb do. out =. out,lf below else. out =. out,lf }:below end. out =. out,'totals: ' htmlboxchar out =. (' We They',LF,LF),out,tab ": +/+/"1>pairs ) z =: 9484 9516 9488 9500 9532 9508 9492 9524 9496 9474 9472 - 9344 char =: a.& i. expand =: (16+i. 11)&( {&1 1j2@(11&>@i.)) mask =: (16+i. 11)&(11&>@i.) NB. htmlboxchar defaults to apply to an html textarea using LF NB. <br/> works better with jhtml. htmlboxchar =: 3 : 0 LF htmlboxchar y : Char =. char ,y,"1 x Starts =. (expand I.@#mask) Char Expanded =. z([{~16-~mask@] #])`(2+Starts"_)`(expand@] #])} Char Expanded =. 226 Starts}Expanded a.{~Expanded =. 148 (Starts+1)}Expanded ) cleanNeg =: ('_',>:@(i.&'-')}.])^:('-'&e.) NB. r is like b in its results NB. but x for r is a string like '-2 s d 100' NB. instead of _2 3 1 100 r =: dyad define boxed =. ;:cleanNeg x bid =. ". >0{boxed suit =. 'cdhsn' i. tolower>1{boxed dbl =. 0 honors =. 0 if. 3<:#boxed do. dbl =. 'ndr' i. tolower>2{boxed end. if. 4<:#boxed do. honors =. ".>3{boxed end. smoutput (bid,suit,dbl,honors) bf y (": bid,suit,dbl,honors),' b ',": y ) NB. b computes vulnerability and adds leg NB. before calling bs, the real scorer b =: dyad define pairs =. _2]\>{: Scores 'wa ta'=. {. pairs 'wb tb'=. {: pairs newgameQ =. wb +.&(100<:(+/)) tb team =. 0&>@{. x leg =. 0 vulQ =. 0 if. newgameQ do. 'wb tb'=. 2$a: else. leg =. team{wb,&(+/)tb end. vulQ =. +./(100&<:)@(+/)&> team{"1 }.pairs xx =. 6{.leg 5}x,4#0 xx =. vulQ 4}xx r =. (|xx) bs y t=. 2{.r t=. r,0 t=. (2>.#r){.r if. -.team do. if. 0<{. r do. wa =. rem0(}.t),wa wb =. rem0({.t),~wb else. ta =. (-{.t),ta wa =. (-{:t),wa end. else. if. 0<{. r do. ta =. rem0(}.t),ta tb =. rem0({.t),~tb else. wa =. (-{.t),wa ta =. (-{:t),ta end. end. scores =. ((<wa),<ta),2}.>{:Scores if. newgameQ do. scores =. scores,((<wb),<tb) else. scores =. ((<wb),<tb),~_2}.scores end. smoutput show scores fn 1!:3~ (": x),' b ',(":y),LF i.0 0[Scores =: Scores,<scores ) NB. bf computes vulnerability and adds leg NB. before calling bs, the real scorer NB. but does not save any results in NB. a file or in a global noun NB. like b does. b and bf are almost identical. NB. Needed for the verb r which uses NB. both b and bf. bf =: dyad define pairs =. _2]\>{:Scores 'wa ta'=. {. pairs 'wb tb'=. {: pairs newgameQ =. wb +.&(100<:(+/)) tb team =. 0&>@{. x leg =. 0 vulQ =. 0 if. newgameQ do. 'wb tb'=. 2$a: else. leg =. team{wb,&(+/)tb end. vulQ =. +./(100&<:)@(+/)&> team{"1 }.pairs xx =. 6{.leg 5}x,4#0 xx =. vulQ 4}xx r =. (|xx) bs y t=. 2{.r t=. r,0 t=. (2>.#r){.r if. -.team do. if. 0<{. r do. wa =. rem0(}.t),wa wb =. rem0({.t),~wb else. ta =. (-{.t),ta wa =. (-{:t),wa end. else. if. 0<{. r do. ta =. rem0(}.t),ta tb =. rem0({.t),~tb else. wa =. (-{.t),wa ta =. (-{:t),ta end. end. scores =. ((<wa),<ta),2}.>{:Scores if. newgameQ do. scores =. scores,((<wb),<tb) else. scores =. ((<wb),<tb),~_2}.scores end. smoutput xx e y smoutput show scores ) h =: help =: 0 : 0 bid suit [dbl honors vul leg] (0=clubs .. 4=NT) negative "bid" means "They"; positive "bid" means "We" suits: 0=clubs, 1=diam, 2=hearts, 3=spades, 4=NT ) echoinput=: 4 : 0"1 0 'level suit dbl honors vul leg' =. x , (#x) }. 0 0 0 0 0 0 Bid=.":level Suit=. ' ',suit pick ;: 'club diamond heart spade notrump' Num=. 's '}.~(2>level)+.suit>3 Dbl=. dbl pick '';;:'doubled redoubled' Vul=. ' ',vul pick '';'vulnerable' Result0=. ', ',(*y) pick ;:'making making down' Result1=. ' ',(*y) pick <@":"0 (y+level),(y+level),-y Leg=. ' ',(*leg) pick '';'with leg of ',":leg Honors=. ' ',(*honors) pick '';'with honors of ',":honors Bid,Suit,Num,Dbl,Vul,Result0,Result1 Bid,Suit,Num,Dbl,Vul,Leg,Honors,Result0,Result1 ) NB. Notice that e does NOT compute vulnerabilty e =: 4 : 0 'level suit dbl honors vul leg' =. x , (#x) }. 0 0 0 0 0 0 WT=. >(*level){' ';'We bid ';'They bid ' Bid=.":|level Suit=. ' ',suit pick ;: 'club diamond heart spade notrump' Num=. 's '}.~(2>|level)+.suit>3 Dbl=. dbl pick '';;:'doubled redoubled' Vul=. ' ',vul pick '';'vulnerable' if. S do. if. y>0 do. y =. y- |level end. end. Result0=. ', ',(*y) pick ;:'making making down' Result1=. ' ',(*y) pick <@":"0 (y+|level),(y+|level),-y Leg=. ' ',(*leg) pick '';'with leg of ',":leg Honors=. ' ',(*honors) pick '';'with honors of ',":honors Bid,Suit,Num,Dbl,Vul,Result0,Result1 WT,Bid,Suit,Num,Dbl,Vul,Leg,Honors,Result0,Result1 ) NB. u does an undo for an empty value of y NB. u does a redo for y=1 NB. " " an undo for y=_1, for example u=: monad define if. y-:'' do. Scores =: _1|. Scores fn 1!:3~ 'Scores =: _1|. Scores',LF else. Scores =: y|. Scores fn 1!:3~ 'Scores =: ',(":y),'|. Scores',LF end. ) NB. score bridge (duplicate and Chicago) NB. x is contract: level suit vul dbl [leg partscorebonus] NB. suit is 0=C, 4=NT NB. dbl is 0, 1, or 2 NB. y is result, neg=down, nonneg=made NB. result is score for contracting side (****revised****) NB. Does not support honors (****revised****) NB. Results are below- and above-line scores for made contracts; NB. *negative* of scores for bidders, defenders for unmades bridgescore =: 4 : 0"1 0 NB. 'level suit vul dbl leg psb honors' =. x , (#x) }. 0 0 0 0 0 50 0 'level suit vul dbl leg honors' =. x , (#x) }. 0 0 0 0 0 0 psb=. 0 if. y < 0 do. if. dbl do. (-honors),dbl * 100 + (y * 300) - 100 * ((y * -.vul) >. _2) else. (-honors),y * vul { 50 100 end. else. 'bb aa' =. (2^dbl) * (10 0 * suit=4) + (level,y) * suit { 2 3 # 20 30 pts =. (dbl * 50) + bb + (100 <: leg+bb) { psb , vul { 300 500 pts =. pts + (<vul,level) { _8 {."1 ] 500 1000 ,: 750 1500 pts =. honors+pts + dbl { aa , (>:vul) * y * 100 200 bb,pts-bb end. )