: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