2048: Difference between revisions

7,818 bytes added ,  6 days ago
→‎{{header|Wren}}: Removed redundant initializeBoard method.
(→‎{{header|Wren}}: Removed redundant initializeBoard method.)
 
(15 intermediate revisions by 4 users not shown)
Line 11:
:*   All tiles move as far as possible in that direction, some move more than others.
:*   Two adjacent tiles (in that direction only) with matching numbers combine into one bearing the sum of those numbers.
:*   A move is valid when at least one tile can be moved,   if onlyincluding by combination.
:*   A new tile with the value of   '''2'''   is spawned at the end of each turn at a randomly chosen empty square   (if there is one).
:*   Adding a new tile on a blank space.   Most of the time,   a new   '''2'''   is to be added,   andbut occasionally   ('''10%''' of the time),   a   '''4'''.
:*   To win,   the player must create a tile with the number   '''2048'''.
:*   The player loses if no valid moves are possible.
 
Line 22:
 
;Requirements:
* &nbsp; "Non-greedy" movement. &nbsp; <br>&nbsp; The tiles that were created by combining other tiles should not be combined again during the same turn (move). &nbsp; <br>&nbsp; That is to say, &nbsp; that moving the tile row of:
 
<big><big> [2][2][2][2] </big></big>
Line 34:
<big><big> .........[8] </big></big>
 
* &nbsp; "Move direction priority". &nbsp; <br>&nbsp; If more than one variant of combining is possible, &nbsp; move direction shall indicate which combination will take effect. <br>&nbsp; For example, moving the tile row of:
 
<big><big> ...[2][2][2] </big></big>
Line 48:
 
 
* &nbsp; Check for valid moves. &nbsp; The player shouldn't be able to skipgain theirnew turntile by trying a move that doesn't change the board.
* &nbsp; Check for a &nbsp;win condition.
* &nbsp; Check for a lose condition.
<br><br>
Line 8,135:
Loop</syntaxhighlight>
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
begin enum 123
_lf
_rt
_dn
_up
_new
_end
end enum
str63 bd
colorref color(11)
byte zs
 
void local fn initialize
subclass window 1, @"2048",(0,0,438,438)
fn WindowSetBackgroundColor( 1, fn ColorBlack )
color(0) = fn ColorDarkGray
color(1) = fn ColorGray
color(2) = fn ColorLightGray
color(3) = fn ColorBlue
color(4) = fn ColorBrown
color(5) = fn ColorCyan
color(6) = fn ColorGreen
color(7) = fn ColorMagenta
color(8) = fn ColorOrange
color(9) = fn ColorPurple
color(10) = fn ColorYellow
color(11) = fn ColorRed
end fn
 
void local fn drawBoard
int x, y,r = 1, add
cls
for y = 320 to 20 step -100
for x = 20 to 320 step 100
rect fill (x,y,98,98),color( bd[r] )
select bd[r]
case < 4 : add = 40
case < 7 : add = 30
case < 10 : add = 20
case else : add = 6
end select
if bd[r] then print %(x+add, y+25)2^bd[r]
r++
next
next
end fn
 
local fn finish( won as bool )
CFStringRef s = @"GAME OVER"
CGRect r = fn windowContentRect( 1 )
r.origin.y += r.size.height - 20
r.size.height = 100
window 2,,r,NSwindowStyleMaskBorderless
if won
fn windowSetBackgroundColor( 2, color(11) )
s = @"CONGRATULATIONS—YOU DID IT!!"
text,24,fn ColorBlack,,NSTextAlignmentCenter
else
fn windowSetBackgroundColor( 2, fn ColorBlack )
text,24,fn ColorWhite,,NSTextAlignmentCenter
end if
print s
button _new,,,@"New Game", (229,20,100,32)
button _end,,,@"Quit", (109,20,100,32)
end fn
 
void local fn newGame
int r
text @"Arial bold", 36, fn ColorBlack, fn ColorClear
bd = chr$(0)
for r = 1 to 4
bd += bd
next
bd[rnd(16)] ++
do
r = rnd(16)
until bd[r] == 0
bd[r]++
zs = 14
fn drawBoard
end fn
 
local fn play( st as short, rd as short, cd as short )
short a, b, c, t, moved = 0
for a = st to st + rd * 3 step rd
// SHIFT
t = a
for b = a to a + cd * 3 step cd
if bd[b]
if t <> b then swap bd[t], bd[b] : moved ++
t += cd
end if
next
// MERGE
for b = a to a + cd * 2 step cd
if bd[b] > 0 && bd[b] == bd[b+cd]
bd[b]++ : c = b + cd
// FILL IN
while c <> a+cd*3
bd[c] = bd[c+cd] : c += cd
wend
bd[c] = 0
// CHECK FOR WIN
if bd[b] == 11 then fn drawBoard : fn finish( yes ) : exit fn
zs ++ : moved ++
end if
next
next
fn drawBoard
if moved == 0 then exit fn
// GROW
b = 0 : c = rnd(zs)
while c
b ++
if bd[b] == 0 then c--
wend
if rnd(10) - 1 then bd[b]++ else bd[b] = 2
zs--
timerbegin 0.25
fn drawBoard
timerend
if zs then exit fn
// IS GAME OVER?
for a = 1 to 12
if bd[a] == bd[a+4] then exit fn
next
for a = 1 to 13 step 4
if bd[a] == bd[a+1] || bd[a+1] == bd[a+2] || bd[a+2] == bd[a+3]¬
then exit fn
next
fn finish( no )
end fn
 
local fn doDialog(ev as long,tag as long, wnd as long)
select ev
case _windowKeyDown : if window() == 2 then exit fn
select fn EventKeyCode
case _up : fn play(13, 1, -4)
case _dn : fn play( 1, 1, 4)
case _lf : fn play( 1, 4, 1)
case _rt : fn play( 4, 4, -1)
case else : exit fn
end select
DialogEventSetBool(yes)
case _btnClick : window close 2
if tag == _end then end
fn newGame
case _windowWillClose : if wnd == 1 then end
end select
end fn
 
fn initialize
fn newGame
on dialog fn doDialog
 
handleevents
</syntaxhighlight>
[[File:FutureBasic 2048.png]]
 
=={{header|Go}}==
Line 9,159 ⟶ 9,325:
}
</syntaxhighlight>
 
=={{header|jq}}==
'''Works with jq, the C implementation of jq'''
 
'''Works with gojq, the Go implementation of jq'''
 
Except for trivial changes to one or two lines in the "play" function, the following
implementation is generic with respect to the number of rows and
columns. The target value can also be specified when calling `play`.
 
As of this writing, neither the C nor Go implementations of jq include
a built-in PRN generator and so in the following the MRG32k3a module
available at [[:Category:jq/MRG32k3a.jq|MRG32k3a.jq]] is used.
<syntaxhighlight lang="jq">
include "MRG32k3a" {search: "."}; # see comment above
 
### Generic functions
 
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;
 
# Create an m x n matrix with initial values specified by .
def matrix($m; $n):
if $m == 0 then []
else . as $init
| if $m == 1 then [range(0;$n) | $init]
elif $m > 0 then
matrix(1; $n) as $row
| [range(0; $m) | $row ]
else error("matrix\($m);\($n)) invalid")
end
end;
 
 
### The 2048 Game
# Left-squish the input array in accordance with the game requirements for a single row
def squish:
def squish($n):
def s:
if length == 0 then [range(0;$n)|null]
elif .[0] == null then .[1:] | s
elif length == 1 then . + [range(0; $n - 1)|null]
elif .[0] == .[1] then [.[0] + .[1]] + (.[2:]|squish($n-1))
else .[0:1] + (.[1:]|squish($n-1))
end;
s;
squish(length);
 
# Input: a matrix of rows
def squish_left:
[.[] | squish];
 
def squish_right:
[.[] | reverse | squish | reverse];
 
def squish_up:
transpose
| [.[] | squish]
| transpose;
 
def squish_down:
transpose
| [.[] | reverse | squish | reverse]
| transpose;
 
# Gather the [i,j] co-ordinates of all the null values in the input matrix
def gather:
if length == 0 then error end
| (.[0] | length) as $cols
| [range(0;length) as $i
| range(0; $cols) as $j
| select(.[$i][$j] == null) | [$i,$j]]
| if length == 0 then error end ;
 
# Input: {matrix}
# Add a random 2 or 4 if possible, else error
# Output: includes .prng for the PRN generator
def add_random:
(.matrix | gather) as $gather
| ($gather | length) as $n
| if $n == 0 then error end
| if .prng == null then .prng = seed(now | tostring | sub("^.*[.]";"") | tonumber) end
| .prng |= nextFloat
| $gather[.prng.nextFloat * $n | trunc] as [$i,$j]
| .prng |= nextFloat
| (if (.prng.nextFloat) < 0.1 then 4 else 2 end) as $exmachina
| .matrix[$i][$j] = $exmachina ;
 
def prompt: "[ijkl] or [wasd] or q to quit or n to restart:";
 
def direction:
{"i": "up", "j": "left", "k": "down", "l": "right",
"w": "up", "a": "left", "s": "down", "d": "right",
"q": "quit",
"n": "restart"
};
 
# Recognize $goal as the goal
def play($goal):
 
# Pretty print
def pp:
.matrix[] | map(. // "." | lpad(4)) | join(" ");
 
def won:
any(.matrix[][]; . == $goal);
 
def lost:
.matrix
| (squish_left == .) and (squish_right == .) and
(squish_up == .) and (squish_down == .);
 
def round:
pp,
if lost then "Sorry! Better luck next time.", play($goal)
else prompt,
( (try input catch halt) as $in
| .matrix as $matrix # for checking if a move is legal
| .emit = null
| direction[$in | ascii_downcase] as $direction
| if $direction == "up" then .matrix |= squish_up
elif $direction == "down" then .matrix |= squish_down
elif $direction == "left" then .matrix |= squish_left
elif $direction == "right" then .matrix |= squish_right
elif $direction == "quit" then .emit = "bye"
elif $direction == "restart" then .emit = "restart"
else .emit = "unknown direction \($direction) ... please try again."
end
| if .emit == "bye" then .emit, halt
elif .emit == "restart" then "Restarting...", play($goal)
elif .emit != null then .emit, round
elif .matrix == $matrix then "Disallowed direction! Please try again.", round
elif won then pp, "Congratulations!", play($goal)
else add_random | round
end)
end;
 
{ matrix: (null | matrix(4;4))}
| .matrix[2] = [null,2,2,2]
| round;
 
play(2048)
</syntaxhighlight>
Invocation: jq -nRrf 2048.jq
{{output}}
<pre>
. . . .
. . . .
. 2 2 2
. . . .
[ijkl] or [wasd] or q to quit or n to restart:
l
2 . . .
. . . .
. . 2 4
. . . .
[ijkl] or [wasd] or q to quit or n to restart:
 
...etc...
</pre>
 
 
=={{header|Julia}}==
Line 16,536 ⟶ 16,862:
{{libheader|Wren-fmt}}
{{libheader|Wren-str}}
<syntaxhighlight lang="ecmascriptwren">import "./dynamic" for Enum, Struct
import "random" for Random
import "./ioutil" for Input
import "./fmt" for Fmt
import "./str" for Str
 
var MoveDirection = Enum.create("MoveDirection", ["up", "down", "left", "right"])
Line 16,558 ⟶ 16,884:
}
_rand = Random.new()
initializeBoard()
}
 
initializeBoard() {
for (y in 0..3) {
for (x in 0..3) _board[x][y] = Tile.new(0, false)
}
}
 
9,490

edits