:Namespace phase2 ⍝ -*- mode:dyalog -*-

 ⍝ ⎕IO=1 is assumed throughout these solutions.

 ⍝ Dyalog 18.0 is used.

    ⎕IO←1

 ⍝ Q1 subspace journey

 ⍝ FIXME: Please specify which filling index to use

     when the regions overlap in T2.

 ⍝ In T3, "in the range 1-≢subspaces" looks confusing, could

     replace it with "⍳≢subspaces" or just plain English "from

     1 to ≢subspaces".



 ⍝ My first attempt for Task 1 is using 

 ⍝ note that:  a runs 1 2⍴b 1  is  ⌽(a⍴2)⊤2*b-1


 ⍝ first to compute the numbers

    num←{⎕IO←0 ⋄ 2*¯1+(⊣/⍵)+⍳⊢/⍵}


      runs←{

          ⍝ each  is just a name for

          ⍝ inner loop

          each←⌽⍤(+/(⍺⍴2)⊤num)

          ∨⌿⍺ each⍤1⊢⍵

      }


 ⍝ For Task 2,  ∘.∧  is used.

      fill←{

          size←⍺

          rank←≢size

          reshap←⍉(2 rank)∘⍴

          run←{⌽+/(⍺⍴2)⊤num ⍵} ⍝ Rewrite of T1

          each←{⊃∘.∧/size run¨↓reshap ⍵}

          ⌈⌿(⍳≢⍵)(×⍤0 rank)each⍤1⊢⍵

      }


 ⍝ T3, the keyword is  ⍸ .

      subspaces←{

          frames←⍵(=⍤99 0)⍳⌈/,⍵

          rank←≢⍴⍵

          space←(⌊⌿(⊣,1∘+⍤-⍨)⌈⌿)∘↑∘⍸

          space⍤rank⊢frames

      }


 ⍝ Q2: Reshaping Reshape


 ⍝ FIXME:

 ⍝ Should the reshape function handle  ⎕IO  for robustness? This

 ⍝ is a minor issue though.

 

 ⍝ In T2 Examples,

 ⍝ "1.5 4 reshape2 ⍳10 ⍝ 1.5 truncates the data repeats the data"

 ⍝ it seems to be not cleaned up the "truncates the data".



 ⍝ Is it possible to do it by  ⍤ ?

    ∇ out←shape reshape in;idx;i

      out←in⍴⍨|shape

      idx←⍸0>,shape

      :For i :In idx

          out←⌽[i]out

      :EndFor

   


 ⍝ FIXME: The T2 Example seems to be wrong!

       ¯3 ¯2.5 phase2.reshape2 'brian' 'adam' 'morten' 'micheal'

 ⍝ ┌───────┬──────┐

 ⍝ │            

 ⍝ ├───────┼──────┤

 ⍝ │micheal│morten│

 ⍝ ├───────┼──────┤

 ⍝ │adam   │brian │

 ⍝ └───────┴──────┘

       3 2.5 phase2.reshape2 'brian' 'adam' 'morten' 'micheal'

 ⍝ ┌──────┬───────┐

 ⍝ │brian │adam  

 ⍝ ├──────┼───────┤

 ⍝ │morten│micheal│

 ⍝ ├──────┼───────┤

 ⍝ │           

 ⍝ └──────┴───────┘

      reshape2←{

          data←,⍵

          ⍝ not very clever solution

          0.5∊|⍺:data reshape⍨(×⍺)×(⌊(≢data)÷0.5~⍨|⍺)@(0.5∘=)|⍺

          1.5∊|⍺:data reshape⍨(×⍺)×(⌈(≢data)÷1.5~⍨|⍺)@(1.5∘=)|⍺

          2.5∊|⍺:((×⍺)×i@(2.5∘=)|⍺)reshape(s×i←⌈(≢data)÷s←2.5~⍨|⍺)↑data

          ⍺ reshape ⍵

      }


 ⍝ Q3: Meetings of the Minds

 ⍝ Since the sample data files are not available,

     only a brief outline would be here.

      Attended←{

          ⍝ The idea is create a discrete representation

          ⍝ for float time intervals computed by ⎕DT

      }

 ⍝ FIXME: T2: What is the exact criteria for attending one day?

     Marked as Attended in more than half of the sessions?

     Or been present for more than half of the total time?

     Or at least attended one session?

      ShowedUp←{

          ⍝ It would be just string matching by = since

          ⍝ the time and date are fixed width format.

      }

 ⍝ FIXME: T3: The "The matrix should not include any

     sessions that are break periods" seems confusing.

     (obscured the issue)


 ⍝ Q4: Instant-Runoff Voting

 ⍝ FIXME: T1: The box is not drawn in the last Example:

       1 phase2.Ballot 150

 ⍝ ┌───┬─┐

 ⍝ │150│1│

 ⍝ └───┴─┘

      Ballot←{

          ⍝ candidates

          c←|⍺

          ⍺>0:{(≢⍵)⍺}⌸?⍨⍤0⊢⍵⍴c

          ⍺<0:{(≢⍵)⍺}⌸{(⍳n)@(⍵?⍨n←?⍵)⊢⍵⍴0}⍤0⊢⍵⍴c

      }


 ⍝ Slow on larger input, but works ;)

    ∇ r←IRV ballot;num;rank;vote;round;lose

      r←⍬

      num←ballot[;1]

      ⍝ if a candidate lose, the rank of

      ⍝ the ballot increase 1

      rank←1⍴⍨≢num

      vote←ballot[;2]

      lose←⍬

     loop:

      ⍝ result of each round

      round←⊃+/num×rank=vote

      r,←⊆((⍳∘≢(/⍨)×){⍺,⍵}⌸~∘0)round

      ⍝ win if has majority of *current* votes

      →((⌈/round)>2÷⍨+/num×rank∊¨vote)/win

      ⍝ tie if all identical

      →((1≥≢∘∪)round~0)/0

      ⍝ keep record of losers

      lose,←(⊢⍸⍤=(⌊/~∘0))round

      ⍝ purge losers by increase rank

      rank←{⍵+(⊃∊∘lose⍤⍸)¨⍵=vote}⍣≡rank

      →loop

     win:

      r,←⊆(⊢⍳⌈/)round

   


 ⍝ Q5: Base85


 ⍝ FIXME: > 2. Convert the Step 1 result from base256 to base85

     It would be nice to at least mention:

     "every 32 (=4×2⍟265) bit group as an integer is decoded into 5

     base85 numbers".

     I referenced Wikipedia's Ascii85 page for this question.

    Original←⎕UCS 32+⍳85

      Base85←{

          ⍝ it is better off start from 0

          ⎕IO←0

          Encode←{

              data←⍵,0⍴⍨p←4|4-4|≢⍵

              ⍺[(-p)↓,⍉(5⍴85)⊤256∘⊥⍤1⊢data⍴⍨4,⍨4÷⍨≢data]

          }

          ⍝ too lazy just copy for the Encode

          Decode←{

              bin←85~⍨⍺⍳⍵

              data←bin,84⍴⍨p←5|5-5|≢bin

              (-p)↓,⍉(4⍴256)⊤85∘⊥⍤1⊢data⍴⍨5,⍨5÷⍨≢data

          }

          2|⎕DR ⍵:⍺ Encode ⍵

          ⍺ Decode ⍵

      }


 ⍝ Q6: It's a Date!

 ⍝ Really? I guess we are supposed to write parsing function

 ⍝ by hand this time. I have rarely attempted this in APL

 ⍝ so I just see how far I can get it.


 ⍝ FIXME: I have yet no idea on how to handle  "  or  '  in

     pattern string for escaping without making the answer

     very complex.

     A difficult case would be handle  "  and  '  together:

       '"''" DD '' " "'''⊃⍤(1200⌶)1232

 ⍝ ' 17  " "

     My answer also makes assumption that only

     character in   '_YMmDdhstP'  are treated for special,

     and that also means "ISO week number", "day of year",

     "Ordinal indicator" that are not shown in the Example

     are not handled, although it should not be difficult to

     implement them in theory by the method I use.

 

 ⍝ I suggest list all the special characters that are needed

     to be handled to avoid any confusion.

 

 ⍝ Well, I think "compute the date given any 2~3 of year, month,

     day, day-of-week" alone is already a complex enough

     puzzle idea. To make this question easier some hints

     could be provided.

 

 ⍝ The last quote and trailing space in this Example looks strange:

     'MM/DD/YY tP:mm' DDN '02/17/22 3P:39 ''

 

 ⍝ Is a negetive number accepted result?

       1 ⎕DT ⊂22 1 1 1 0 0 0

 ⍝ ¯685923.9583



 ⍝ It is not easy to handle the case the pattern

 ⍝ contains date like stuff for non format spec part,

 ⍝ or the variable length format spec like  'Dddd' .

 ⍝ A seemingly reliable method is compile the pattern to PCRE

 ⍝ and let  ⎕R  do all the heavy liftings, but that involves

 ⍝ escaping. I'd go with the straight forward method.


 ⍝ A good news is  'DdddDdd'  is not valid input. And I'm not

 ⍝ going to handle string escaping in this solution for the

 ⍝ reason stated in FIXME, so it is feasible to tokenize the

 ⍝ pattern by all to uppercase then compare element wise.


 ⍝ There are definitely shorter methods to generate these.

    month←'January' 'February' 'March' 'April' 'May' 'June'

    month,←'July' 'August' 'September' 'October'

    month,←'November' 'December'

    week←'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday'

    week,←'Saturday' 'Sunday'

      ⍝ helper functions

      ⍝ match length

    matlen←{(('|'(∊1↓∘,,⍤0)⍺)⎕S 1⍠ 'IC' 1)⍵}

      ⍝ ⍺  is a fmt spec,    is the input,

      ⍝ return length to be take from the input

      flen←{

          'Y'=⊃⍺:≢⍺

          ⍝ length less than 3 are simple

          4>≢⍺:≢⍺

          ⍝ match month length

          'mM'∊⍨2⊃⍺:month matlen ⍵

          ⍝ match day of week length

          'dD'∊⍨2⊃⍺:week matlen ⍵

          ⍝ catch all, signal an error to debug

          ⎕SIGNAL 666

      }


 ⍝ This might be improved to handle escaping.

 ⍝ But so far it is good enough.

       lex 'MM/DD/YY tP:mm'

 ⍝ ┌───────────────────┬─────────────────────────┐

 ⍝ │1 0 1 0 1 0 1 1 0 1│┌──┬─┬──┬─┬──┬─┬─┬─┬─┬──┐│

 ⍝ │                   ││MM│/│DD│/│YY│ │t│P│:│mm││

 ⍝ │                   │└──┴─┴──┴─┴──┴─┴─┴─┴─┴──┘│

 ⍝ └───────────────────┴─────────────────────────┘

      lex←{

      ⍝ special chars

          c←'_YMmDdhstPp'

      ⍝ format

          (⊃¨⍤⊂∘l,⍥⊂⊂∘⍵)m←(l∧1,2≠/⎕C ⍵)∨1,2≠/l←⍵∊c

      }


      label←{

          'hstP'∊⍨⊃⍵:⊃⍵

          'Y'=⊃⍵:⎕C⍣(4>≢⍵)⊢'Y' ⍝ the two digit Y

          'p'=⊃⍵:'P'

          2=≢⍵:⍵[2]

          1=≢⍵:⊃⍵

          'd'=⎕C ⍵[2]:'d'

          'm'=⎕C ⍵[2]:'M'

          ⍝ signal an error to debug

          ⎕SIGNAL 666

      }


      numval←{

          (s n)←⎕VFI ⍵

          s:n

          2≥≢⍵:'p'=⎕C⊃⍵ ⍝ AM is 0, PM is 1

          mon←∨/⍵⍷↑month

          day←∨/⍵⍷↑week

          ∨/mon:⍸mon

          ∨/day:⍸day ⍝ 1 is Monday, 7 Sunday

          ⎕SIGNAL 666

      }


    ∇ table←str parse(fmt spec);key;val;i;n

      key←⍬

      val←⍬

      :For i :In ⍳≢fmt

          :If fmt[i]

              n←(i⊃spec)flen str

              key,←label i⊃spec

              val,←numval n↑str

              str←n↓str

          :Else

              str←str↓⍨≢i⊃spec

          :EndIf

      :EndFor

    ⍝ only pick last one.

      table←key{⍺,⊃⌽⍵}⌸val

   


    ⍝ Lemma: https://cs.uwaterloo.ca/~alopez-o/math-faq/node73.html

    ⍝ January 1 year N occurs on the same day of the

    ⍝ week as January 1 year N + 400.

      guessday←{

            ⍝ ⍵ is any of (mon day week) in order

            ⍝ ⍺ is a boolean mask over (mon day week)

            ⍝ year mon day week

          table←{(3↑⊃¯1 ⎕DT ⍵),3⌷⊃¯11 ⎕DT ⍵}⍤0⊢⍳146098 ⍝ 1900/1/1 to 2300/1/1

            ⍝ return (year mon day)

          (⍵≡⍤1⊢(0,⍺)/table)⌿1 1 1 0/table

      }


    ⍝ Finally

    ∇ ddn←pattern DDN string;tb;lookup;guess

      tb←string parse lex pattern

      lookup←{(tb[;2],0)[tb[;1]⍳⍵]}

      ⍝ normalize 12 hour time

      tb⍪←'h',(lookup't')+12×lookup'P'

      ⍝ Has no week of day, which is great.

      :If ~'d'∊tb[;1]

          tb⍪←3 2⍴'Y'(1900+lookup'y')'M' 1 'D' 1 ⍝ default year mon day

           ⍝ for 2 digits year num this would be negative

           ⍝ but I guess it would be fine.

          ddn←¯1 1 ⎕DT⊂lookup'YMDhms'

          :Return

      :EndIf

      ⍝ Do some guesswork

      guess←(0∘≠guessday~∘0)lookup'MDd'

      :If 'Y'∊tb[;1]

          ddn←(lookup'Y'),1↓,1↑((lookup'Y')=⍥(400∘|)guess[;1])⌿guess

      :ElseIf 'y'∊tb[;1]

          ddn←,1↑((lookup'y')=100|guess[;1])⌿guess

      :Else

          ddn←,1↑guess

      :EndIf

      ddn,←,lookup'hms'

      ddn←¯1 1 ⎕DT⊂ddn

   

:EndNamespace