NYCJUG/2017-02-14

From J Wiki
Jump to navigation Jump to search

Beginner's regatta

Removing Column Groups

Wherein we show how to clean up some messy real-world data.

The Problem

First, we read in a matrix from file and split it assuming it's tab-delimited by line.

   'tt mm'=. split <;._1&>TAB,&.><;._2 ] LF (],[ #~[ ~:[: {:]) CR-.~fread 'matrix1012.txt'
   $mm
337 4111
   $tt
4111

We have titles' vector tt corresponding to columns in our matrix mm.

How Messy the Data Are

Here's what these two arrays look like:

 
   13{.tt
++--------------++++++++++----------------++
||6MAvgChg1MRecC||||||||||AdjChgEPStoSales||
++--------------++++++++++----------------++

Each of the above factors has 10 industry codes associated with it: these are the column groups, as seen below. We want to remove three columns, accounting for the multiple columns in a group.

   
   3 11{.tt,mm                NB. 1st column group: 6MAvgChg1MRecC
+----------+--------------+--+--+--+--+--+--+--+--+--+
|          |6MAvgChg1MRecC|  |  |  |  |  |  |  |  |  |
+----------+--------------+--+--+--+--+--+--+--+--+--+
|          |EN            |MA|IN|CD|CS|HC|FN|IT|TS|UT|
+----------+--------------+--+--+--+--+--+--+--+--+--+
|1989-01-31|0             |0 |0 |0 |0 |0 |0 |0 |0 |0 |
+----------+--------------+--+--+--+--+--+--+--+--+--+

Dropping off the initial date column to better see the tabular data next to it:

   11}."1 ] 3 21{.tt,mm       NB. 2nd column group: AdjChgEPStoSales
+----------------+--+--+--+--+--+--+--+--+--+
|AdjChgEPStoSales|  |  |  |  |  |  |  |  |  |
+----------------+--+--+--+--+--+--+--+--+--+
|EN              |MA|IN|CD|CS|HC|FN|IT|TS|UT|
+----------------+--+--+--+--+--+--+--+--+--+
|0               |0 |0 |0 |0 |0 |0 |0 |0 |0 |
+----------------+--+--+--+--+--+--+--+--+--+

Here's a corner of the matrix we are going to associate with the data item title code immediately preceding it.

   3 3{.mm
+----------+--+--+
|          |EN|MA|
+----------+--+--+
|1989-01-31|0 |0 |
+----------+--+--+
|1989-02-28|0 |0 |
+----------+--+--+
   15{.tt
++--------------++++++++++----------------++++
||6MAvgChg1MRecC||||||||||AdjChgEPStoSales||||
++--------------++++++++++----------------++++

Initial Cleaning

Here we see how the sparse title line hints at how we might partition the column groups.

   a:~:15{.tt
0 1 0 0 0 0 0 0 0 0 0 1 0 0 0

Here are the titles of the column groups we want to remove:

   rms=. 'GrossProfittoAssets';'IndRel_GrossProfittoAsset';'5YExpEGrowth'
   indyPtn=. (1) 0}a:~:tt
   $indyPtn
4111
   {.&.>indyPtn<;.1 tt
+--+----------------+------------------+------------------+--------------...
|++|+--------------+|+----------------+|+----------------+|+-------------...
|||||6MAvgChg1MRecC|||AdjChgEPStoSales|||AdjEPSNumRevFY1C|||AdjEPSNumRevF...
|++|+--------------+|+----------------+|+----------------+|+-------------...
+--+----------------+------------------+------------------+--------------...

At this point we have all the names of all the data items partitioned by industry.

   (<rms) e.~&.>{.&.>indyPtn<;.1 tt
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...

Cleaning the Mess

Now we have the proper data structures to easily work with our data, it should be a cinch to get it into a usable format. Comments are inline here:

   +/;(<rms) e.~&.>{.&.>indyPtn<;.1 tt
3                                       NB. Check that we’re removing only the 3 we want.
   rmvec=. 1$~#indyPtn
   #&><;.1~indyPtn                      NB. Length of each partition
1 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10...
   $;(<rms) e.~&.>{.&.>indyPtn<;.1 tt   NB. Check that size will be what we want.
412
   npp=. #&><;.1~indyPtn                NB. Number per partition
   ~.rmvec=. npp# -.;(<rms) e.~&.>{.&.>indyPtn<;.1 tt
1 0                                     NB. Ensure “rmvec” is boolean
   +/rmvec
4081                                    NB. Width we’ll get after removing 3 groups.
   $indyPtn
4111
   +/-.rmvec
30                                      NB. Check that total = removed + result
   +/;(<rms) e.~&.>{.&.>(rmvec#indyPtn)<;.1 tt#~rmvec
0
   $mm
337 4111
   $rmvec#"1 mm
337 4081

How We Worked This Out

In the course of exploring this data, we came to rely on a few trusty utilities. Here are some to switch between enclosed and tab-delimited text mats.

NB.* tabMatify (was "usuMatify"): tab-delimited fields, LF-terminated lines -> boxed mat.
tabMatify=: (TAB,LF)&([: <;._1&> (0 { [) ,&.> [: <;._2 ] (],[ #~ [ ~:[: {:])~ 1 { [)"0 1
NB.* tabUnmatify (was "unmatify"): inverse of "tabMatify" above.
tabUnmatify=: ([: ; [: , [: (] _1}&.|:~ (10{a.) ,~&.> [: }:&.> {:"1) (9{a.) ,~&.> ])

Using these, we can easily fix what ails our data and write out the corrected version to another file.

               
   $(tabUnmatify rmvec#"1 tt,mm)
2766293
   1!:43''
Z:\Alphaworks\Weights
   (tabUnmatify rmvec#"1 tt,mm) fwrite 'matrix1012.txt'
2766293

Hunting, then Gathering

Once we have successfully worked out how to wrestle one unruly data source into the ground, along comes another one. Wouldn't it be nice to have a handy toolset to work with? We already have the start of it with the utilities above.

Now we can go back over the preceding and gather up the good lines. Generally, the ones we want have an assignment, so we search on '='.

gatherGood=: 0 : 0
   'tt mm'=. split <;._1&>TAB,&.><;._2 ] LF (] , [ #~ [ ~: [: {: ]) CR-.~fread 'matrix1012.txt'
   rms=. 'GrossProfittoAssets';'IndRel_GrossProfittoAsset';'5YExpEGrowth'
   $indyPtn=. (1) 0}a:~:15{.tt
   indyPtn=. (1) 0}a:~:tt
   rmvec=. 1$~#indyPtn
   npp=. #&><;.1~indyPtn   NB. Number per partition
   ~.rmvec=. npp# -.;(<rms) e.~&.>{.&.>indyPtn<;.1 tt
   indyPtn=. (1) 0}a:~:15{.tt

NB.* tabMatify (was "usuMatify"): usual tab-delimited fields, LF-terminated lines -> boxed matrix.
tabMatify=: (TAB,LF)&([: <;._1&> (0 { [) ,&.> [: <;._2 ] (] , [ #~ [ ~:[: {:])~ 1 { [)"0 1
NB.* tabUnmatify (was "unmatify"): inverse of "tabMatify" above.
tabUnmatify=: ([: ; [: , [: (] _1}&.|:~ (10{a.) ,~&.> [: }:&.> {:"1) (9{a.) ,~&.> ])

   (tabUnmatify rmvec#"1 tt,mm) fwrite 'matrix1012.txt'
)

We see that there is some repetition and a few extraneous leading characters, so we eliminate the extraneous characters and take only the last assignment of any duplicate definition. Then we replace the specific input with a parameter and encapsulate this as a new verb. We also change the hard-coded names of column groups to remove to be the left argument.

NB.* rmColGroups: remove column groups designated by x from matrix
NB. file y and replace the file with the reduced (text) matrix.
rmColGroups=: 4 : 0
   'tt mm'=. split <;._1&>TAB,&.><;._2 ] LF (] , [ #~ [ ~: [: {: ]) CR-.~fread y
   indyPtn=. (1) 0}a:~:tt
   npp=. #&><;.1~indyPtn      NB. Number per partition
   rmvec=. npp# -.;(<x) e.~&.>{.&.>indyPtn<;.1 tt
   (tabUnmatify rmvec#"1 tt,mm) fwrite 'matrix1012.txt'
NB.EG  ('GrossProfittoAssets';'IndRel_GrossProfittoAsset') rmColGroups 'matrix1012.txt'
)

On further reflection, change the comparison line to be case insensitive:

rmvec=. npp# -.;(<toupper&.>x) e.~&.>toupper&.>{.&.>indyPtn<;.1 tt

rmColGroups=: 4 : 0
   'tt mm'=. split <;._1&>TAB,&.><;._2 ] LF (] , [ #~ [ ~: [: {: ]) CR-.~fread y
   indyPtn=. (1) 0}a:~:tt
   npp=. #&><;.1~indyPtn      NB. Number per partition
   rmvec=. npp# -.;(<toupper&.>x) e.~&.>toupper&.>&.>{.&.>indyPtn<;.1 tt
   (tabUnmatify rmvec#"1 tt,mm) fwrite 'matrix1012.txt'
NB.EG  ('GrossProfittoAssets';'IndRel_GrossProfittoAsset') rmColGroups 'matrix1012.txt'
)

Show-and-tell

Building Cost Curves

Convexification

The portfolio optimizers require that cost curves be convex. That is, the sequence of slopes of the cost curve must be nondecreasing, where the slope between two adjacent points a and b

CostCurve0.jpg

where

It is perfectly possible to import cost curves which are not convex, and the importer will not complain if you do so (most of ITG's cost curves are not strictly convex). Imported cost curves are used, unmodified, when a transaction cost model is queried from TradeSim. However, before cost curves are passed to the optimizer, they are made convex by removing a minimal number of breakpoints needed to eliminate all concave bulges from the original curve. (Or equivalently, these concave segments are made linear.)

The algorithm for doing this works as follows:

  1. If the curve consists of just two breakpoints, terminate.
  2. Iterate through the list with a sliding window of size three. For windows (a,b,c) that have slope(a,b) > slope(b,c), mark b for deletion.
  3. Remove all marked breakpoints from the curve. If no breakpoints have been marked, the curve is convex, and we terminate.
  4. Repeat.

Build Cost Curve to Combine a Minimum Amount with a Minimum Percentage

We work out how to do this by starting with a specific example:

   minamt=. 125
   maxpct=. 0.5
   tgt=. 25e3  NB. New min of $125 / 0.5%
   tgt=. minamt%maxpct%100
   mat=. 0 0$a:
for_ix. i.#pxs do.
   px=. ix{pxs
   shrs=. i.>:<.tgt%px
   pcts=. (0) 0}100*minamt%shrs*px
   pairs=. ,shrs,.pcts
   pairs=. pairs,tgt,0.5,1e8,0.5
   id=. ix{ids
   mat=. mat,id;detrail&.>16j4":&.>pairs
end.

NB. ..
costCurve=: 3 : 0
   (tgt;minamt;maxpct) costCurve y
:
   'id px'=.  y [ 'tgt minamt maxpct'=. x
   shrs=. i.>:<.tgt%px
   pcts=. (0) 0}100*minamt%shrs*px
   pairs=. (,shrs,.pcts),tgt,maxpct,1e8,maxpct
   id;detrail&.>16j4":&.>pairs
)

Generalizing this, we develop the following code:

NB.* buildCC.ijs: build cost curves given flattened basket of universe (e.g.
NB. "flatSP100" below [omitted]).

require 'dsv'

NB.* costCurve: build cost curve for (minimum dollar amount)>.(cost % of trade)
costCurve=: 3 : 0
   25e3 125 0.5 costCurve y
:
   'id px'=.  y [ 'tgt minamt maxpct'=. x
   px=. ".px
   shrs=. i.>:<.tgt%px
   pcts=. (0) 0}100*minamt%shrs*px
   pairs=. (,shrs,.pcts),(>:>./shrs),maxpct,1e8,maxpct
   id;detrail&.>16j4":&.>pairs
)

NB.* buildCCs: build cost curve files so that cost per trade is $125 or 0.5%,
NB. whichever is higher: this is not possible without specifying the curve for
NB. every share amount up to $25,000 worth of shares.
buildCCs=: 3 : 0
   125 0.5 buildCCs y    NB. x: min $ amount, min % as whole number (10 = 10% = 0.1)
:
   'pfx tt flatU'=. y [ 'minamt maxpct'=. x
   whdts=. tt e.~&> '/'
   tgt=. minamt%maxpct%100
   for_col. I. whdts do.
       pxs=. }.col{"1 flatU
       whpxs=. -.pxs e. <'NaN'
       ids=. whpxs#}.flatU{"1~tt i. <'Issue ID'
       pxs=. whpxs#pxs
       dt=. ;2 0 1{<;._2 '/',~>col{tt   NB. '12/31/2015' -> 20151231
       flnm=. pfx,'.',dt,'.csv'
       cc=. (<tgt,minamt,maxpct) costCurve &> <"1 ids,.pxs
       cc=. <;._2 ' '-.~(',';'') makedsv_pdsv_ cc
       cc=. ;LF,~&.>(<',,') detrail &.> cc
       (('#Date:',dt,LF),cc) fwrite flnm
    end.
)

NB.* detrail: remove trailing {.x after {:x
detrail=: 3 : 0
   '0.' detrail y   NB. 0s after '.'
:   
   whd=. y i. {:x                       NB. Where decimal point is
   if. 0~:#decimal=. whd }. rr=. y do.  NB. If anything after decimal
       nt=. ({.x) ([: +/ [: *./\ [: |. =) decimal NB. Number of trailing items
       nt=. -nt+nt=<:#decimal NB. Also drop decimal point if only all trailing after it
       rr=. (whd{.y),nt}.decimal
   end.
   rr
NB.EG ('50.05';'0.5';'0';(,'0');'0.2';'100';'101')-:detrail '50.050';'0.5000';'0';'0.0';'0.20';'100';'101'
)

Ensuring Convexity

Now we apply the rules given above for ensuring that our curve is convex, working through an iterative process manually.

   qts''
2016 11 29 14 36 28.492
   6!:2 'buildCCs ''Generic150min05pct'';tt;<flatSP100'
567.751

   $sampcc=. _2<\}.11931401,0,0,1,8.479,2,4.2395,3,2.8263,4,2.1198,5,1.6958,6,1.4132,7,1.2113,8,1.0599,9,0.9421,10,0.8479,11,0.7708,12,0.7066,13,0.6522,14,0.6056,15,0.5653,16,0.5299,17,0.5,100000000,0.5
19 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) sampcc
8.479 0 _0.0001 0.0003 _0.0002 0.0002 _0.0001 0.0001 _0.0003 0.0001 _0.0002 0.0004 _0.0006 _0.0002 0.0011 _0.0011 0.0216 0.5
   $newsampcc=. sampcc#~1,~1,2<:/\slopes
11 2
   newsampcc
  0      0
  3 2.8263
  5 1.6958
  7 1.2113
  9 0.9421
 11 0.7708
 13 0.6522
 14 0.6056
 16 0.5299
 17    0.5
1e8    0.5
   $sampcc=. _2[\}.  NB. Sample generated cost curve  00169001,0,0,1,110.0934,2,55.0467,3,36.6978,...219,0.5027,220,0.5004,221,0.5,100000000,0.5 NB. AAPL on 10/31/2016
223 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) sampcc
110.093 0 0 _0.0002 0.0003 _0.0001 _0.0002 0.0004 _0.0002 _0.0004....
   $newsampcc=. sampcc#~1,~1,2<:/\slopes
113 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
55.0467 _0.0001 4.73695e_15 _6.66667e_5 _0.0001 0.0002 _0.0002...
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
57 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
27.5233 _5e_5 _3.55271e_15 _6e_5 _0.0001 3.33333e_5 0 _7.14286e_...
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
31 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
9.1744 _4e_5 _5.71429e_5 0.0001 _3.33333e_5 _2.85714e_5 0.00015 ...
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
19 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
3.0581 2e_5 _2.85714e_5 _9.16667e_5 _7.77778e_5 1.09314e_15 _8e_5 ...
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
13 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
1.6937 _7.77778e_5 _4.28571e_5 _7.5e_5 _5.71429e_5 _1.86047e_5 ...
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
10 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
1.4877 _5e_5 _5.71429e_5 _4e_5 _7.77778e_5 2.5e_5 0.0013 0.412 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
7 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
0.8878 _4.93151e_5 2.5e_5 0.0013 0.412 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
6 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
0.5588 2.5e_5 0.0013 0.412 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
5 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
0.5073 0.0013 0.412 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
4 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
0.5004 0.412 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
3 2
   ]slopes=. ((2 -~/\ */"1) % 2 -~/\ 0 {"1 ]) newsampcc
0.5 0.5
   $newsampcc=. newsampcc#~1,~1,2<:/\slopes
3 2
   newsampcc
  0   0
221 0.5
1e8 0.5

Advanced topics

We look at an email discussion of GUI-building and graphical tool tutorials, then take a look at the conversion of a sophisticated bridge-scoring system from a command-line based on jconsole version to a graphical one based on JHS.

Qt or GUI tutorials and information

From: Robert Herman rpjherman@gmail.com via forums.jsoftware.com 
To: programming@jsoftware.com
Date: Mon, Jun 6, 2016 at 1:47 AM

I am trying to change my usage of J only for simple calculations and small programs, and I would like to try to develop or copy some other apps I have made with a GUI. Other than the demos or studio examples, are there any A-Z guides on using Qt to build apps with windows, forms, buttons, events, etc...?

Along the lines of a 'J GUIs for C Programmers' would be a nice start. I can't seem to make the leap to a GUI app in J without just using JHS.

I have seen the YouTube videos by Martin Saurer using qjide, and I know of JHS, but I am really looking for vanilla Qt with J. Thanks.

Rob ---

From: robert therriault bobtherriault@mac.com via forums.jsoftware.com 

Hi Rob,

Probably a good place to start is the j wiki http://code.jsoftware.com/wiki/Guides/Window_Driver . http://code.jsoftware.com/wiki/Guides/Window_Driver/Form_Definition is also useful to see how forms are constructed http://code.jsoftware.com/wiki/Guides/Window_Driver/Layout gives a sense of how bins (used for layout of controls) can be used. Joe Bogner also did a very useful write up that helps explain bins a bit further. http://code.jsoftware.com/wiki/User:Joe_Bogner/QtLayout A way to see things in action is to access the Help/Studio/Showcase... Menu. If you select 'events' from the list that pops up and click ok - you will see the results of the script. To see the script itself double click on 'events' and the script itself pops up.

That should get you started.

Cheers, bob ---

From: Raul Miller

You have seen the "Studio..." option under Help? The labs, in particular, have some good stuff. Don't be afraid to ask, though, if something doesn't seem to work right - there's been quite a lot of version drift since some of that was originally written. Thanks, ---

 
From: Robert Herman

Thanks, guys. I think part of my confusion comes from the different ways a GUI is made in different J versions. I had thought the WD driver was the older way, and that there was a new way to use Qt directly or as in the JQT terminal. I will certainly get back to those suggestions this week, and ask questions. OT: Robert, your video tutorials worked great on my Win 10 and Linux box without issue, and the behavior of the popups and buttons was as expected; no surprises. I would have replied inline, but I did not know how to reply when the list was being sent as a daily digest. Good work! Rob ---

From: robert therriault

Thanks for the feedback on the video tutorials Rob. The biggest challenge that I find with them is the amount of work that goes into creating them and it is good to hear that are working across different systems.

As Raul mentioned, keep asking questions as you explore. It allows us to learn together.

Cheers, bob ---

From Raul Miller rauldmiller@gmail.com via forums.jsoftware.com 

You were not completely wrong: there have been changes to the WD driver to adapt it to the features and shortcomings of Qt. So some of the old stuff will fail and if you try those things you should get an error message that explains what is broken. Hopefully it will also be obvious how to fix the problem - if not, please ask. (And if a question gets asked a lot, that might motivate us to improve and/or better document that part of the system.) Thanks,


Bridge Scoring – from jconsole to JHS

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

Bridge system screenshot.jpg

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 [some of] 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 ('1'jhradio'one';0;'bidgroup');('4'jhradio'NT';0;'suitgroup');('0'jhradio'not';1;'dblgroup');('0'jhradio'none';1;'honorgroup');('0'jhradio'We';0;'wetheygroup')
jhtr ('2' jhradio'two';0;'bidgroup');('3' jhradio'♠';0;'suitgroup');('1' jhradio'double';0;'dblgroup');('100' jhradio'100';0;'honorgroup');('1'jhradio'They';0;'wetheygroup')
jhtr ('3' jhradio'three';0;'bidgroup');('2' jhradio'♥';0;'suitgroup');('2' jhradio'redouble';0;'dblgroup');('150' jhradio'150';0;'honorgroup')
jhtr ('4' jhradio'four';0;'bidgroup');('1' jhradio'♦';0;'suitgroup')
jhtr ('5' jhradio'five';0;'bidgroup');('0' jhradio'♣';0;'suitgroup')
jhtr <('6' jhradio'six';0;'bidgroup')
jhtr <('7' 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. 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;
…

// 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=="0"){
				elements[i].checked = true;
			}
			if (elements[i].name=="honorgroup" && elements[i].id=="0"){
				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;
        break;
    }
}
}

)

bridge.ijs

This is [some of] 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