Anyone who can write an APL function should be able to host it on the web.™
Rendered webpage |
APL code |
2048 | ▲ | 0 | ||||||||||||||||
◄ |
| ► | ||||||||||||||||
Use keyboard's arrow keys | ▼ | ? |
:class The_2048_Game :MiPageSample
⍝ Control:: _DC.Table
⍝ Description:: Simple version of the addictive "2048" sliding game
:field Public _Sessioned←1
:field public BOARD
∇ Compose;u;l;r;d;board;help;keys;score;name
:Access Public
:Trap 0 ⍝ initialize RNG
⎕RL←⍬
:Else
{}16807⌶2
:EndTrap
BOARD←Put2 4 4⍴0 ⍝ create initial board state the board
Add _.style ScriptFollows
⍝ #game {font-size:xx-large; margin: auto;}
⍝ #game td {vertical-align: middle; text-align: center;}
⍝ .slide, #help {background: darkorange; color:white; cursor: pointer; line-height: 2em;
⍝ border-radius: 2em; padding: 5px; margin: auto; height: 2em; width: 2em;}
⍝ #board td {height: 3em; width: 3em; max-width: 3em; overflow: visible;
⍝ background: #FFC680; box-shadow: 0 0 0 3px white inset;}
⍝ #status {position: fixed; text-align: center; top: 75px; bottom: 0; left: 0; right: 0;
⍝ color: darkorange; font-size: 2em; line-height: calc(100vh - 2em); cursor: pointer;}
⍝ #keys {font-size: medium; width: 2em; white-space: nowrap; color: darkorange;}
⍝ #name {width: 0; color: darkorange; font-size: 200%;}
⍝ #score {width: 2em; direction: rtl; text-align: right;}
Add _.title'2048'
help←'#help' 'target="_blank"'New _.A' ? ' 'https://en.wikipedia.org/wiki/2048_(video_game)#Gameplay'
keys←'#keys'New _.div'Use keyboard''s arrow keys'
board←'#board'New _.div(Disp BOARD)
name←'#name'New _.div 2048
score←'#score'New _.div 0
(u l r d)←'a1' 'a0' 'a2' 'a3'{⍺'.slide'New _.div ⍵}¨'▲' '◄' '►' '▼'
'game'Add _.Table(3 3⍴name u score l board r keys d help)
Add _.Handler'.slide' 'click' 'OnSlide'
⍝ If user presses a keyboard button "click" the corresponding element and return false to prevent scrolling the page:
On'keydown' 0 '' 'return!$("#a"+(event.which-37)).click().length[0]'
∇
∇ r←OnSlide;already;new
:Access public
already←Won BOARD
new←BOARD Slide⍎1↓_target
r←'#score'Replace Score new ⍝ right-to-left trickery to get cell overflow to the left
:If new≢BOARD ⍝ invalid slide if sliding did not do anything
BOARD←Put2 new
r,←'#board'Replace Disp BOARD
:If (Won BOARD)∧(~already) ⍝ won now
r,←Status'WIN – click to clear'
:ElseIf (Won BOARD)⍱(Movable BOARD) ⍝ cannot move and has not won
r,←Status'LOSS – click to clear'
:EndIf
:EndIf
∇
∇ board←Put2 board;what;empties;where ⍝ Add a 2 to an empty tile
what←2+2×1=?10 ⍝ a 2, but 1 in 10 chance of a 4
empties←Empties board
where←?+/empties ⍝ random empty cell
(where⊃empties/∊board)←what ⍝ do it
∇
∇ table←Disp board;empties ⍝ Create a display form of the board
empties←Empties board
(empties/∊board)←' ' ⍝ replace with spaces so they do not display
table←'#world'New _.Table board
∇
Pack←{ ⍝ Find the new row state caused by packing to the left
t←2*⍳16 ⍝ 2 4 8 16... 65536, the biggest tile that can be merged
pairs←2/¨t ⍝ (2 2)(4 4)(8 8)(16 16)...
results←,¨2×t ⍝ (,4)(,8)(,16)(,32)...
filled←⍵~0 ⍝ remove empty tiles to leave just the filled ones - packed to the left
packed←pairs ∆R results⊢filled ⍝ replace two identicals with one double-the-value
4↑packed ⍝ replenish with empty tiles to the right
}
Empties←0=∊
Movable←1∊0∘=,(⍉2=⌿⊢),2=/⊢ ⍝ Has empties or two identicals above each other or two identicals next to each other
Won←2048≤⌈/∘∊ ⍝ Do we have 2048 or higher?
∆R←{⎕UCS(⎕UCS¨⍺⍺)⎕R(⎕UCS¨⍵⍵)⎕UCS ⍵} ⍝ This is just a ⎕R which uses numbers instead of strings
Under←{⍵⍵⍣¯1 ⍺⍺ ⍵⍵ ⍵} ⍝ See http://www.dyalog.com/user-meetings/dyalog15.htm#D16
Rot_90←⍉∘⌽ ⍝ Rotate 90 degrees counterclockwise
Slide←{Pack¨Under↓Under(Rot_90⍣⍵)⊢⍺} ⍝ Rotate, split, pack each, mix, rotate back
Score←+/∘∊4×∘⌊2*⍨÷∘4 ⍝ 16: 16 + 8+8 + 4+4+4+4
Status←{'#contentblock'Append'#status' 'onclick="window.location.reload()"'New _.div ⍵}
:endclass