Anyone who can write an APL function should be able to host it on the web.™
Rendered webpage |
APL code |
:Class Snakes_And_Ladders : MiPageSample
⍝ Control:: _html.svg _DC.StackPanel _html.style
⍝ Description:: Classic Snakes and Ladders Game
⍝ Notes::
⍝ Demonstrates using JQ.Position to manipulate svg elements
⍝ Incorporates external "business logic" from #.SNLMS3 developed for Live Code Jugalbandi at #FnConf15
:field private Turn←0
:field public _Sessioned←1
:field public Positions←-1
maxPlayers←4
colors←'blue' 'purple' 'salmon' 'cyan'
Players←⍬
:section Utilities
⍝ define a color token (player marker)
token←{t⊣(t←('#player',⍕⍵)New _.svg '' ('width=50 height=50')).Add _.circle '' ('cx=25 cy=25 r=20 stroke=black stroke-width=4 fill=',⍺)}
⍝ use jQueryUI's Position utility to place tokens on playing board
moveToken←{('#player',⍕⍺) #.JQ.Position 'left bottom'(∊'left' ' bottom'{⍺,('-+'[1+0⌈×⍵]),(⍕|⍵)}¨(⊂⍺ ⍵)⊃offsets) '#board' 'none'}
:endsection
:section Main Rendering
∇ Compose;frm;sp;businessLogic
:Access public
Add _.title'S & L'
Use'JQueryUI'
Add _.style ScriptFollows
⍝ #output table {border: 1px solid black;border-collapse:collapse;font-size:.8em;}
⍝ #output th {border: 1px solid black}
⍝ #output td {border: 1px solid black}
⍝ .snlbutton {width:100px;margin-left:25px;}
⍝ .snltab td {width:100px;text-align:center}
⍝ svg {display:none;z-index:2;transition:0.5s} /* hide the player tokens */
⍝ #player2 {transition-delay:0.5s}
⍝ #player3 {transition-delay:1.5s}
⍝ #player4 {transition-delay:2s}
:If 0=#.⎕NC'SNLMS3' ⍝ load the "business logic" if not already loaded
⍝ businessLogic←(_Request.Server.Config.AppRoot,3↓⊃#.Files.SplitFilename _PageName),'SNLMS3'
businessLogic←(_Request.Server.Config.AppRoot,1↓⊃⎕nparts _PageName),'SNLMS3'
⎕SE.SALT.Load businessLogic,' -target=#'
:EndIf
Add _.h3'Snakes and Ladders a la MiServer'
frm←Add _.Form
⍝'#players'('min' 1)('max'maxPlayers)('step' 1)frm.Add _.Input'number' 1 'Number of Players '
'for' 'players'frm.Add _.label'Number of Players '
'#players'frm.Add _.Select(,¨⍳4)1
('.snlbutton'frm.Add _.Button'Play').On'click' 'start'
('#single' '.snlbutton'frm.Add _.Button'Single Step').On'click' 'start'
Add _.br
(sp←Add _.StackPanel).Horizontal←1
sp.Add('board'New _.img''(⊂'src'(({(¯1+⍵⍳'/')↓⍵}⊃#.Files.SplitFilename _PageName),'snakes_and_ladders.jpg')))
sp.Add('output'New _.div)
Add _.Handler'body' 'play' 'playRound'
Add¨(colors token¨⍳maxPlayers)
∇
:endsection
:section Callbacks
∇ r←start;players
:Access public
:If 'single'≢_what ⍝ if we're not single stepping
:OrIf Positions∨.<0 ⍝ or if the previous game finished
Positions←#.SNLMS3.Init Players←0 Get'players'
Turn←0
:EndIf
⍝ construct offsets for tokens for all board positions
offsets←107 ¯107∘ר⌽¨¯1+⍳#.SNLMS3.(Rows Cols)
offsets[2 4;]←⌽offsets[2 4;]
offsets←,⍤2⊢(,0 53∘.,0 ¯53)∘.+offsets
players←'#player'∘,¨⍕¨N←⍳Players
r←Execute'svg'#._JSS.Hide''
r←{Execute ⍵ #._JSS.Show''}¨players
r,←playRound
∇
∇ r←playRound;Start;Type;Rolls;mask;tab;data
:Access public
r←''
(Turn Start Rolls Positions Type)←Turn #.SNLMS3.playaround Positions
mask←<\Positions<0 ⋄ (mask/Type)←⊂'Winner!' ⍝ mark first winning position, if any
data←(⊂''),⍉↑Start Rolls(|Positions)Type
tab←'.snltab'New #._.Table('Player' 'Start' 'Roll' 'End' 'Type'⍪data)
tab.HeaderRows←1
tab.CellAttr←(⍴data)⍴⊂''
tab.CellAttr[;1]←{'style="background-color:',⍵,'"'}¨Players↑colors
r,←'#output'Replace tab
r,←N{Execute ⍺ moveToken ⍵}¨|Positions
:If (_what≡'single')<~∨/mask
r,←Execute'$("body").trigger("play")'
{}⎕DL Players×1<Turn
:EndIf
∇
:endsection
:EndClass