User:Brian Schott/code/BridgeScoring

From J Wiki
Jump to navigation Jump to search

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

Screen Shot 2016-04-02 at 8.25.56 AM.png

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.
)