Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
6
Task/2048/00-META.yaml
Normal file
6
Task/2048/00-META.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
category:
|
||||
- Puzzles
|
||||
- Games
|
||||
from: http://rosettacode.org/wiki/2048
|
||||
note: Games
|
||||
50
Task/2048/00-TASK.txt
Normal file
50
Task/2048/00-TASK.txt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
;Task:
|
||||
Implement a 2D sliding block puzzle game where blocks with numbers are combined to add their values.
|
||||
|
||||
|
||||
;Rules of the game:
|
||||
:* The rules are that on each turn the player must choose a direction (up, down, left or right).
|
||||
:* 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 only 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, and 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.
|
||||
|
||||
|
||||
The name comes from the popular open-source implementation of this game mechanic, [https://gabrielecirulli.github.io/2048/ 2048].
|
||||
|
||||
|
||||
;Requirements:
|
||||
* "Non-greedy" movement. <br> The tiles that were created by combining other tiles should not be combined again during the same turn (move). <br> That is to say, that moving the tile row of:
|
||||
|
||||
<big><big> [2][2][2][2] </big></big>
|
||||
|
||||
:: to the right should result in:
|
||||
|
||||
<big><big> ......[4][4] </big></big>
|
||||
|
||||
:: and not:
|
||||
|
||||
<big><big> .........[8] </big></big>
|
||||
|
||||
* "Move direction priority". <br> If more than one variant of combining is possible, move direction shall indicate which combination will take effect. <br> For example, moving the tile row of:
|
||||
|
||||
<big><big> ...[2][2][2] </big></big>
|
||||
|
||||
:: to the right should result in:
|
||||
|
||||
<big><big> ......[2][4] </big></big>
|
||||
|
||||
:: and not:
|
||||
|
||||
<big><big> ......[4][2] </big></big>
|
||||
|
||||
|
||||
|
||||
* Check for valid moves. The player shouldn't be able to skip their turn by trying a move that doesn't change the board.
|
||||
* Check for a win condition.
|
||||
* Check for a lose condition.
|
||||
<br><br>
|
||||
|
||||
1050
Task/2048/AArch64-Assembly/2048.aarch64
Normal file
1050
Task/2048/AArch64-Assembly/2048.aarch64
Normal file
File diff suppressed because it is too large
Load diff
142
Task/2048/ALGOL-68/2048.alg
Normal file
142
Task/2048/ALGOL-68/2048.alg
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
main:(
|
||||
INT side = 4;
|
||||
INT right = 1, up = 2, left = 3, down = 4;
|
||||
[]CHAR direction letters = "ruld";
|
||||
[]STRING direction descriptions = ("right", "up", "left", "down");
|
||||
|
||||
MODE BOARD = REF[,]INT;
|
||||
MODE CELL = REF INT;
|
||||
|
||||
OP = = (BOARD a, BOARD b) BOOL:
|
||||
(FOR i TO side DO FOR j TO side DO IF a[i,j] /= b[i,j] THEN mismatch FI OD OD;
|
||||
TRUE EXIT
|
||||
mismatch: FALSE);
|
||||
|
||||
PROC traverse board = (BOARD board, PROC(CELL)VOID callback) VOID:
|
||||
FOR i FROM 1 LWB board TO 1 UPB board DO
|
||||
FOR j FROM 2 LWB board TO 2 UPB board DO
|
||||
callback(board[i,j])
|
||||
OD OD;
|
||||
|
||||
PROC count blanks = (BOARD board) INT:
|
||||
(INT count := 0;
|
||||
traverse board(board, (CELL c)VOID: IF c = 0 THEN count +:= 1 FI);
|
||||
count);
|
||||
|
||||
PROC nth blank = (BOARD board, INT nth) CELL:
|
||||
(CELL result;
|
||||
INT count := 0;
|
||||
traverse board(board, (CELL c)VOID:
|
||||
(IF c = 0 THEN count +:= 1 FI;
|
||||
IF count = nth THEN
|
||||
result := c; return
|
||||
FI));
|
||||
return: result);
|
||||
|
||||
PROC add new number = (BOARD board) VOID:
|
||||
(INT nblanks = count blanks(board);
|
||||
INT number := (random >= .9 | 4 | 2);
|
||||
INT position := ENTIER (random * nblanks) + 1;
|
||||
|
||||
nth blank(board, position) := number);
|
||||
|
||||
PROC shift = (REF[]INT row, BOOL to the end) VOID:
|
||||
(INT from = (to the end | UPB row | LWB row),
|
||||
to = (to the end | LWB row | UPB row),
|
||||
dir = (to the end | -1 | 1);
|
||||
FOR i FROM from + dir BY dir TO to DO
|
||||
IF row[i] /= 0 THEN
|
||||
INT blank := 0;
|
||||
FOR j FROM i - dir BY -dir TO from WHILE row[j] = 0 DO
|
||||
blank := j
|
||||
OD;
|
||||
IF blank /= 0 THEN
|
||||
row[blank] := row[i];
|
||||
row[i] := 0
|
||||
FI
|
||||
FI
|
||||
OD);
|
||||
|
||||
PROC combine = (REF[]INT row, BOOL to the end) VOID:
|
||||
(INT from = (to the end | UPB row | LWB row),
|
||||
to = (to the end | LWB row | UPB row),
|
||||
dir = (to the end | -1 | 1);
|
||||
FOR i FROM from BY dir TO to - dir DO
|
||||
IF row[i] /= 0 AND row[i] = row[i+dir] THEN
|
||||
row[i] *:= 2;
|
||||
row[i+dir] := 0
|
||||
FI
|
||||
OD);
|
||||
|
||||
PROC move = (BOARD board, INT direction) VOID:
|
||||
FOR i TO side DO
|
||||
CASE direction IN
|
||||
# right # (shift(board[i,], TRUE); combine(board[i,], TRUE); shift(board[i,], TRUE)),
|
||||
# up # (shift(board[,i], FALSE); combine(board[,i], FALSE); shift(board[,i], FALSE)),
|
||||
# left # (shift(board[i,], FALSE); combine(board[i,], FALSE); shift(board[i,], FALSE)),
|
||||
# down # (shift(board[,i], TRUE); combine(board[,i], TRUE); shift(board[,i], TRUE))
|
||||
ESAC
|
||||
OD;
|
||||
|
||||
PROC print board = (BOARD board)VOID:
|
||||
(FOR i FROM 1 LWB board TO 1 UPB board DO
|
||||
print("+");
|
||||
FOR j FROM 2 LWB board TO 2 UPB board DO print("------+") OD;
|
||||
print((new line, "|"));
|
||||
FOR j FROM 2 LWB board TO 2 UPB board DO
|
||||
print(((board[i,j] = 0 | " " | whole(board[i,j],-5)), " |"))
|
||||
OD;
|
||||
print(new line)
|
||||
OD;
|
||||
print("+"); FOR j FROM 2 LWB board TO 2 UPB board DO print("------+") OD;
|
||||
print(new line)
|
||||
);
|
||||
|
||||
PROC score = (BOARD board) INT:
|
||||
(INT result := 0;
|
||||
traverse board(board, (CELL c)VOID: result +:= c);
|
||||
result);
|
||||
|
||||
PROC join = ([]STRING strings, STRING joiner) STRING:
|
||||
IF UPB strings > 0 THEN
|
||||
STRING result := strings[1];
|
||||
FOR i FROM 2 TO UPB strings DO result +:= joiner +:= strings[i] OD;
|
||||
result
|
||||
ELSE
|
||||
""
|
||||
FI;
|
||||
|
||||
BOARD board = LOC [side,side]INT;
|
||||
BOARD previous = LOC [side,side]INT;
|
||||
|
||||
traverse board(board, (CELL c)VOID: c := 0);
|
||||
|
||||
# start with two numbers #
|
||||
TO 2 DO add new number(board) OD;
|
||||
|
||||
# play! #
|
||||
STRING prompt := "enter one of [" + direction letters + "] (for " + join(direction descriptions, "/") + "): ";
|
||||
DO
|
||||
CHAR key;
|
||||
INT dir;
|
||||
print board(board);
|
||||
print(("score: ", whole(score(board),0), new line));
|
||||
WHILE
|
||||
print(prompt);
|
||||
read((key, new line));
|
||||
NOT char in string(key, dir, direction letters)
|
||||
DO SKIP OD;
|
||||
previous := board;
|
||||
move(board, dir);
|
||||
IF count blanks(board) = 0 THEN lose FI;
|
||||
traverse board(board, (CELL c)VOID: IF c = 2048 THEN win FI);
|
||||
IF previous = board THEN
|
||||
print(("try again!", new line))
|
||||
ELSE
|
||||
add new number(board)
|
||||
FI
|
||||
OD;
|
||||
|
||||
win: print board(board); print(("you win!", new line)) EXIT
|
||||
lose: print(("you lose!", new line))
|
||||
)
|
||||
891
Task/2048/ARM-Assembly/2048.arm
Normal file
891
Task/2048/ARM-Assembly/2048.arm
Normal file
|
|
@ -0,0 +1,891 @@
|
|||
/* ARM assembly Raspberry PI */
|
||||
/* program 2048.s */
|
||||
|
||||
/* REMARK 1 : this program use routines in a include file
|
||||
see task Include a file language arm assembly
|
||||
for the routine affichageMess conversion10
|
||||
see at end of this program the instruction include */
|
||||
/* for constantes see task include a file in arm assembly */
|
||||
/************************************/
|
||||
/* Constantes */
|
||||
/************************************/
|
||||
.include "../constantes.inc"
|
||||
.equ STDIN, 0 @ Linux input console
|
||||
.equ READ, 3 @ Linux syscall
|
||||
.equ SIZE, 4
|
||||
.equ TOTAL, 2048
|
||||
.equ BUFFERSIZE, 80
|
||||
|
||||
.equ IOCTL, 0x36 @ Linux syscall
|
||||
.equ SIGACTION, 0x43 @ Linux syscall
|
||||
.equ SYSPOLL, 0xA8 @ Linux syscall
|
||||
|
||||
.equ TCGETS, 0x5401
|
||||
.equ TCSETS, 0x5402
|
||||
.equ ICANON, 2
|
||||
.equ ECHO, 10
|
||||
.equ POLLIN, 1
|
||||
|
||||
.equ SIGINT, 2 @ Issued if the user sends an interrupt signal (Ctrl + C)
|
||||
.equ SIGQUIT, 3 @ Issued if the user sends a quit signal (Ctrl + D)
|
||||
.equ SIGTERM, 15 @ Software termination signal (sent by kill by default)
|
||||
.equ SIGTTOU, 22
|
||||
|
||||
/*******************************************/
|
||||
/* Structures */
|
||||
/********************************************/
|
||||
/* structure termios see doc linux*/
|
||||
.struct 0
|
||||
term_c_iflag: @ input modes
|
||||
.struct term_c_iflag + 4
|
||||
term_c_oflag: @ output modes
|
||||
.struct term_c_oflag + 4
|
||||
term_c_cflag: @ control modes
|
||||
.struct term_c_cflag + 4
|
||||
term_c_lflag: @ local modes
|
||||
.struct term_c_lflag + 4
|
||||
term_c_cc: @ special characters
|
||||
.struct term_c_cc + 20 @ see length if necessary
|
||||
term_fin:
|
||||
|
||||
/* structure sigaction see doc linux */
|
||||
.struct 0
|
||||
sa_handler:
|
||||
.struct sa_handler + 4
|
||||
sa_mask:
|
||||
.struct sa_mask + 4
|
||||
sa_flags:
|
||||
.struct sa_flags + 4
|
||||
sa_sigaction:
|
||||
.struct sa_sigaction + 4
|
||||
sa_fin:
|
||||
|
||||
/* structure poll see doc linux */
|
||||
.struct 0
|
||||
poll_fd: @ File Descriptor
|
||||
.struct poll_fd + 4
|
||||
poll_events: @ events mask
|
||||
.struct poll_events + 4
|
||||
poll_revents: @ events returned
|
||||
.struct poll_revents + 4
|
||||
poll_fin:
|
||||
/*********************************/
|
||||
/* Initialized data */
|
||||
/*********************************/
|
||||
.data
|
||||
szMessOK: .asciz "Bravo !! You win. \n"
|
||||
szMessNotOK: .asciz "You lost !! \n"
|
||||
szMessNewGame: .asciz "New game (y/n) ? \n"
|
||||
szMessErreur: .asciz "Error detected.\n"
|
||||
szCarriageReturn: .asciz "\n"
|
||||
//szMessMovePos: .asciz "\033[00;00H"
|
||||
szMess0: .asciz " "
|
||||
szMess2: .asciz " 2 "
|
||||
szMess4: .asciz " 4 "
|
||||
szMess8: .asciz " 8 "
|
||||
szMess16: .asciz " 16 "
|
||||
szMess32: .asciz " 32 "
|
||||
szMess64: .asciz " 64 "
|
||||
szMess128: .asciz " 128 "
|
||||
szMess256: .asciz " 256 "
|
||||
szMess512: .asciz " 512 "
|
||||
szMess1024: .asciz " 1024 "
|
||||
szMess2048: .asciz " 2048 "
|
||||
szClear1: .byte 0x1B
|
||||
.byte 'c' @ other console clear
|
||||
.byte 0
|
||||
|
||||
szLineH: .asciz "-----------------------------\n"
|
||||
szLineV: .asciz "|"
|
||||
szLineVT: .asciz "| | | | |\n"
|
||||
.align 4
|
||||
iGraine: .int 123456
|
||||
/*********************************/
|
||||
/* UnInitialized data */
|
||||
/*********************************/
|
||||
.bss
|
||||
.align 4
|
||||
sZoneConv: .skip 24
|
||||
sBuffer: .skip BUFFERSIZE
|
||||
iTbCase: .skip 4 * SIZE * SIZE
|
||||
iEnd: .skip 4 @ 0 loop 1 = end loop
|
||||
iTouche: .skip 4 @ value key pressed
|
||||
stOldtio: .skip term_fin @ old terminal state
|
||||
stCurtio: .skip term_fin @ current terminal state
|
||||
stSigAction: .skip sa_fin @ area signal structure
|
||||
stSigAction1: .skip sa_fin
|
||||
stPoll1: .skip poll_fin @ area poll structure
|
||||
stPoll2: .skip poll_fin
|
||||
/*********************************/
|
||||
/* code section */
|
||||
/*********************************/
|
||||
.text
|
||||
.global main
|
||||
main: @ entry of program
|
||||
|
||||
1: @ begin game loop
|
||||
ldr r0,iAdrszClear1
|
||||
bl affichageMess
|
||||
bl razTable
|
||||
2:
|
||||
bl addDigit
|
||||
cmp r0,#-1
|
||||
beq 5f @ end game
|
||||
bl displayGame
|
||||
3:
|
||||
bl readKey
|
||||
cmp r0,#-1
|
||||
beq 100f @ error or control-c
|
||||
bl keyMove
|
||||
cmp r0,#0
|
||||
beq 3b @ no change -> loop
|
||||
cmp r0,#2 @ last addition = 2048 ?
|
||||
beq 4f
|
||||
cmp r0,#-1 @ quit ?
|
||||
bne 2b @ loop
|
||||
|
||||
b 10f
|
||||
4: @ last addition = 2048
|
||||
ldr r0,iAdrszMessOK
|
||||
bl affichageMess
|
||||
b 10f
|
||||
5: @ display message no solution
|
||||
ldr r0,iAdrszMessNotOK
|
||||
bl affichageMess
|
||||
|
||||
10: @ display new game ?
|
||||
ldr r0,iAdrszCarriageReturn
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszMessNewGame
|
||||
bl affichageMess
|
||||
bl readKey
|
||||
ldr r0,iAdriTouche
|
||||
ldrb r0,[r0]
|
||||
cmp r0,#'y'
|
||||
beq 1b
|
||||
cmp r0,#'Y'
|
||||
beq 1b
|
||||
|
||||
100: @ standard end of the program
|
||||
mov r0, #0 @ return code
|
||||
mov r7, #EXIT @ request to exit program
|
||||
svc #0 @ perform the system call
|
||||
|
||||
iAdrszCarriageReturn: .int szCarriageReturn
|
||||
iAdrszMessNotOK: .int szMessNotOK
|
||||
iAdrszMessOK: .int szMessOK
|
||||
iAdrszMessNewGame: .int szMessNewGame
|
||||
iAdrsZoneConv: .int sZoneConv
|
||||
iAdrszClear1: .int szClear1
|
||||
/******************************************************************/
|
||||
/* raz table cases */
|
||||
/******************************************************************/
|
||||
razTable:
|
||||
push {r0-r2,lr} @ save registers
|
||||
ldr r1,iAdriTbCase
|
||||
mov r0,#0
|
||||
mov r2,#0
|
||||
1:
|
||||
str r0,[r1,r2,lsl #2]
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE * SIZE
|
||||
blt 1b
|
||||
100:
|
||||
pop {r0-r2,lr} @ restaur registers
|
||||
bx lr @return
|
||||
/******************************************************************/
|
||||
/* key move */
|
||||
/******************************************************************/
|
||||
/* r0 contains key value */
|
||||
keyMove:
|
||||
push {r1,lr} @ save registers
|
||||
cmp r0,#0x42 @ down arrow
|
||||
bne 1f
|
||||
bl moveDown
|
||||
b 100f
|
||||
1:
|
||||
cmp r0,#0x41 @ high arrow
|
||||
bne 2f
|
||||
bl moveUp
|
||||
b 100f
|
||||
2:
|
||||
cmp r0,#0x43 @ right arrow
|
||||
bne 3f
|
||||
bl moveRight
|
||||
b 100f
|
||||
3:
|
||||
cmp r0,#0x44 @ left arrow
|
||||
bne 4f
|
||||
bl moveLeft
|
||||
b 100f
|
||||
4:
|
||||
ldr r0,iAdriTouche
|
||||
ldrb r0,[r0]
|
||||
cmp r0,#'q' @ quit game
|
||||
bne 5f
|
||||
mov r0,#-1
|
||||
b 100f
|
||||
5:
|
||||
cmp r0,#'Q' @ quit game
|
||||
bne 100f
|
||||
mov r0,#-1
|
||||
b 100f
|
||||
|
||||
100:
|
||||
pop {r1,lr} @ restaur registers
|
||||
bx lr @return
|
||||
/******************************************************************/
|
||||
/* move left */
|
||||
/******************************************************************/
|
||||
/* r0 return -1 if ok */
|
||||
moveLeft:
|
||||
push {r1-r10,lr} @ save registers
|
||||
ldr r1,iAdriTbCase
|
||||
mov r0,#0 @ top move Ok
|
||||
mov r2,#0 @ line indice
|
||||
1:
|
||||
mov r6,#0 @ counter empty case
|
||||
mov r7,#0 @ first digit
|
||||
mov r10,#0 @ last digit to add
|
||||
mov r3,#0 @ column indice
|
||||
2:
|
||||
lsl r5,r2,#2 @ change this if size <> 4
|
||||
add r5,r5,r3 @ compute table indice
|
||||
ldr r4,[r1,r5,lsl #2]
|
||||
cmp r4,#0
|
||||
addeq r6,r6,#1 @ positions vides
|
||||
beq 5f
|
||||
cmp r6,#0
|
||||
beq 3f @ no empty left case
|
||||
mov r8,#0
|
||||
str r8,[r1,r5,lsl #2] @ raz digit
|
||||
sub r5,r5,r6
|
||||
str r4,[r1,r5,lsl #2] @ and store to left empty position
|
||||
mov r0,#1 @ move Ok
|
||||
//sub r6,r6,#1
|
||||
3:
|
||||
cmp r7,#0 @ first digit
|
||||
beq 4f
|
||||
cmp r10,r4 @ prec digit have to add
|
||||
beq 4f
|
||||
sub r8,r5,#1 @ prec digit
|
||||
ldr r9,[r1,r8,lsl #2]
|
||||
cmp r4,r9 @ equal ?
|
||||
bne 4f
|
||||
mov r10,r4 @ save digit
|
||||
add r4,r4,r9 @ yes -> add
|
||||
str r4,[r1,r8,lsl #2]
|
||||
cmp r4,#TOTAL
|
||||
moveq r0,#2
|
||||
beq 100f
|
||||
mov r4,#0
|
||||
str r4,[r1,r5,lsl #2]
|
||||
add r6,r6,#1 @ empty case + 1
|
||||
mov r0,#1 @ move Ok
|
||||
4:
|
||||
add r7,r7,#1 @ no first digit
|
||||
|
||||
5: @ and loop
|
||||
add r3,r3,#1
|
||||
cmp r3,#SIZE
|
||||
blt 2b
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE
|
||||
blt 1b
|
||||
100:
|
||||
pop {r1-r12,lr}
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* move right */
|
||||
/******************************************************************/
|
||||
/* r0 return -1 if ok */
|
||||
moveRight:
|
||||
push {r1-r5,lr} @ save registers
|
||||
ldr r1,iAdriTbCase
|
||||
mov r0,#0
|
||||
mov r2,#0
|
||||
1:
|
||||
mov r6,#0
|
||||
mov r7,#0
|
||||
mov r10,#0
|
||||
mov r3,#SIZE-1
|
||||
2:
|
||||
lsl r5,r2,#2 @ change this if size <> 4
|
||||
add r5,r5,r3
|
||||
ldr r4,[r1,r5,lsl #2]
|
||||
cmp r4,#0
|
||||
addeq r6,r6,#1 @ positions vides
|
||||
beq 5f
|
||||
|
||||
cmp r6,#0
|
||||
beq 3f @ no empty right case
|
||||
mov r0,#0
|
||||
str r0,[r1,r5,lsl #2] @ raz digit
|
||||
add r5,r5,r6
|
||||
str r4,[r1,r5,lsl #2] @ and store to right empty position
|
||||
mov r0,#1
|
||||
3:
|
||||
cmp r7,#0 @ first digit
|
||||
beq 4f
|
||||
add r8,r5,#1 @ next digit
|
||||
ldr r9,[r1,r8,lsl #2]
|
||||
cmp r4,r9 @ equal ?
|
||||
bne 4f
|
||||
cmp r10,r4
|
||||
beq 4f
|
||||
mov r10,r4
|
||||
add r4,r4,r9 @ yes -> add
|
||||
str r4,[r1,r8,lsl #2]
|
||||
cmp r4,#TOTAL
|
||||
moveq r0,#2
|
||||
beq 100f
|
||||
mov r4,#0
|
||||
str r4,[r1,r5,lsl #2]
|
||||
add r6,r6,#1 @ empty case + 1
|
||||
mov r0,#1
|
||||
4:
|
||||
add r7,r7,#1 @ no first digit
|
||||
|
||||
5: @ and loop
|
||||
sub r3,r3,#1
|
||||
cmp r3,#0
|
||||
bge 2b
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE
|
||||
blt 1b
|
||||
|
||||
100:
|
||||
pop {r1-r5,lr}
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* move down */
|
||||
/******************************************************************/
|
||||
/* r0 return -1 if ok */
|
||||
moveDown:
|
||||
push {r1-r5,lr} @ save registers
|
||||
ldr r1,iAdriTbCase
|
||||
mov r0,#0
|
||||
mov r3,#0
|
||||
1:
|
||||
mov r6,#0
|
||||
mov r7,#0
|
||||
mov r10,#0
|
||||
mov r2,#SIZE-1
|
||||
2:
|
||||
lsl r5,r2,#2 @ change this if size <> 4
|
||||
add r5,r5,r3
|
||||
ldr r4,[r1,r5,lsl #2]
|
||||
cmp r4,#0
|
||||
addeq r6,r6,#1 @ positions vides
|
||||
beq 5f
|
||||
cmp r6,#0
|
||||
beq 3f @ no empty right case
|
||||
mov r0,#0
|
||||
str r0,[r1,r5,lsl #2] @ raz digit
|
||||
lsl r0,r6,#2
|
||||
add r5,r5,r0
|
||||
str r4,[r1,r5,lsl #2] @ and store to right empty position
|
||||
mov r0,#1
|
||||
3:
|
||||
cmp r7,#0 @ first digit
|
||||
beq 4f
|
||||
add r8,r5,#SIZE @ down digit
|
||||
ldr r9,[r1,r8,lsl #2]
|
||||
cmp r4,r9 @ equal ?
|
||||
bne 4f
|
||||
cmp r10,r4
|
||||
beq 4f
|
||||
mov r10,r4
|
||||
add r4,r4,r9 @ yes -> add
|
||||
str r4,[r1,r8,lsl #2]
|
||||
cmp r4,#TOTAL
|
||||
moveq r0,#2
|
||||
beq 100f
|
||||
mov r4,#0
|
||||
str r4,[r1,r5,lsl #2]
|
||||
add r6,r6,#1 @ empty case + 1
|
||||
mov r0,#1
|
||||
4:
|
||||
add r7,r7,#1 @ no first digit
|
||||
|
||||
5: @ and loop
|
||||
sub r2,r2,#1
|
||||
cmp r2,#0
|
||||
bge 2b
|
||||
add r3,r3,#1
|
||||
cmp r3,#SIZE
|
||||
blt 1b
|
||||
|
||||
100:
|
||||
pop {r1-r5,lr}
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* move up */
|
||||
/******************************************************************/
|
||||
/* r0 return -1 if ok */
|
||||
moveUp:
|
||||
push {r1-r5,lr} @ save registers
|
||||
ldr r1,iAdriTbCase
|
||||
mov r0,#0
|
||||
mov r3,#0
|
||||
1:
|
||||
mov r6,#0
|
||||
mov r7,#0
|
||||
mov r10,#0
|
||||
mov r2,#0
|
||||
2:
|
||||
lsl r5,r2,#2 @ change this if size <> 4
|
||||
add r5,r5,r3
|
||||
ldr r4,[r1,r5,lsl #2]
|
||||
cmp r4,#0
|
||||
addeq r6,r6,#1 @ positions vides
|
||||
beq 5f
|
||||
cmp r6,#0
|
||||
beq 3f @ no empty right case
|
||||
mov r0,#0
|
||||
str r0,[r1,r5,lsl #2] @ raz digit
|
||||
lsl r0,r6,#2
|
||||
sub r5,r5,r0
|
||||
str r4,[r1,r5,lsl #2] @ and store to right empty position
|
||||
mov r0,#1
|
||||
3:
|
||||
cmp r7,#0 @ first digit
|
||||
beq 4f
|
||||
sub r8,r5,#SIZE @ up digit
|
||||
ldr r9,[r1,r8,lsl #2]
|
||||
cmp r4,r9 @ equal ?
|
||||
bne 4f
|
||||
cmp r10,r4
|
||||
beq 4f
|
||||
mov r10,r4
|
||||
add r4,r4,r9 @ yes -> add
|
||||
str r4,[r1,r8,lsl #2]
|
||||
cmp r4,#TOTAL
|
||||
moveq r0,#2
|
||||
beq 100f
|
||||
mov r4,#0
|
||||
str r4,[r1,r5,lsl #2]
|
||||
add r6,r6,#1 @ empty case + 1
|
||||
mov r0,#1
|
||||
4:
|
||||
add r7,r7,#1 @ no first digit
|
||||
|
||||
5: @ and loop
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE
|
||||
blt 2b
|
||||
add r3,r3,#1
|
||||
cmp r3,#SIZE
|
||||
blt 1b
|
||||
|
||||
100:
|
||||
pop {r1-r5,lr}
|
||||
bx lr @ return
|
||||
/******************************************************************/
|
||||
/* add new digit on game */
|
||||
/******************************************************************/
|
||||
/* r0 return -1 if ok */
|
||||
addDigit:
|
||||
push {r1-r5,lr} @ save registers
|
||||
sub sp,#4 * SIZE*SIZE
|
||||
mov fp,sp
|
||||
|
||||
mov r0,#100
|
||||
bl genereraleas
|
||||
cmp r0,#10
|
||||
movlt r5,#4
|
||||
movge r5,#2
|
||||
ldr r1,iAdriTbCase
|
||||
mov r3,#0
|
||||
mov r4,#0
|
||||
1:
|
||||
ldr r2,[r1,r3,lsl #2]
|
||||
cmp r2,#0
|
||||
bne 2f
|
||||
str r3,[fp,r4,lsl #2]
|
||||
add r4,r4,#1
|
||||
2:
|
||||
add r3,r3,#1
|
||||
cmp r3,#SIZE*SIZE
|
||||
blt 1b
|
||||
cmp r4,#0 @ no empty case
|
||||
moveq r0,#-1
|
||||
beq 100f
|
||||
cmp r4,#1
|
||||
bne 3f
|
||||
ldr r2,[fp] @ one case
|
||||
str r5,[r1,r2,lsl #2]
|
||||
mov r0,#0
|
||||
b 100f
|
||||
3: @ multiple case
|
||||
sub r0,r4,#1
|
||||
bl genereraleas
|
||||
ldr r2,[fp,r0,lsl #2]
|
||||
str r5,[r1,r2,lsl #2]
|
||||
mov r0,#0
|
||||
|
||||
100:
|
||||
add sp,#4* (SIZE*SIZE) @ stack alignement
|
||||
pop {r1-r5,lr}
|
||||
bx lr @ return
|
||||
iAdriTbCase: .int iTbCase
|
||||
/******************************************************************/
|
||||
/* display game */
|
||||
/******************************************************************/
|
||||
displayGame:
|
||||
push {r1-r3,lr} @ save registers
|
||||
ldr r0,iAdrszClear1
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineH
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
ldr r1,iAdriTbCase
|
||||
mov r2,#0
|
||||
1:
|
||||
ldr r0,[r1,r2,lsl #2]
|
||||
bl digitString
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE
|
||||
blt 1b
|
||||
ldr r0,iAdrszCarriageReturn
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineH
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
2:
|
||||
ldr r0,[r1,r2,lsl #2]
|
||||
bl digitString
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE*2
|
||||
blt 2b
|
||||
ldr r0,iAdrszCarriageReturn
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineH
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
3:
|
||||
ldr r0,[r1,r2,lsl #2]
|
||||
bl digitString
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE*3
|
||||
blt 3b
|
||||
ldr r0,iAdrszCarriageReturn
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineH
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
4:
|
||||
ldr r0,[r1,r2,lsl #2]
|
||||
bl digitString
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineV
|
||||
bl affichageMess
|
||||
add r2,r2,#1
|
||||
cmp r2,#SIZE*4
|
||||
blt 4b
|
||||
ldr r0,iAdrszCarriageReturn
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineVT
|
||||
bl affichageMess
|
||||
ldr r0,iAdrszLineH
|
||||
bl affichageMess
|
||||
|
||||
100:
|
||||
pop {r1-r3,lr}
|
||||
bx lr @ return
|
||||
iAdrszLineH: .int szLineH
|
||||
iAdrszLineV: .int szLineV
|
||||
iAdrszLineVT: .int szLineVT
|
||||
//iAdrszMessMovePos: .int szMessMovePos
|
||||
/******************************************************************/
|
||||
/* digits string */
|
||||
/******************************************************************/
|
||||
/* r0 contains number */
|
||||
/* r0 return address string */
|
||||
digitString:
|
||||
push {r1,lr} @ save registers
|
||||
cmp r0,#0
|
||||
bne 1f
|
||||
ldr r0,iAdrszMess0
|
||||
b 100f
|
||||
1:
|
||||
cmp r0,#2
|
||||
bne 2f
|
||||
ldr r0,iAdrszMess2
|
||||
b 100f
|
||||
2:
|
||||
cmp r0,#4
|
||||
bne 3f
|
||||
ldr r0,iAdrszMess4
|
||||
b 100f
|
||||
3:
|
||||
cmp r0,#8
|
||||
bne 4f
|
||||
ldr r0,iAdrszMess8
|
||||
b 100f
|
||||
4:
|
||||
cmp r0,#16
|
||||
bne 5f
|
||||
ldr r0,iAdrszMess16
|
||||
b 100f
|
||||
5:
|
||||
cmp r0,#32
|
||||
bne 6f
|
||||
ldr r0,iAdrszMess32
|
||||
b 100f
|
||||
6:
|
||||
cmp r0,#64
|
||||
bne 7f
|
||||
ldr r0,iAdrszMess64
|
||||
b 100f
|
||||
7:
|
||||
cmp r0,#128
|
||||
bne 8f
|
||||
ldr r0,iAdrszMess128
|
||||
b 100f
|
||||
8:
|
||||
cmp r0,#256
|
||||
bne 9f
|
||||
ldr r0,iAdrszMess256
|
||||
b 100f
|
||||
9:
|
||||
cmp r0,#512
|
||||
bne 10f
|
||||
ldr r0,iAdrszMess512
|
||||
b 100f
|
||||
10:
|
||||
cmp r0,#1024
|
||||
bne 11f
|
||||
ldr r0,iAdrszMess1024
|
||||
b 100f
|
||||
11:
|
||||
cmp r0,#2048
|
||||
bne 12f
|
||||
ldr r0,iAdrszMess2048
|
||||
b 100f
|
||||
12:
|
||||
ldr r1,iAdrszMessErreur @ error message
|
||||
bl displayError
|
||||
100:
|
||||
pop {r1,lr}
|
||||
bx lr @ return
|
||||
iAdrszMess0: .int szMess0
|
||||
iAdrszMess2: .int szMess2
|
||||
iAdrszMess4: .int szMess4
|
||||
iAdrszMess8: .int szMess8
|
||||
iAdrszMess16: .int szMess16
|
||||
iAdrszMess32: .int szMess32
|
||||
iAdrszMess64: .int szMess64
|
||||
iAdrszMess128: .int szMess128
|
||||
iAdrszMess256: .int szMess256
|
||||
iAdrszMess512: .int szMess512
|
||||
iAdrszMess1024: .int szMess1024
|
||||
iAdrszMess2048: .int szMess2048
|
||||
|
||||
//iAdrsBuffer: .int sBuffer
|
||||
/***************************************************/
|
||||
/* Generation random number */
|
||||
/***************************************************/
|
||||
/* r0 contains limit */
|
||||
genereraleas:
|
||||
push {r1-r4,lr} @ save registers
|
||||
ldr r4,iAdriGraine
|
||||
ldr r2,[r4]
|
||||
ldr r3,iNbDep1
|
||||
mul r2,r3,r2
|
||||
ldr r3,iNbDep2
|
||||
add r2,r2,r3
|
||||
str r2,[r4] @ maj de la graine pour l appel suivant
|
||||
cmp r0,#0
|
||||
beq 100f
|
||||
add r1,r0,#1 @ divisor
|
||||
mov r0,r2 @ dividende
|
||||
bl division
|
||||
mov r0,r3 @ résult = remainder
|
||||
|
||||
100: @ end function
|
||||
pop {r1-r4,lr} @ restaur registers
|
||||
bx lr @ return
|
||||
/*****************************************************/
|
||||
iAdriGraine: .int iGraine
|
||||
iNbDep1: .int 0x343FD
|
||||
iNbDep2: .int 0x269EC3
|
||||
/***************************************************/
|
||||
/* read touch */
|
||||
/***************************************************/
|
||||
readKey:
|
||||
push {r1-r7,lr}
|
||||
mov r5,#0
|
||||
ldr r1,iAdriTouche @ buffer address
|
||||
str r5,[r1] @ raz 4 bytes iTouche
|
||||
/* read terminal state */
|
||||
mov r0,#STDIN @ input console
|
||||
mov r1,#TCGETS
|
||||
ldr r2,iAdrstOldtio
|
||||
mov r7, #IOCTL @ call system Linux
|
||||
svc #0
|
||||
cmp r0,#0 @ error ?
|
||||
beq 1f
|
||||
ldr r1,iAdrszMessErreur @ error message
|
||||
bl displayError
|
||||
mov r0,#-1
|
||||
b 100f
|
||||
1:
|
||||
adr r0,sighandler @ adresse routine traitement signal
|
||||
ldr r1,iAdrstSigAction @ adresse structure sigaction
|
||||
str r0,[r1,#sa_handler] @ maj handler
|
||||
mov r0,#SIGINT @ signal type
|
||||
ldr r1,iAdrstSigAction
|
||||
mov r2,#0 @ NULL
|
||||
mov r7, #SIGACTION @ call system
|
||||
svc #0
|
||||
cmp r0,#0 @ error ?
|
||||
bne 97f
|
||||
mov r0,#SIGQUIT
|
||||
ldr r1,iAdrstSigAction
|
||||
mov r2,#0 @ NULL
|
||||
mov r7, #SIGACTION @ call system
|
||||
svc #0
|
||||
cmp r0,#0 @ error ?
|
||||
bne 97f
|
||||
mov r0,#SIGTERM
|
||||
ldr r1,iAdrstSigAction
|
||||
mov r2,#0 @ NULL
|
||||
mov r7, #SIGACTION @ appel systeme
|
||||
svc #0
|
||||
cmp r0,#0
|
||||
bne 97f
|
||||
@
|
||||
adr r0,iSIG_IGN @ address signal ignore function
|
||||
ldr r1,iAdrstSigAction1
|
||||
str r0,[r1,#sa_handler]
|
||||
mov r0,#SIGTTOU @invalidate other process signal
|
||||
ldr r1,iAdrstSigAction1
|
||||
mov r2,#0 @ NULL
|
||||
mov r7,#SIGACTION @ call system
|
||||
svc #0
|
||||
cmp r0,#0
|
||||
bne 97f
|
||||
@
|
||||
/* read terminal current state */
|
||||
mov r0,#STDIN
|
||||
mov r1,#TCGETS
|
||||
ldr r2,iAdrstCurtio @ address current termio
|
||||
mov r7,#IOCTL @ call systeme
|
||||
svc #0
|
||||
cmp r0,#0 @ error ?
|
||||
bne 97f
|
||||
mov r2,#ICANON | ECHO @ no key pressed echo on display
|
||||
mvn r2,r2 @ and one key
|
||||
ldr r1,iAdrstCurtio
|
||||
ldr r3,[r1,#term_c_lflag]
|
||||
and r3,r2 @ add flags
|
||||
str r3,[r1,#term_c_lflag] @ and store
|
||||
mov r0,#STDIN @ maj terminal current state
|
||||
mov r1,#TCSETS
|
||||
ldr r2,iAdrstCurtio
|
||||
mov r7, #IOCTL @ call system
|
||||
svc #0
|
||||
cmp r0,#0
|
||||
bne 97f
|
||||
@
|
||||
2: @ loop waiting key
|
||||
ldr r0,iAdriEnd @ if signal ctrl-c -> end
|
||||
ldr r0,[r0]
|
||||
cmp r0,#0
|
||||
movne r5,#-1
|
||||
bne 98f
|
||||
ldr r0,iAdrstPoll1 @ address structure poll
|
||||
mov r1,#STDIN
|
||||
str r1,[r0,#poll_fd] @ maj FD
|
||||
mov r1,#POLLIN @ action code
|
||||
str r1,[r0,#poll_events]
|
||||
mov r1,#1 @ items number structure poll
|
||||
mov r2,#0 @ timeout = 0
|
||||
mov r7,#SYSPOLL @ call system POLL
|
||||
svc #0
|
||||
cmp r0,#0 @ key pressed ?
|
||||
ble 2b @ no key pressed -> loop
|
||||
@ read key
|
||||
mov r0,#STDIN @ File Descriptor
|
||||
ldr r1,iAdriTouche @ buffer address
|
||||
mov r2,#BUFFERSIZE @ buffer size
|
||||
mov r7,#READ @ read key
|
||||
svc #0
|
||||
cmp r0,#0 @ error ?
|
||||
bgt 98f
|
||||
|
||||
97: @ error detected
|
||||
ldr r1,iAdrszMessErreur @ error message
|
||||
bl displayError
|
||||
mov r5,#-1
|
||||
98: @ end then restaur begin state terminal
|
||||
mov r0,#STDIN
|
||||
mov r1,#TCSETS
|
||||
ldr r2,iAdrstOldtio
|
||||
mov r7,#IOCTL @ call system
|
||||
svc #0
|
||||
cmp r0,#0
|
||||
beq 99f @ restaur ok
|
||||
ldr r1,iAdrszMessErreur @ error message
|
||||
bl displayError
|
||||
mov r0,#-1
|
||||
b 100f
|
||||
99:
|
||||
cmp r5,#0 @ no error or control-c ?
|
||||
ldreq r2,iAdriTouche @ key address
|
||||
ldreqb r0,[r2,#2] @ return key byte
|
||||
movne r0,r5 @ or error
|
||||
100:
|
||||
pop {r1-r7, lr}
|
||||
bx lr
|
||||
iSIG_IGN: .int 1
|
||||
iAdriEnd: .int iEnd
|
||||
iAdrstPoll1: .int stPoll1
|
||||
iAdriTouche: .int iTouche
|
||||
iAdrstOldtio: .int stOldtio
|
||||
iAdrstCurtio: .int stCurtio
|
||||
iAdrstSigAction: .int stSigAction
|
||||
iAdrstSigAction1: .int stSigAction1
|
||||
iAdrszMessErreur : .int szMessErreur
|
||||
/******************************************************************/
|
||||
/* traitement du signal */
|
||||
/******************************************************************/
|
||||
sighandler:
|
||||
push {r0,r1}
|
||||
ldr r0,iAdriEnd
|
||||
mov r1,#1 @ maj zone end
|
||||
str r1,[r0]
|
||||
pop {r0,r1}
|
||||
bx lr
|
||||
/***************************************************/
|
||||
/* ROUTINES INCLUDE */
|
||||
/***************************************************/
|
||||
.include "../affichage.inc"
|
||||
177
Task/2048/Ada/2048.ada
Normal file
177
Task/2048/Ada/2048.ada
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
with System.Random_Numbers;
|
||||
procedure Play_2048 is
|
||||
-- ----- Keyboard management
|
||||
type t_Keystroke is (Up, Down, Right, Left, Quit, Restart, Invalid);
|
||||
-- Redefining this standard procedure as function to allow Get_Keystroke as an expression function
|
||||
function Get_Immediate return Character is
|
||||
begin
|
||||
return Answer : Character do Ada.Text_IO.Get_Immediate(Answer);
|
||||
end return;
|
||||
end Get_Immediate;
|
||||
Arrow_Prefix : constant Character := Character'Val(224); -- works for windows
|
||||
function Get_Keystroke return t_Keystroke is
|
||||
(case Get_Immediate is
|
||||
when 'Q' | 'q' => Quit,
|
||||
when 'R' | 'r' => Restart,
|
||||
when 'W' | 'w' => Left,
|
||||
when 'A' | 'a' => Up,
|
||||
when 'S' | 's' => Down,
|
||||
when 'D' | 'd' => Right,
|
||||
-- Windows terminal
|
||||
when Arrow_Prefix => (case Character'Pos(Get_Immediate) is
|
||||
when 72 => Up,
|
||||
when 75 => Left,
|
||||
when 77 => Right,
|
||||
when 80 => Down,
|
||||
when others => Invalid),
|
||||
-- Unix escape sequences
|
||||
when ASCII.ESC => (case Get_Immediate is
|
||||
when '[' => (case Get_Immediate is
|
||||
when 'A' => Up,
|
||||
when 'B' => Down,
|
||||
when 'C' => Right,
|
||||
when 'D' => Left,
|
||||
when others => Invalid),
|
||||
when others => Invalid),
|
||||
when others => Invalid);
|
||||
|
||||
-- ----- Game data
|
||||
function Random_Int is new System.Random_Numbers.Random_Discrete(Integer);
|
||||
type t_List is array (Positive range <>) of Natural;
|
||||
subtype t_Row is t_List (1..4);
|
||||
type t_Board is array (1..4) of t_Row;
|
||||
Board : t_Board;
|
||||
New_Board : t_Board;
|
||||
Blanks : Natural;
|
||||
Score : Natural;
|
||||
Generator : System.Random_Numbers.Generator;
|
||||
|
||||
-- ----- Displaying the board
|
||||
procedure Display_Board is
|
||||
Horizontal_Rule : constant String := "+----+----+----+----+";
|
||||
function Center (Value : in String) return String is
|
||||
((1..(2-(Value'Length-1)/2) => ' ') & -- Add leading spaces
|
||||
Value(Value'First+1..Value'Last) & -- Trim the leading space of the raw number image
|
||||
(1..(2-Value'Length/2) => ' ')); -- Add trailing spaces
|
||||
begin
|
||||
Put_Line (Horizontal_Rule);
|
||||
for Row of Board loop
|
||||
for Cell of Row loop
|
||||
Put('|' & (if Cell = 0 then " " else Center(Cell'Img)));
|
||||
end loop;
|
||||
Put_Line("|");
|
||||
Put_Line (Horizontal_Rule);
|
||||
end loop;
|
||||
Put_Line("Score =" & Score'Img);
|
||||
end Display_Board;
|
||||
|
||||
-- ----- Game mechanics
|
||||
procedure Add_Block is
|
||||
Block_Offset : Positive := Random_Int(Generator, 1, Blanks);
|
||||
begin
|
||||
Blanks := Blanks-1;
|
||||
for Row of Board loop
|
||||
for Cell of Row loop
|
||||
if Cell = 0 then
|
||||
if Block_Offset = 1 then
|
||||
Cell := (if Random_Int(Generator,1,10) = 1 then 4 else 2);
|
||||
return;
|
||||
else
|
||||
Block_Offset := Block_Offset-1;
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
end loop;
|
||||
end Add_Block;
|
||||
|
||||
procedure Reset_Game is
|
||||
begin
|
||||
Board := (others => (others => 0));
|
||||
Blanks := 16;
|
||||
Score := 0;
|
||||
Add_Block;
|
||||
Add_Block;
|
||||
end Reset_Game;
|
||||
|
||||
-- Moving and merging will always be performed leftward, hence the following transforms
|
||||
function HFlip (What : in t_Row) return t_Row is
|
||||
(What(4),What(3),What(2),What(1));
|
||||
function VFlip (What : in t_Board) return t_Board is
|
||||
(HFlip(What(1)),HFlip(What(2)),HFlip(What(3)),HFlip(What(4)));
|
||||
function Transpose (What : in t_Board) return t_Board is
|
||||
begin
|
||||
return Answer : t_Board do
|
||||
for Row in t_Board'Range loop
|
||||
for Column in t_Row'Range loop
|
||||
Answer(Column)(Row) := What(Row)(Column);
|
||||
end loop;
|
||||
end loop;
|
||||
end return;
|
||||
end Transpose;
|
||||
|
||||
-- For moving/merging, recursive expression functions will be used, but they
|
||||
-- can't contain statements, hence the following sub-function used by Merge
|
||||
function Add_Blank (Delta_Score : in Natural) return t_List is
|
||||
begin
|
||||
Blanks := Blanks+1;
|
||||
Score := Score+Delta_Score;
|
||||
return (1 => 0);
|
||||
end Add_Blank;
|
||||
|
||||
function Move_Row (What : in t_List) return t_List is
|
||||
(if What'Length = 1 then What
|
||||
elsif What(What'First) = 0
|
||||
then Move_Row(What(What'First+1..What'Last)) & (1 => 0)
|
||||
else (1 => What(What'First)) & Move_Row(What(What'First+1..What'Last)));
|
||||
|
||||
function Merge (What : in t_List) return t_List is
|
||||
(if What'Length <= 1 or else What(What'First) = 0 then What
|
||||
elsif What(What'First) = What(What'First+1)
|
||||
then (1 => 2*What(What'First)) & Merge(What(What'First+2..What'Last)) & Add_Blank(What(What'First))
|
||||
else (1 => What(What'First)) & Merge(What(What'First+1..What'Last)));
|
||||
|
||||
function Move (What : in t_Board) return t_Board is
|
||||
(Merge(Move_Row(What(1))),Merge(Move_Row(What(2))),Merge(Move_Row(What(3))),Merge(Move_Row(What(4))));
|
||||
|
||||
begin
|
||||
System.Random_Numbers.Reset(Generator);
|
||||
|
||||
Main_Loop: loop
|
||||
Reset_Game;
|
||||
Game_Loop: loop
|
||||
Display_Board;
|
||||
case Get_Keystroke is
|
||||
when Restart => exit Game_Loop;
|
||||
when Quit => exit Main_Loop;
|
||||
when Left => New_Board := Move(Board);
|
||||
when Right => New_Board := VFlip(Move(VFlip(Board)));
|
||||
when Up => New_Board := Transpose(Move(Transpose(Board)));
|
||||
when Down => New_Board := Transpose(VFlip(Move(VFlip(Transpose(Board)))));
|
||||
when others => null;
|
||||
end case;
|
||||
|
||||
if New_Board = Board then
|
||||
Put_Line ("Invalid move...");
|
||||
elsif (for some Row of New_Board => (for some Cell of Row => Cell = 2048)) then
|
||||
Display_Board;
|
||||
Put_Line ("Win !");
|
||||
exit Main_Loop;
|
||||
else
|
||||
Board := New_Board;
|
||||
Add_Block; -- OK since the board has changed
|
||||
if Blanks = 0
|
||||
and then (for all Row in 1..4 =>
|
||||
(for all Column in 1..3 =>
|
||||
(Board(Row)(Column) /= Board(Row)(Column+1))))
|
||||
and then (for all Row in 1..3 =>
|
||||
(for all Column in 1..4 =>
|
||||
(Board(Row)(Column) /= Board(Row+1)(Column)))) then
|
||||
Display_Board;
|
||||
Put_Line ("Lost !");
|
||||
exit Main_Loop;
|
||||
end if;
|
||||
end if;
|
||||
end loop Game_Loop;
|
||||
end loop Main_Loop;
|
||||
end Play_2048;
|
||||
236
Task/2048/Amazing-Hopper/2048-1.hopper
Normal file
236
Task/2048/Amazing-Hopper/2048-1.hopper
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#context-free select Position of aleatory tail
|
||||
#context-free show Table
|
||||
#context-free chek Winner or Game Over
|
||||
#context-free print Table structure
|
||||
#proto MovingRightDown(_X_)
|
||||
#proto MovingLeftUp(_X_)
|
||||
#proto checkPointLeftUp(_X_)
|
||||
#proto checkPointRightDown(_X_)
|
||||
#proto checkMoveRightDown(_X_)
|
||||
#proto checkMoveLeftUp(_X_)
|
||||
#define KUP 5
|
||||
#define KDOWN 24
|
||||
#define KLEFT 19
|
||||
#define KRIGHT 4
|
||||
#define KESCAPE 27
|
||||
#define MOVEHORZ 1
|
||||
#define MOVEVERT 0
|
||||
#define equaltables(_X_,_Y_) _I_=1,\
|
||||
__LOOP_ROW__:,\
|
||||
_J_=1,\
|
||||
__LOOP_COL__:,\
|
||||
[_I_,_J_]get(_X_),get(_Y_),neq? do{{0},jmp(__OUT__LOOP__)},\
|
||||
++_J_,{4,_J_}jle(__LOOP_COL__),\
|
||||
++_I_,{4,_I_}jle(__LOOP_ROW__),\
|
||||
{1},__OUT__LOOP__:,clear mark
|
||||
#include <hopper.h>
|
||||
|
||||
main:
|
||||
.ctrl c
|
||||
contador de movimientos=0
|
||||
score=0
|
||||
table=0,{4,4}zeros array(table) // create table
|
||||
oldTable=0, show Structure=1
|
||||
/* define initial positions */
|
||||
{""}tok sep
|
||||
select Position of aleatory tail
|
||||
select Position of aleatory tail
|
||||
home
|
||||
hide cursor
|
||||
show Table
|
||||
c=0, go=1,swFin=1
|
||||
|
||||
/* game! */
|
||||
__PLAY_GAME__:
|
||||
|
||||
if key pressed?
|
||||
lastkey(c)
|
||||
oldTable = table
|
||||
switch(c)
|
||||
case(KRIGHT) :: do{ _check Move Right Down(MOVEHORZ), exit }
|
||||
case(KDOWN) :: do{ _check Move Right Down(MOVEVERT), exit }
|
||||
case(KLEFT) :: do{ _check Move Left Up(MOVEHORZ), exit }
|
||||
case(KUP) :: do{ _check Move Left Up(MOVEVERT), exit }
|
||||
case(KESCAPE):: do{ go=0,swFin=0 }
|
||||
end switch
|
||||
kbfree
|
||||
chek Winner or Game Over
|
||||
{go}do{
|
||||
if ( not( equal tables(oldTable, table) ) )
|
||||
select Position of aleatory tail
|
||||
++contador de movimientos
|
||||
end if
|
||||
show Table
|
||||
}
|
||||
end if
|
||||
{go},jt(__PLAY_GAME__)
|
||||
|
||||
if ( {swFin} )
|
||||
{" \LG","YOU WIN!!!\OFF"}
|
||||
else
|
||||
{" \LR","GAME OVER\OFF"}
|
||||
end if
|
||||
println
|
||||
show cursor
|
||||
exit(0)
|
||||
|
||||
.locals
|
||||
Moving Right Down(tmpTab)
|
||||
{tmpTab} compact,ht=0,cpy(ht), length,{4}sub,sizet=0,mov(sizet)
|
||||
clear(tmpTab),{sizet}zerosarray(tmpTab)
|
||||
{ht,tmpTab}array(CONCAT)
|
||||
{tmpTab}
|
||||
back
|
||||
Moving Left Up(tmpTab)
|
||||
{tmpTab} compact,clear(tmpTab),cpy(tmpTab), length,{4}sub,sizet=0,mov(sizet)
|
||||
{sizet}zero?,not,do{ ht=0,{sizet}zerosarray(ht)
|
||||
{ht,tmpTab}array(CONCAT) }
|
||||
{tmpTab}
|
||||
back
|
||||
check Point Right Down(tmpTab)
|
||||
v1=0,v2=0,tScore=0,totScore=0
|
||||
for(k=4,{k}gthan(1),--k)
|
||||
[k]get(tmpTab),mov(v1)
|
||||
[{k}minus(1)]get(tmpTab),mov(v2)
|
||||
if( {v1} eqto (v2) )
|
||||
{v1,v2}add,cpy(tScore),[k]put(tmpTab),[{k}minus(1)]{0}put(tmpTab)
|
||||
{tScore}plus(totScore),mov(totScore)
|
||||
end if
|
||||
next
|
||||
{tmpTab,totScore}
|
||||
back
|
||||
check Move Right Down (_DIRECTION_)
|
||||
tmpTab=0
|
||||
for(i=1,{i}lethan(4),++i)
|
||||
if ( {_DIRECTION_} ) // rows or cols??
|
||||
[i,1:4] // rows!
|
||||
else
|
||||
[1:4,i] // cols!
|
||||
end if
|
||||
get(table), mov(tmpTab)
|
||||
|
||||
if( {tmpTab}stats(SUMMATORY) ) // exist numbers in the row??
|
||||
clear mark
|
||||
_Moving Right Down(tmpTab),mov(tmpTab) // move its!
|
||||
clear mark
|
||||
_check Point Right Down(tmpTab),plus(score),mov(score) // check score...
|
||||
mov(tmpTab)
|
||||
_Moving Right Down(tmpTab),mov(tmpTab) // move remanents!
|
||||
if( {_DIRECTION_} )
|
||||
[i,1:4]
|
||||
else
|
||||
[1:4,i]
|
||||
end if
|
||||
{tmpTab}, put(table)
|
||||
end if
|
||||
next
|
||||
clear mark.
|
||||
back
|
||||
|
||||
check Point Left Up(tmpTab)
|
||||
v1=0,v2=0,tScore=0,totScore=0
|
||||
for(k=1,{k}lthan(4),++k)
|
||||
[k]get(tmpTab),mov(v1)
|
||||
[{k}plus(1)]get(tmpTab),mov(v2)
|
||||
if( {v1} eqto (v2) )
|
||||
{v1,v2}add,cpy(tScore),[k]put(tmpTab),[{k}plus(1)]{0}put(tmpTab)
|
||||
{tScore}plus(totScore),mov(totScore)
|
||||
end if
|
||||
next
|
||||
{tmpTab,totScore}
|
||||
back
|
||||
|
||||
check Move Left Up(_DIRECTION_)
|
||||
tmpTab=0
|
||||
for(i=1,{i}lethan(4),++i)
|
||||
if( {_DIRECTION_} )
|
||||
[i,1:4]
|
||||
else
|
||||
[1:4,i]
|
||||
end if
|
||||
get(table),mov(tmpTab)
|
||||
if( {tmpTab}stats(SUMMATORY) ) // exist numbers in the row??
|
||||
clear mark
|
||||
_Moving Left Up(tmpTab),mov(tmpTab) // move its!
|
||||
clear mark
|
||||
_check Point Left Up(tmpTab),plus(score),mov(score) // check score...
|
||||
mov(tmpTab)
|
||||
_Moving Left Up(tmpTab),mov(tmpTab) // move remanents!
|
||||
if( {_DIRECTION_} )
|
||||
[i,1:4]
|
||||
else
|
||||
[1:4,i]
|
||||
end if
|
||||
{tmpTab},put(table)
|
||||
end if
|
||||
next
|
||||
clear mark.
|
||||
back
|
||||
|
||||
chek Winner or Game Over:
|
||||
{table}gthan(0),xtonum,stats(SUMMATORY),{16} eq? do{{0}mov(go),{0}mov(swFin),back} // You loose!
|
||||
{0}reshape(table),{2048,table}array(SCAN){0} neq? do{{0}mov(go),back} // you Win!
|
||||
{4,4}reshape(table)
|
||||
back
|
||||
|
||||
select Position of aleatory tail:
|
||||
prec(-1)
|
||||
__NO_VALID_POS__:
|
||||
{10}rand, mulby(10),ceil,module(5),x=0,cpy(x),zero?,do{x=1}
|
||||
{10}rand, mulby(10),ceil,module(5),y=0,cpy(y),zero?,do{y=1}
|
||||
[x,y]get(table),jnz(__NO_VALID_POS__)
|
||||
newTail=2
|
||||
{1}rand,gthan(0.9), do{ newTail=4 }
|
||||
{newTail},put(table), clear mark.
|
||||
prec(0)
|
||||
back
|
||||
|
||||
show Table:
|
||||
tmpTable=0
|
||||
{" ",6,table}xtostr,padcenter,mov(tmpTable)
|
||||
// prepare colours of tiles
|
||||
{"\BGLGR\BK \OFF"," 0 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGLGR\BK 2 \OFF"," 2 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGLGR\B 4 \OFF"," 4 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGLGR\B 8 \OFF"," 8 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGR\W 16 \OFF"," 16 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGY\BK 32 \OFF"," 32 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGB\W 64 \OFF"," 64 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGLM\BK 128 \OFF"," 128 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGG\W 256 \OFF"," 256 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGB\W 512 \OFF"," 512 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGR\W 1024 \OFF"," 1024 ",tmpTable} transform, mov(tmpTable)
|
||||
{"\BGBK\W\ENF 2048 \OFF"," 2048 ",tmpTable} transform, mov(tmpTable)
|
||||
|
||||
// and PRINT!!
|
||||
{show Structure} do{ print Table structure,{0} mov(show Structure) }
|
||||
|
||||
clear mark
|
||||
scrx=2
|
||||
for (i=1, {i}lethan(4),++i)
|
||||
{2,scrx}goxy,[1,i]get(tmpTable),print
|
||||
{4,scrx}goxy,[2,i]get(tmpTable),print
|
||||
{6,scrx}goxy,[3,i]get(tmpTable),print
|
||||
{8,scrx}goxy,[4,i]get(tmpTable),print
|
||||
clear mark
|
||||
scrx += 7
|
||||
next
|
||||
|
||||
{"\BGB\W\ENF","\n\n\t 2 0 4 8 \OFF\n\n"}
|
||||
{"Movimiento # ",contador de movimientos,", \INVSCORE=",score,"\OFF\n"}//,tmpTable}
|
||||
println
|
||||
|
||||
back
|
||||
|
||||
print Table structure:
|
||||
{"┌──────┬──────┬──────┬──────┐\n"},strtoutf8,
|
||||
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
|
||||
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
|
||||
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
|
||||
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
|
||||
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
|
||||
{"├──────┼──────┼──────┼──────┤\n"},strtoutf8,
|
||||
{"│ 2048 │ 2048 │ 2048 │ 2048 │\n"},strtoutf8,
|
||||
{"└──────┴──────┴──────┴──────┘"},strtoutf8,
|
||||
println
|
||||
back
|
||||
287
Task/2048/Amazing-Hopper/2048-2.hopper
Normal file
287
Task/2048/Amazing-Hopper/2048-2.hopper
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
// Definicion de "contextos"
|
||||
#context-free select Position of aleatory tail
|
||||
set Decimal (-1)
|
||||
tSIZE=0,
|
||||
Let( tSIZE := var(SIZE) Plus (1) )
|
||||
__NO_VALID_POS__:
|
||||
x=0, y=0
|
||||
When( Is Zero? ( Ceil( Rand(10) Mul by(10) ) Module (tSIZE) » (x) )){ x = 1 }
|
||||
When( Is Zero? ( Ceil( Rand(10) Mul by(10) ) Module (tSIZE) » (y) )){ y = 1 }
|
||||
At Interval [x,y], Get (table), Goto If Not Zero(__NO_VALID_POS__)
|
||||
newTail=2
|
||||
When ( Rand(1) Is Gt (0.9) ) { newTail=4 }
|
||||
Take( newTail ), and SPut(table).
|
||||
set Decimal(0)
|
||||
Return\\
|
||||
|
||||
#context-free check Winner or Game Over
|
||||
When ( Summatory ( Val( var(table) Is Gt (0) ) ), Is Eq? ( var(SIZE) Mulby(SIZE) ) ) {
|
||||
MStore( 0, go, swFin ), and Back // You loose!
|
||||
}
|
||||
ReDim( table, 0 ) // convierte en vector
|
||||
When( Scan(1, 2048, table ) Is Not Eq? (0) ){
|
||||
ReDim( table, SIZE, SIZE ), Let ( go:=0 ) and Back // You Win!
|
||||
}
|
||||
ReDim( table, SIZE, SIZE )
|
||||
Return\\
|
||||
|
||||
#context-free show Table
|
||||
tmpTable=0
|
||||
Let ( tmpTable := CPad$(" ", 6, Str$(table)) )
|
||||
Let ( tmpTable := Tran$("\BGLGR\BK \OFF"," 0 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGLGR\BK 2 \OFF"," 2 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGLGR\B 4 \OFF"," 4 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGLGR\B 8 \OFF"," 8 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGR\W 16 \OFF"," 16 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGY\BK 32 \OFF"," 32 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGB\W 64 \OFF"," 64 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGLM\BK 128 \OFF"," 128 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGG\W 256 \OFF"," 256 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGB\W 512 \OFF"," 512 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGR\W 1024 \OFF"," 1024 ", tmpTable) )
|
||||
Let ( tmpTable := Tran$("\BGBK\W\ENF 2048 \OFF"," 2048 ", tmpTable) )
|
||||
When( show Structure ) { print Table structure, and Let ( show Structure := 0 ) }
|
||||
Clear Mark
|
||||
scrx=2
|
||||
For (i=1, var(i) Is Le (SIZE), ++i)
|
||||
Locate in Column (scrx)
|
||||
Locate in Row (2), At Interval [1,i], Print( Get (tmpTable) )
|
||||
Locate in Row (4), At Interval [2,i], Print( Get (tmpTable) )
|
||||
Locate in Row (6), At Interval [3,i], Print( Get (tmpTable) )
|
||||
Locate in Row (8), At Interval [4,i], Print( Get (tmpTable) )
|
||||
When( var(SIZE) Is Ge? (5) ) {Locate in Row (10), At Interval [5,i], Print( Get (tmpTable) )}
|
||||
When( var(SIZE) Is Ge? (6) ) {Locate in Row (12), At Interval [6,i], Print( Get (tmpTable) )}
|
||||
scrx += 7
|
||||
Next
|
||||
Clear Mark
|
||||
Take( "\BGB\W\ENF","\n\n\t 2 0 4 8 \OFF\n\n",\
|
||||
"Movimiento # ",contador de movimientos,", \INVSCORE=",score,"\OFF\n" )
|
||||
and Print It
|
||||
Return\\
|
||||
|
||||
#context-free print Table structure
|
||||
Locate (1,1)
|
||||
If ( var(SIZE) Is Eq? (4) )
|
||||
Str2Utf8$("┌──────┬──────┬──────┬──────┐\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("└──────┴──────┴──────┴──────┘")
|
||||
Else If( var(SIZE) Is Eq? (5) )
|
||||
Str2Utf8$("┌──────┬──────┬──────┬──────┬──────┐\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("└──────┴──────┴──────┴──────┴──────┘")
|
||||
Else If( var(SIZE) Is Eq? (6) )
|
||||
Str2Utf8$("┌──────┬──────┬──────┬──────┬──────┬──────┐\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("├──────┼──────┼──────┼──────┼──────┼──────┤\n")
|
||||
Str2Utf8$("│ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │ 2048 │\n")
|
||||
Str2Utf8$("└──────┴──────┴──────┴──────┴──────┴──────┘")
|
||||
End If
|
||||
now Print It
|
||||
Return\\
|
||||
|
||||
// definicion de prototipos:
|
||||
#proto MovingRightDown(_X_)
|
||||
#proto MovingLeftUp(_X_)
|
||||
#proto checkPointLeftUp(_X_)
|
||||
#proto checkPointRightDown(_X_)
|
||||
#proto checkMoveRightDown(_X_)
|
||||
#proto checkMoveLeftUp(_X_)
|
||||
|
||||
// definiciones varias:
|
||||
#define KUP 5
|
||||
#define KDOWN 24
|
||||
#define KLEFT 19
|
||||
#define KRIGHT 4
|
||||
#define KESCAPE 27
|
||||
#define MOVEHORZ 1
|
||||
#define MOVEVERT 0
|
||||
|
||||
// archivo de inclusión de macros H-BASIC:
|
||||
#include <hbasic.h>
|
||||
|
||||
Begin
|
||||
Option Ctrl+C
|
||||
Option Stack 16
|
||||
|
||||
contador de movimientos=0
|
||||
score=0, SIZE=4
|
||||
When( ArgCount, Is Eq? (2) ){ get ArgNumber(2,SIZE) }
|
||||
|
||||
If ( var(SIZE) Is Not Between?(4,includ,6,includ) )
|
||||
Print("Usage: hopper 2048.bas [4(default)-6]\n")
|
||||
Stop
|
||||
End If
|
||||
|
||||
Dim (SIZE,SIZE) for Zeros Array (table)
|
||||
|
||||
oldTable=0, show Structure=1
|
||||
/* define initial positions */
|
||||
Token Sep("")
|
||||
select Position of aleatory tail
|
||||
select Position of aleatory tail
|
||||
Cls
|
||||
Hide Cursor
|
||||
show Table
|
||||
c=0, go=1,swFin=1
|
||||
|
||||
/* game! */
|
||||
While ( go )
|
||||
Let ( c:=GetCh )
|
||||
oldTable = table
|
||||
Switch(c)
|
||||
Case(KRIGHT) { _check Move Right Down(MOVEHORZ), Exit }
|
||||
Case(KDOWN) { _check Move Right Down(MOVEVERT), Exit }
|
||||
Case(KLEFT) { _check Move Left Up(MOVEHORZ), Exit }
|
||||
Case(KUP) { _check Move Left Up(MOVEVERT), Exit }
|
||||
Case(KESCAPE){ go=0, swFin=0 }
|
||||
End Switch
|
||||
|
||||
check Winner or Game Over
|
||||
When( go ){
|
||||
If ( are Not EqArray? (oldTable, table) ) //( not( equal tables(oldTable, table) ) )
|
||||
select Position of aleatory tail
|
||||
++contador de movimientos
|
||||
End If
|
||||
show Table
|
||||
}
|
||||
Wend
|
||||
|
||||
If ( swFin )
|
||||
show Table
|
||||
Print(" \LG","YOU WIN!!!\OFF")
|
||||
Else
|
||||
Print(" \LR","GAME OVER\OFF")
|
||||
End If
|
||||
Put a Newl
|
||||
Show Cursor
|
||||
End
|
||||
|
||||
Subrutines
|
||||
|
||||
Moving Right Down(tmpTab)
|
||||
ht=0, sizet=0
|
||||
Let( sizet := var(SIZE) Minus ( Length( Compact(tmpTab), Copy to (ht) ) ) )
|
||||
If ( Is Not Zero?(sizet) )
|
||||
Clear(tmpTab)
|
||||
Dim (sizet) for Zeros Array (tmpTab)
|
||||
Concat( ht,tmpTab )
|
||||
End If
|
||||
Return (tmpTab)
|
||||
|
||||
Moving Left Up(tmpTab)
|
||||
sizet=0
|
||||
Compact( tmpTab ),Clear(tmpTab) and Copy to (tmpTab); get Length It, Subtracted from (SIZE); then Move to (sizet)
|
||||
//When( Is Not Zero?(sizet) ){
|
||||
When( var(sizet) Is Not Zero? ){
|
||||
ht=0
|
||||
Dim (sizet) for Zeros Array (ht)
|
||||
Concat( ht, tmpTab )
|
||||
}
|
||||
Return (tmpTab)
|
||||
|
||||
check Point Right Down(tmpTab)
|
||||
v1=0,v2=0,tScore=0,totScore=0
|
||||
For(k=SIZE, var(k) Is Gt (1), --k)
|
||||
Set Interval [k] and Get (tmpTab); then Move to (v1)
|
||||
Set Interval [ var(k) Minus(1)], Get(tmpTab), and Move to (v2)
|
||||
If( var(v1) Is Eq? (v2) )
|
||||
Add(v1,v2), Copy to(tScore);
|
||||
At Interval [k] Put(tmpTab)
|
||||
At Interval [ var(k) Minus(1) ], now Take(0); then Put (tmpTab)
|
||||
Let( totScore := var(tScore) Plus (totScore) )
|
||||
End If
|
||||
Next
|
||||
Take(tmpTab,totScore) and Return
|
||||
|
||||
check Move Right Down (_DIRECTION_)
|
||||
tmpTab=0
|
||||
For(i=1, while var(i) Is Le (SIZE), ++i)
|
||||
If ( _DIRECTION_ ) // rows or cols??
|
||||
Set Interval [i,1:SIZE] // rows!
|
||||
Else
|
||||
Set Interval [1:SIZE,i] // cols!
|
||||
End If
|
||||
now Let( tmpTab := Get(table) )
|
||||
|
||||
If( Summatory ( tmpTab ) ) // exist numbers in the row??
|
||||
Clear Mark
|
||||
|
||||
Let( tmpTab := _Moving Right Down(tmpTab) ) // move its!
|
||||
Clear Mark
|
||||
Store ( _check Point Right Down(tmpTab) Plus (score), tmpTab, score ) // check score...
|
||||
Clear Mark
|
||||
Let ( tmpTab := _Moving Right Down(tmpTab) ) // move remanents!
|
||||
If( _DIRECTION_ )
|
||||
Set Interval [i,1:SIZE]
|
||||
Else
|
||||
Set Interval [1:SIZE,i]
|
||||
End If
|
||||
Take( tmpTab ), and Put(table)
|
||||
End If
|
||||
Next
|
||||
Clear(tmpTab) and Clear Mark.
|
||||
Return
|
||||
|
||||
check Point Left Up(tmpTab)
|
||||
v1=0,v2=0,tScore=0,totScore=0
|
||||
For(k=1, while var(k) Is Lt (SIZE),++k)
|
||||
At Interval [k] Get (tmpTab), and Move to (v1)
|
||||
At Interval [ var(k) Plus(1) ] Get(tmpTab), and Move to (v2)
|
||||
If( var(v1) Is Eq? (v2) )
|
||||
Add(v1, v2),Copy to (tScore)
|
||||
At Interval [k] Put(tmpTab), At Interval [ var(k) Plus(1)]; then Take(0) and Put(tmpTab)
|
||||
Let( totScore := var(tScore) Plus (totScore) )
|
||||
End If
|
||||
Next
|
||||
Take (tmpTab,totScore)
|
||||
Return
|
||||
|
||||
check Move Left Up(_DIRECTION_)
|
||||
tmpTab=0
|
||||
For(i=1, while var(i) Is Le (SIZE),++i)
|
||||
If( _DIRECTION_ )
|
||||
Set Interval [i,1:SIZE]
|
||||
Else
|
||||
Set Interval [1:SIZE,i]
|
||||
End If
|
||||
now Get(table), and Move to (tmpTab)
|
||||
If( Summatory (tmpTab) ) // exist numbers in the row??
|
||||
Clear Mark
|
||||
Let ( tmpTab := _Moving Left Up(tmpTab) ) // move its!
|
||||
Clear Mark
|
||||
Store ( _check Point Left Up(tmpTab) Plus (score), tmpTab, score ) // check score...
|
||||
|
||||
Clear Mark
|
||||
Let ( tmpTab := _Moving Left Up(tmpTab) ) // move remanents!
|
||||
If( _DIRECTION_ )
|
||||
Set Interval [i,1:SIZE]
|
||||
Else
|
||||
Set Interval [1:SIZE,i]
|
||||
End If
|
||||
now Take (tmpTab), and Put(table)
|
||||
End If
|
||||
Next
|
||||
Clear Mark.
|
||||
Return
|
||||
204
Task/2048/Applesoft-BASIC/2048.basic
Normal file
204
Task/2048/Applesoft-BASIC/2048.basic
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
PRINT "Game 2048"
|
||||
|
||||
10 REM ************
|
||||
20 REM * 2024 *
|
||||
30 REM ************
|
||||
40 HOME
|
||||
100 W = 2: REM **** W=0 FOR LOOSE W=1 FOR WIN W=2 FOR PLAYING ****
|
||||
110 DIM MA(4,4)
|
||||
120 FC = 16: REM FREECELLS
|
||||
130 A$ = "":SC = 0:MT = 2
|
||||
140 GOSUB 1000: DRAW THESCREEN
|
||||
150 GOSUB 1500: REM PRINT SCORE AND MAXTILE
|
||||
160 GOSUB 1700: REM BREED
|
||||
170 GOSUB 2000: REM PRINT SCORES IN THE MATRIX AND CALC FC AND MT
|
||||
200 REM ******************
|
||||
210 REM MAIN PROGRAM
|
||||
220 REM ******************
|
||||
230 HTAB 38: VTAB 22
|
||||
235 IF W < 2 THEN GOTO 950: REM ******* END GAME ********
|
||||
240 WAIT - 16384,128:A = PEEK ( - 16384) - 128 - 68: POKE - 16368,0
|
||||
250 ON A GOTO 999,900,900,900,300,350,400,900,450
|
||||
280 REM ************************
|
||||
285 REM FOLLOWING LINES HANDLE THE UP, LEFT, RIGHT, DOWN, NOP, EXIT
|
||||
290 REM ************************
|
||||
300 GOSUB 2500: GOSUB 3500: GOSUB 2500: GOSUB 1700: GOSUB 2000: GOSUB 1
|
||||
500
|
||||
310 GOTO 200
|
||||
350 GOSUB 2600: GOSUB 3600: GOSUB 2600: GOSUB 1700: GOSUB 2000: GOSUB 1
|
||||
500
|
||||
360 GOTO 200
|
||||
400 GOSUB 2700: GOSUB 3700: GOSUB 2700: GOSUB 1700: GOSUB 2000: GOSUB 1
|
||||
500
|
||||
410 GOTO 200
|
||||
450 GOSUB 2800: GOSUB 3800: GOSUB 2800: GOSUB 1700: GOSUB 2000: GOSUB 1
|
||||
500
|
||||
460 GOTO 200
|
||||
900 GOTO 200
|
||||
950 HOME : VTAB 10
|
||||
960 PRINT " ********************"
|
||||
970 IF W = 1 THEN PRINT " * YOU WIN *"
|
||||
980 IF W = 0 THEN PRINT " * YOU LOOSE *"
|
||||
990 PRINT " ********************"
|
||||
995 PRINT " SCORE =";SC
|
||||
996 PRINT " MAXTILE=";MT
|
||||
999 END
|
||||
1000 REM DRAW FRAME + SCORE
|
||||
1010 FOR I = 1 TO 5
|
||||
1020 VTAB 1 + (I - 1) * 4: PRINT "---------------------"
|
||||
1030 NEXT I
|
||||
1040 FOR I = 1 TO 4
|
||||
1050 FOR J = 1 TO 3
|
||||
1060 VTAB 1 + (I - 1) * 4 + J: PRINT "| | | | |"
|
||||
1070 NEXT J
|
||||
1080 NEXT I
|
||||
1090 HTAB 30: VTAB 3: PRINT "I";
|
||||
1100 HTAB 30: VTAB 9: PRINT "M";
|
||||
1110 HTAB 25: VTAB 6: PRINT "J";
|
||||
1120 HTAB 35: VTAB 6: PRINT "K";
|
||||
1130 HTAB 25: VTAB 12: PRINT "E = END"
|
||||
1140 HTAB 25: VTAB 14: PRINT "SCORE:"
|
||||
1150 HTAB 25: VTAB 16: PRINT "MAXTILE:"
|
||||
1160 HTAB 1: VTAB 19: PRINT "YOU CAN SLIDE THE NUMBERS IN THE MATRIX"
|
||||
1170 HTAB 1: VTAB 20: PRINT "BY PRESSING IJKM. WHEN MATCHING NUMBERS"
|
||||
1180 HTAB 1: VTAB 21: PRINT "MEET THEY COMBINE IN THE SUM"
|
||||
1190 HTAB 1: VTAB 22: PRINT "TO WIN YOU HAVE TO REACH THE SUM 2048"
|
||||
1200 RETURN
|
||||
1500 REM ***************
|
||||
1501 REM PRINT SCORE + MAXTILE
|
||||
1502 REM ***************
|
||||
1510 VTAB 14: HTAB 32:
|
||||
1520 SC$ = STR$ (SC):LS = LEN (SC$)
|
||||
1530 FOR I = 1 TO 7 - LS: PRINT " ";: NEXT I
|
||||
1540 PRINT SC$
|
||||
1550 VTAB 16: HTAB 34:
|
||||
1560 MT$ = STR$ (MT):LS = LEN (MT$)
|
||||
1570 FOR I = 1 TO 5 - LS: PRINT " ";: NEXT I
|
||||
1580 PRINT MT$
|
||||
1590 IF SC = 2048 THEN W = 1: REM ******** YOU WIN ********
|
||||
1690 RETURN
|
||||
1700 REM ****************
|
||||
1701 REM PUT A "2" IN A RANDOM EMPTY CELL
|
||||
1702 REM ****************
|
||||
1708 IF FC = 0 THEN W = 0: GOTO 1800: REM ***** YOU LOOSE *****
|
||||
1710 K = INT ( RND (1) * FC + 1)
|
||||
1720 N = 0
|
||||
1730 FOR I = 1 TO 4
|
||||
1740 FOR J = 1 TO 4
|
||||
1750 IF MA(I,J) = 0 THEN N = N + 1
|
||||
1760 IF N = K THEN MA(I,J) = 2:FC = FC - 1:I = 4:J = 4
|
||||
1780 NEXT J
|
||||
1790 NEXT I
|
||||
1800 RETURN
|
||||
2000 REM *************
|
||||
2001 REM WRITE THE CELL CONTENT AND CALC. FREECELLS AND MAXTILE
|
||||
2002 REM *************
|
||||
2005 FC = 0:MT = 0: REM INITIALIZE FREECELLS AND MAXTILES
|
||||
2010 FOR I = 1 TO 4
|
||||
2020 FOR J = 1 TO 4
|
||||
2030 HTAB 2 + (J - 1) * 5: VTAB 3 + (I - 1) * 4
|
||||
2040 PRINT " ";: HTAB 2 + (J - 1) * 5
|
||||
2050 IF MA(I,J) = 0 THEN FC = FC + 1: GOTO 2060
|
||||
2055 PRINT MA(I,J);
|
||||
2060 IF MA(I,J) > MT THEN MT = MA(I,J)
|
||||
2090 NEXT J
|
||||
2100 NEXT I
|
||||
2190 RETURN
|
||||
2500 REM *****************
|
||||
2510 REM COMPACT UP - KIND OF BUBBLE SORT
|
||||
2520 REM *****************
|
||||
2530 FOR J = 1 TO 4
|
||||
2540 FOR K = 3 TO 1 STEP - 1
|
||||
2550 FOR I = 1 TO K
|
||||
2560 IF MA(I,J) = 0 THEN MA(I,J) = MA(I + 1,J):MA(I + 1,J) = 0
|
||||
2570 NEXT : NEXT : NEXT
|
||||
2590 RETURN
|
||||
2600 REM ************
|
||||
2610 REM COMPACT LEFT
|
||||
2620 REM ************
|
||||
2630 FOR I = 1 TO 4
|
||||
2640 FOR K = 3 TO 1 STEP - 1
|
||||
2650 FOR J = 1 TO K
|
||||
2660 IF MA(I,J) = 0 THEN MA(I,J) = MA(I,J + 1):MA(I,J + 1) = 0
|
||||
2670 NEXT : NEXT : NEXT
|
||||
2690 RETURN
|
||||
2700 REM ************
|
||||
2710 REM COMPACT RIGHT
|
||||
2720 REM ************
|
||||
2730 FOR I = 1 TO 4
|
||||
2740 FOR K = 2 TO 4
|
||||
2750 FOR J = 4 TO K STEP - 1
|
||||
2760 IF MA(I,J) = 0 THEN MA(I,J) = MA(I,J - 1):MA(I,J - 1) = 0
|
||||
2770 NEXT : NEXT : NEXT
|
||||
2790 RETURN
|
||||
2800 REM *****************
|
||||
2810 REM COMPACT DOWN
|
||||
2820 REM *****************
|
||||
2830 FOR J = 1 TO 4
|
||||
2840 FOR K = 2 TO 4
|
||||
2850 FOR I = 4 TO K STEP - 1
|
||||
2860 IF MA(I,J) = 0 THEN MA(I,J) = MA(I - 1,J):MA(I - 1,J) = 0
|
||||
2870 NEXT : NEXT : NEXT
|
||||
2890 RETURN
|
||||
3500 REM ***************
|
||||
3510 REM ADD UP
|
||||
3520 REM ***************
|
||||
3530 FOR J = 1 TO 4
|
||||
3540 FOR I = 1 TO 3
|
||||
3550 IF MA(I,J) = MA(I + 1,J) THEN MA(I,J) = MA(I,J) * 2:MA(I + 1,J) =
|
||||
0:SC = SC + MA(I,J)
|
||||
3560 NEXT : NEXT
|
||||
3590 RETURN
|
||||
3600 REM **************
|
||||
3610 REM SUM LEFT
|
||||
3620 REM **************
|
||||
3630 FOR I = 1 TO 4
|
||||
3640 FOR J = 1 TO 3
|
||||
3650 IF MA(I,J) = MA(I,J + 1) THEN MA(I,J) = MA(I,J) * 2:MA(I,J + 1) =
|
||||
0:SC = SC + MA(I,J)
|
||||
3660 NEXT : NEXT
|
||||
3690 RETURN
|
||||
3700 REM **************
|
||||
3710 REM SUM RIGHT
|
||||
3720 REM **************
|
||||
3730 FOR I = 1 TO 4
|
||||
3740 FOR J = 4 TO 2 STEP - 1
|
||||
3750 IF MA(I,J) = MA(I,J - 1) THEN MA(I,J) = MA(I,J) * 2:MA(I,J - 1) =
|
||||
0:SC = SC + MA(I,J)
|
||||
3760 NEXT : NEXT
|
||||
3790 RETURN
|
||||
3800 REM ***************
|
||||
3810 REM ADD DOWN
|
||||
3820 REM ***************
|
||||
3830 FOR J = 1 TO 4
|
||||
3840 FOR I = 4 TO 2 STEP - 1
|
||||
3850 IF MA(I,J) = MA(I - 1,J) THEN MA(I,J) = MA(I,J) * 2:MA(I - 1,J) =
|
||||
0:SC = SC + MA(I,J)
|
||||
3860 NEXT : NEXT
|
||||
3890 RETURN
|
||||
|
||||
-----
|
||||
it runs somehow slowly but still fun to play. The only non standard basic is the input routine which reads directly the memory location (line 240) instead of using "input" od "get"
|
||||
|
||||
---------------------
|
||||
| | | | |
|
||||
|4 | | |2 | I
|
||||
| | | | |
|
||||
---------------------
|
||||
| | | | | J K
|
||||
|4 |2 | | |
|
||||
| | | | |
|
||||
--------------------- M
|
||||
| | | | |
|
||||
|2 |16 |4 | |
|
||||
| | | | | E = END
|
||||
---------------------
|
||||
| | | | | SCORE: 4924
|
||||
|128 |512 | | |
|
||||
| | | | | MAXTILE: 512
|
||||
---------------------
|
||||
|
||||
YOU CAN SLIDE THE NUMBERS IN THE MATRIX
|
||||
BY PRESSING IJKM. WHEN MATCHING NUMBERS
|
||||
MEET THEY COMBINE IN THE SUM
|
||||
TO WIN YOU HAVE TO REACH THE SUM 2048
|
||||
224
Task/2048/AutoHotkey/2048.ahk
Normal file
224
Task/2048/AutoHotkey/2048.ahk
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
Grid := [], s := 16, w := h := S * 4.5
|
||||
Gui, font, s%s%
|
||||
Gui, add, text, y1
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
if col = 1
|
||||
Gui, add, button, v%row%_%col% xs y+1 w%w% h%h% -TabStop, % Grid[row,col] := 0
|
||||
else
|
||||
Gui, add, button, v%row%_%col% x+1 yp w%w% h%h% -TabStop, % Grid[row,col] := 0
|
||||
}
|
||||
}
|
||||
Gui, show,, 2048
|
||||
;------------------------------
|
||||
|
||||
Start:
|
||||
for row, obj in Grid
|
||||
for col, val in obj
|
||||
Grid[row,col] := 0
|
||||
|
||||
Grid[1,1]:=2
|
||||
ShowGrid()
|
||||
return
|
||||
|
||||
;------------------------------
|
||||
GuiClose:
|
||||
ExitApp
|
||||
return
|
||||
;------------------------------
|
||||
#IfWinActive, 2048
|
||||
;------------------------------
|
||||
up::
|
||||
move := false
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
Loop, 3
|
||||
{
|
||||
row := A_Index
|
||||
if Grid[row, col] && (Grid[row, col] = Grid[row+1, col])
|
||||
Grid[row, col] *=2 , Grid[row+1, col] := 0, move := true
|
||||
}
|
||||
}
|
||||
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
loop, 4
|
||||
if !Grid[row, col]
|
||||
loop, 3
|
||||
if !Grid[row, col] && Grid[row+A_Index, col]
|
||||
{
|
||||
Grid[row, col] := Grid[row+A_Index, col] , Grid[row+A_Index, col] := 0, move := true
|
||||
if (Grid[row, col] = Grid[row-1, col])
|
||||
Grid[row-1, col] *=2 , Grid[row, col] := 0, move := true
|
||||
}
|
||||
}
|
||||
}
|
||||
gosub, AddNew
|
||||
return
|
||||
;------------------------------
|
||||
Down::
|
||||
move := false
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
Loop, 3
|
||||
{
|
||||
row := 5-A_Index
|
||||
if Grid[row, col] && (Grid[row, col] = Grid[row-1, col])
|
||||
Grid[row, col] *=2 , Grid[row-1, col] := 0, move := true
|
||||
}
|
||||
}
|
||||
|
||||
loop, 4
|
||||
{
|
||||
row := 5-A_Index
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
loop, 4
|
||||
if !Grid[row, col]
|
||||
loop, 3
|
||||
if !Grid[row, col] && Grid[row-A_Index, col]
|
||||
{
|
||||
Grid[row, col] := Grid[row-A_Index, col] , Grid[row-A_Index, col] := 0, move := true
|
||||
if (Grid[row, col] = Grid[row+1, col])
|
||||
Grid[row+1, col] *=2 , Grid[row, col] := 0, move := true
|
||||
}
|
||||
}
|
||||
}
|
||||
gosub, AddNew
|
||||
return
|
||||
;------------------------------
|
||||
Left::
|
||||
move := false
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
Loop, 3
|
||||
{
|
||||
col := A_Index
|
||||
if Grid[row, col] && (Grid[row, col] = Grid[row, col+1])
|
||||
Grid[row, col] *=2 , Grid[row, col+1] := 0, move := true
|
||||
}
|
||||
}
|
||||
|
||||
loop, 4
|
||||
{
|
||||
col := A_Index
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
loop, 4
|
||||
if !Grid[row, col]
|
||||
loop, 3
|
||||
if !Grid[row, col] && Grid[row, col+A_Index]
|
||||
{
|
||||
Grid[row, col] := Grid[row, col+A_Index] , Grid[row, col+A_Index] := 0, move := true
|
||||
if (Grid[row, col] = Grid[row, col-1])
|
||||
Grid[row, col-1] *=2 , Grid[row, col] := 0, move := true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
gosub, AddNew
|
||||
return
|
||||
;------------------------------
|
||||
Right::
|
||||
move := false
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
Loop, 3
|
||||
{
|
||||
col := 5-A_Index
|
||||
if Grid[row, col] && (Grid[row, col] = Grid[row, col-1])
|
||||
Grid[row, col] *=2 , Grid[row, col-1] := 0, move := true
|
||||
}
|
||||
}
|
||||
|
||||
loop, 4
|
||||
{
|
||||
col := 5-A_Index
|
||||
loop, 4
|
||||
{
|
||||
row := A_Index
|
||||
loop, 4
|
||||
if !Grid[row, col]
|
||||
loop, 3
|
||||
if !Grid[row, col] && Grid[row, col-A_Index]
|
||||
{
|
||||
Grid[row, col] := Grid[row, col-A_Index] , Grid[row, col-A_Index] := 0, move := true
|
||||
if (Grid[row, col] = Grid[row, col+1])
|
||||
Grid[row, col+1] *=2 , Grid[row, col] := 0, move := true
|
||||
}
|
||||
}
|
||||
}
|
||||
gosub, AddNew
|
||||
return
|
||||
|
||||
;------------------------------
|
||||
#IfWinActive
|
||||
;------------------------------
|
||||
AddNew:
|
||||
if EndOfGame()
|
||||
{
|
||||
MsgBox Done `nPress OK to retry
|
||||
goto start
|
||||
}
|
||||
return
|
||||
|
||||
;------------------------------
|
||||
EndOfGame(){
|
||||
global
|
||||
if Move
|
||||
AddRandom()
|
||||
ShowGrid()
|
||||
for row, obj in Grid
|
||||
for col, val in obj
|
||||
if !grid[row,col]
|
||||
return 0
|
||||
|
||||
for row, obj in Grid
|
||||
for col, val in obj
|
||||
if (grid[row,col] = grid[row+1,col]) || (grid[row,col] = grid[row-1,col]) || (grid[row,col] = grid[row,col+1]) || (grid[row,col] = grid[row,col-1])
|
||||
return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
;------------------------------
|
||||
ShowGrid(){
|
||||
global Grid
|
||||
for row, obj in Grid
|
||||
for col, val in obj
|
||||
{
|
||||
GuiControl,, %row%_%col%, %val%
|
||||
if val
|
||||
GuiControl, Show, %row%_%col%
|
||||
else
|
||||
GuiControl, Hide, %row%_%col%
|
||||
}
|
||||
}
|
||||
|
||||
;------------------------------
|
||||
AddRandom(){
|
||||
global Grid
|
||||
ShowGrid()
|
||||
Sleep, 200
|
||||
for row, obj in Grid
|
||||
for col, val in obj
|
||||
if !grid[row,col]
|
||||
list .= (list?"`n":"") row "," col
|
||||
Sort, list, random
|
||||
Rnd := StrSplit(list, "`n").1
|
||||
Grid[StrSplit(rnd, ",").1, StrSplit(rnd, ",").2] := 2
|
||||
}
|
||||
;------------------------------
|
||||
70
Task/2048/BBC-BASIC/2048.basic
Normal file
70
Task/2048/BBC-BASIC/2048.basic
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
SIZE = 4 : MAX = SIZE-1
|
||||
Won% = FALSE : Lost% = FALSE
|
||||
@% = 5
|
||||
DIM Board(MAX,MAX),Stuck% 3
|
||||
|
||||
PROCBreed
|
||||
PROCPrint
|
||||
REPEAT
|
||||
Direction = GET-135
|
||||
IF Direction > 0 AND Direction < 5 THEN
|
||||
Moved% = FALSE
|
||||
PROCShift
|
||||
PROCMerge
|
||||
PROCShift
|
||||
IF Moved% THEN PROCBreed : !Stuck%=0 ELSE ?(Stuck%+Direction-1)=-1 : Lost% = !Stuck%=-1
|
||||
PROCPrint
|
||||
ENDIF
|
||||
UNTIL Won% OR Lost%
|
||||
IF Won% THEN PRINT "You WON! :-)" ELSE PRINT "You lost :-("
|
||||
END
|
||||
|
||||
REM -----------------------------------------------------------------------------------------------------------------------
|
||||
DEF PROCPrint
|
||||
FOR i = 0 TO SIZE*SIZE-1
|
||||
IF Board(i DIV SIZE,i MOD SIZE) THEN PRINT Board(i DIV SIZE,i MOD SIZE); ELSE PRINT " _";
|
||||
IF i MOD SIZE = MAX THEN PRINT
|
||||
NEXT
|
||||
PRINT STRING$(SIZE,"-----")
|
||||
ENDPROC
|
||||
|
||||
REM ----------------------------------------------------------------------------------------------------------------------
|
||||
DEF PROCShift
|
||||
IF Direction = 2 OR Direction = 3 THEN loopend = MAX : step = -1 ELSE loopend = 0 : step = 1
|
||||
FOR row = loopend TO MAX-loopend STEP step
|
||||
zeros = 0
|
||||
FOR col = loopend TO MAX-loopend STEP step
|
||||
IF Direction < 3 THEN
|
||||
IF Board(row,col) = 0 THEN zeros += step ELSE IF zeros THEN SWAP Board(row,col),Board(row,col-zeros) : Moved% = TRUE
|
||||
ELSE
|
||||
IF Board(col,row) = 0 THEN zeros += step ELSE IF zeros THEN SWAP Board(col,row),Board(col-zeros,row) : Moved% = TRUE
|
||||
ENDIF
|
||||
NEXT
|
||||
NEXT
|
||||
ENDPROC
|
||||
|
||||
REM -----------------------------------------------------------------------------------------------------------------------
|
||||
DEF PROCMerge
|
||||
IF Direction = 1 THEN loopend = 0 : rowoff = 0 : coloff = 1 : step = 1
|
||||
IF Direction = 2 THEN loopend = MAX : rowoff = 0 : coloff = -1 : step = -1
|
||||
IF Direction = 3 THEN loopend = MAX : rowoff = -1 : coloff = 0 : step = -1
|
||||
IF Direction = 4 THEN loopend = 0 : rowoff = 1 : coloff = 0 : step = 1
|
||||
FOR row = loopend TO MAX-loopend-rowoff STEP step
|
||||
FOR col = loopend TO MAX-loopend-coloff STEP step
|
||||
IF Board(row,col) THEN IF Board(row,col) = Board(row+rowoff,col+coloff) THEN
|
||||
Board(row,col) *= 2 : Board(row+rowoff,col+coloff) = 0
|
||||
Moved% = TRUE
|
||||
IF NOT Won% THEN Won% = Board(row,col)=2048
|
||||
ENDIF
|
||||
NEXT
|
||||
NEXT
|
||||
ENDPROC
|
||||
|
||||
REM -----------------------------------------------------------------------------------------------------------------------
|
||||
DEF PROCBreed
|
||||
cell = RND(SIZE*SIZE)-1
|
||||
FOR i = 0 TO SIZE*SIZE-1
|
||||
z = (cell+i) MOD (SIZE*SIZE)
|
||||
IF Board(z DIV SIZE,z MOD SIZE) = 0 THEN Board(z DIV SIZE,z MOD SIZE) = 2-(RND(10)=1)*2 : EXIT FOR
|
||||
NEXT
|
||||
ENDPROC
|
||||
40
Task/2048/BQN/2048.bqn
Normal file
40
Task/2048/BQN/2048.bqn
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env BQN
|
||||
# 2048 game
|
||||
# The game is controlled with the vim movement keys:
|
||||
# h: left, j: down, k: up, l: right, q: quit
|
||||
# needs a VT-100 compatible terminal
|
||||
|
||||
Merge←{𝕩 0⊸≠⊸/↩ ⋄ m←<`=⟜«𝕩 ⋄ 4↑(¬»m)/𝕩×1+m}⌾⌽ # Merge a single row to the right
|
||||
Step←Merge˘ # Merges each row of the board
|
||||
Up←Step⌾(⌽⍉∘⌽) # Each direction merges the board
|
||||
Down←Step⌾⍉ # by rotating it to the correct orientation, merging the rows
|
||||
Right←Step # and reversing the rotation
|
||||
Left←Step⌾(⌽˘)
|
||||
# Spawns a 2 or a 4 (10% chance) at a random empty position
|
||||
Spawn←{i←•rand.Range∘≠⊸⊑(0⊸= /○⥊ ↕∘≢)𝕩 ⋄ (•rand.Range∘≠⊸⊑9‿1/2‿4)⌾(i⊸⊑) 𝕩}
|
||||
Lose←Left∘Right∘Down∘Up⊸≡ # Losing condition, no moves change the board
|
||||
Win←∨´·∨˝2048⊸= # Winning condition, 2048!
|
||||
|
||||
Quit←{•Out e∾"[?12l"∾e∾"[?25h" ⋄ •Exit 𝕩} # Restores the terminal and exits
|
||||
Display←{ # Displays the board, score and controls
|
||||
•Out e∾"[H"∾e∾"[2J" # Cursor to origin and clear screen
|
||||
•Out "Controls: h: left, j: down, k: up, l: right, q: quit"
|
||||
•Show 𝕩
|
||||
•Out "score: "∾•Repr ⌈´⌈˝ 𝕩
|
||||
}
|
||||
|
||||
board←Spawn 4‿4⥊0
|
||||
e←@+27 # Escape character for the ANSI escape codes
|
||||
•term.RawMode 1
|
||||
•Out e∾"[?25l"∾e∾"[2J"∾e∾"[H" # Cursor to origin, hide it and clear screen
|
||||
{𝕤⋄
|
||||
Display board
|
||||
{𝕤⋄•Out "You win!" ⋄ Quit 0}⍟Win board
|
||||
{𝕤⋄•Out "You lose!"⋄ Quit 1}⍟Lose board
|
||||
key←•term.CharB @ # Read key
|
||||
⊑key∊"hjklq"? # Valid key?
|
||||
{𝕤⋄ Quit 0}⍟(key='q')@ # Quit key?
|
||||
move←⊑(key="hjkl")/Left‿Down‿Up‿Right # Get movement function from the key
|
||||
{𝕤⋄board↩Spawn∘Move 𝕩}⍟(Move⊸≢) board # Generate the next board if the move is valid
|
||||
; @
|
||||
}•_While_{𝕤⋄1}@
|
||||
172
Task/2048/Batch-File/2048.bat
Normal file
172
Task/2048/Batch-File/2048.bat
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
:: 2048 Game Task from RosettaCode
|
||||
:: Batch File Implementation v2.0.1
|
||||
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
rem initialization
|
||||
:begin_game
|
||||
set "size=4" %== board size ==%
|
||||
set "score=0" %== current score ==%
|
||||
set "won=0" %== boolean for winning ==%
|
||||
set "target=2048" %== as the game title says ==%
|
||||
for /l %%R in (1,1,%size%) do for /l %%C in (1,1,%size%) do set "X_%%R_%%C=0"
|
||||
|
||||
rem add two numbers in the board
|
||||
call :addtile
|
||||
call :addtile
|
||||
|
||||
rem main game loop
|
||||
:main_loop
|
||||
call :display
|
||||
echo(
|
||||
echo(Keys: WASD (Slide Movement), N (New game), P (Exit)
|
||||
|
||||
rem get keypress trick
|
||||
set "key="
|
||||
for /f "delims=" %%? in ('xcopy /w "%~f0" "%~f0" 2^>nul') do if not defined key set "key=%%?"
|
||||
set "key=%key:~-1%"
|
||||
|
||||
set "changed=0" %== boolean for changed board ==%
|
||||
set "valid_key=0" %== boolean for pressing WASD ==%
|
||||
rem process keypress
|
||||
if /i "!key!" equ "W" (set "valid_key=1" & call :slide "C" "1,1,%size%" "X")
|
||||
if /i "!key!" equ "A" (set "valid_key=1" & call :slide "R" "1,1,%size%" "X")
|
||||
if /i "!key!" equ "S" (set "valid_key=1" & call :slide "C" "%size%,-1,1" "X")
|
||||
if /i "!key!" equ "D" (set "valid_key=1" & call :slide "R" "%size%,-1,1" "X")
|
||||
if /i "!key!" equ "N" goto begin_game
|
||||
if /i "!key!" equ "P" exit /b 0
|
||||
if "%valid_key%" equ "0" goto main_loop
|
||||
|
||||
rem check if the board changed
|
||||
if %changed% neq 0 call :addtile
|
||||
|
||||
rem check for win condition
|
||||
if %won% equ 1 (
|
||||
set "msg=Nice one... You WON^!^!"
|
||||
goto gameover
|
||||
)
|
||||
|
||||
rem check for lose condition
|
||||
if %blank_count% equ 0 (
|
||||
for /l %%R in (1,1,%size%) do for /l %%C in (1,1,%size%) do set "LX_%%R_%%C=!X_%%R_%%C!"
|
||||
set "save_changed=%changed%" & set "changed=0" %== save actual changed for test ==%
|
||||
call :slide "C" "1,1,%size%" "LX"
|
||||
call :slide "R" "1,1,%size%" "LX"
|
||||
if !changed! equ 0 (
|
||||
set "msg=No moves are possible... Game Over :("
|
||||
goto gameover
|
||||
) else set "changed=!save_changed!"
|
||||
)
|
||||
goto main_loop
|
||||
|
||||
rem add number to a random blank tile
|
||||
:addtile
|
||||
set "blank_count=0" %== blank tile counter ==%
|
||||
set "new_tile=" %== clearing ==%
|
||||
rem create pseudo-array blank_tiles
|
||||
for /l %%R in (1,1,%size%) do (
|
||||
for /l %%C in (1,1,%size%) do (
|
||||
if !X_%%R_%%C! equ 0 (
|
||||
set "blank_tiles[!blank_count!]=X_%%R_%%C"
|
||||
set /a "blank_count+=1"
|
||||
)
|
||||
)
|
||||
)
|
||||
if %blank_count% equ 0 goto :EOF
|
||||
set /a "pick_tile=%random%%%%blank_count%"
|
||||
set "new_tile=!blank_tiles[%pick_tile%]!"
|
||||
set /a "rnd_newnum=%random%%%10"
|
||||
rem 10% chance new number is 4, 90% chance it's 2
|
||||
if %rnd_newnum% equ 5 (set "%new_tile%=4") else (set "%new_tile%=2")
|
||||
set /a "blank_count-=1" %== to be used for checking lose condition ==%
|
||||
goto :EOF
|
||||
|
||||
rem display the board
|
||||
:display
|
||||
cls
|
||||
echo(2048 Game in Batch
|
||||
echo(
|
||||
set "wall=+"
|
||||
for /l %%C in (1,1,%size%) do set "wall=!wall!----+"
|
||||
for /l %%R in (1,1,%size%) do (
|
||||
set "disp_row=|"
|
||||
for /l %%C in (1,1,%size%) do (
|
||||
if "!new_tile!" equ "X_%%R_%%C" (set "DX_%%R_%%C= +!X_%%R_%%C!") else (
|
||||
set "DX_%%R_%%C=!X_%%R_%%C!"
|
||||
if !X_%%R_%%C! lss 1000 set "DX_%%R_%%C= !DX_%%R_%%C!"
|
||||
if !X_%%R_%%C! lss 100 set "DX_%%R_%%C= !DX_%%R_%%C!"
|
||||
if !X_%%R_%%C! lss 10 set "DX_%%R_%%C= !DX_%%R_%%C!"
|
||||
if !X_%%R_%%C! equ 0 set "DX_%%R_%%C= "
|
||||
)
|
||||
set "disp_row=!disp_row!!DX_%%R_%%C!|"
|
||||
)
|
||||
echo(%wall%
|
||||
echo(!disp_row!
|
||||
)
|
||||
echo(%wall%
|
||||
echo(
|
||||
echo(Score: %score%
|
||||
goto :EOF
|
||||
|
||||
rem the main slider of numbers in tiles
|
||||
:slide
|
||||
rem %%A and %%B are used here because sliding direction is variable
|
||||
for /l %%A in (1,1,%size%) do (
|
||||
rem first slide: removing blank tiles in the middle
|
||||
set "slide_1="
|
||||
set "last_blank=0" %== boolean if last tile is blank ==%
|
||||
for /l %%B in (%~2) do (
|
||||
if "%~1" equ "R" (set "curr_tilenum=!%~3_%%A_%%B!"
|
||||
) else if "%~1" equ "C" (set "curr_tilenum=!%~3_%%B_%%A!")
|
||||
if !curr_tilenum! equ 0 (set "last_blank=1") else (
|
||||
set "slide_1=!slide_1! !curr_tilenum!"
|
||||
if !last_blank! equ 1 set "changed=1"
|
||||
set "last_blank=0"
|
||||
)
|
||||
)
|
||||
rem second slide: addition of numbered tiles
|
||||
rem slide_2 would be pseudo-array
|
||||
set "slide_2_count=0"
|
||||
set "skip=1" %== boolean for skipping after previous summing ==%
|
||||
if "!slide_1!" neq "" for %%S in (!slide_1! 0) do (
|
||||
if !skip! equ 1 (
|
||||
set "prev_tilenum=%%S" & set "skip=0"
|
||||
) else if !skip! equ 0 (
|
||||
if %%S equ !prev_tilenum! (
|
||||
set /a "sum=%%S+!prev_tilenum!"
|
||||
if "%~3" equ "X" set /a "score+=sum"
|
||||
set "changed=1" & set "skip=1"
|
||||
rem check for winning condition!
|
||||
if !sum! equ !target! set "won=1"
|
||||
) else (
|
||||
set "sum=!prev_tilenum!"
|
||||
set "prev_tilenum=%%S"
|
||||
)
|
||||
set "slide_2[!slide_2_count!]=!sum!"
|
||||
set /a "slide_2_count+=1"
|
||||
)
|
||||
)
|
||||
rem new values of tiles
|
||||
set "slide_2_run=0" %== running counter for slide_2 ==%
|
||||
for /l %%B in (%~2) do (
|
||||
if "%~1" equ "R" (set "curr_tile=%~3_%%A_%%B"
|
||||
) else if "%~1" equ "C" (set "curr_tile=%~3_%%B_%%A")
|
||||
for %%? in ("!slide_2_run!") do (
|
||||
if %%~? lss !slide_2_count! (set "!curr_tile!=!slide_2[%%~?]!"
|
||||
) else (set "!curr_tile!=0")
|
||||
)
|
||||
set /a "slide_2_run+=1"
|
||||
)
|
||||
)
|
||||
goto :EOF
|
||||
|
||||
rem game over xD
|
||||
:gameover
|
||||
call :display
|
||||
echo(
|
||||
echo(!msg!
|
||||
echo(
|
||||
echo(Press any key to exit . . .
|
||||
pause>nul
|
||||
exit /b 0
|
||||
193
Task/2048/C++/2048.cpp
Normal file
193
Task/2048/C++/2048.cpp
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#include <time.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
|
||||
typedef unsigned int uint;
|
||||
using namespace std;
|
||||
enum movDir { UP, DOWN, LEFT, RIGHT };
|
||||
|
||||
class tile
|
||||
{
|
||||
public:
|
||||
tile() : val( 0 ), blocked( false ) {}
|
||||
uint val;
|
||||
bool blocked;
|
||||
};
|
||||
|
||||
class g2048
|
||||
{
|
||||
public:
|
||||
g2048() : done( false ), win( false ), moved( true ), score( 0 ) {}
|
||||
void loop()
|
||||
{
|
||||
addTile();
|
||||
while( true )
|
||||
{
|
||||
if( moved ) addTile();
|
||||
drawBoard();
|
||||
if( done ) break;
|
||||
waitKey();
|
||||
}
|
||||
string s = "Game Over!";
|
||||
if( win ) s = "You've made it!";
|
||||
cout << s << endl << endl;
|
||||
}
|
||||
private:
|
||||
void drawBoard()
|
||||
{
|
||||
system( "cls" );
|
||||
cout << "SCORE: " << score << endl << endl;
|
||||
for( int y = 0; y < 4; y++ )
|
||||
{
|
||||
cout << "+------+------+------+------+" << endl << "| ";
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
if( !board[x][y].val ) cout << setw( 4 ) << " ";
|
||||
else cout << setw( 4 ) << board[x][y].val;
|
||||
cout << " | ";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
cout << "+------+------+------+------+" << endl << endl;
|
||||
}
|
||||
void waitKey()
|
||||
{
|
||||
moved = false; char c;
|
||||
cout << "(W)Up (S)Down (A)Left (D)Right "; cin >> c; c &= 0x5F;
|
||||
switch( c )
|
||||
{
|
||||
case 'W': move( UP );break;
|
||||
case 'A': move( LEFT ); break;
|
||||
case 'S': move( DOWN ); break;
|
||||
case 'D': move( RIGHT );
|
||||
}
|
||||
for( int y = 0; y < 4; y++ )
|
||||
for( int x = 0; x < 4; x++ )
|
||||
board[x][y].blocked = false;
|
||||
}
|
||||
void addTile()
|
||||
{
|
||||
for( int y = 0; y < 4; y++ )
|
||||
for( int x = 0; x < 4; x++ )
|
||||
if( !board[x][y].val )
|
||||
{
|
||||
uint a, b;
|
||||
do
|
||||
{ a = rand() % 4; b = rand() % 4; }
|
||||
while( board[a][b].val );
|
||||
|
||||
int s = rand() % 100;
|
||||
if( s > 89 ) board[a][b].val = 4;
|
||||
else board[a][b].val = 2;
|
||||
if( canMove() ) return;
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
bool canMove()
|
||||
{
|
||||
for( int y = 0; y < 4; y++ )
|
||||
for( int x = 0; x < 4; x++ )
|
||||
if( !board[x][y].val ) return true;
|
||||
|
||||
for( int y = 0; y < 4; y++ )
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
if( testAdd( x + 1, y, board[x][y].val ) ) return true;
|
||||
if( testAdd( x - 1, y, board[x][y].val ) ) return true;
|
||||
if( testAdd( x, y + 1, board[x][y].val ) ) return true;
|
||||
if( testAdd( x, y - 1, board[x][y].val ) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool testAdd( int x, int y, uint v )
|
||||
{
|
||||
if( x < 0 || x > 3 || y < 0 || y > 3 ) return false;
|
||||
return board[x][y].val == v;
|
||||
}
|
||||
void moveVert( int x, int y, int d )
|
||||
{
|
||||
if( board[x][y + d].val && board[x][y + d].val == board[x][y].val && !board[x][y].blocked && !board[x][y + d].blocked )
|
||||
{
|
||||
board[x][y].val = 0;
|
||||
board[x][y + d].val *= 2;
|
||||
score += board[x][y + d].val;
|
||||
board[x][y + d].blocked = true;
|
||||
moved = true;
|
||||
}
|
||||
else if( !board[x][y + d].val && board[x][y].val )
|
||||
{
|
||||
board[x][y + d].val = board[x][y].val;
|
||||
board[x][y].val = 0;
|
||||
moved = true;
|
||||
}
|
||||
if( d > 0 ) { if( y + d < 3 ) moveVert( x, y + d, 1 ); }
|
||||
else { if( y + d > 0 ) moveVert( x, y + d, -1 ); }
|
||||
}
|
||||
void moveHori( int x, int y, int d )
|
||||
{
|
||||
if( board[x + d][y].val && board[x + d][y].val == board[x][y].val && !board[x][y].blocked && !board[x + d][y].blocked )
|
||||
{
|
||||
board[x][y].val = 0;
|
||||
board[x + d][y].val *= 2;
|
||||
score += board[x + d][y].val;
|
||||
board[x + d][y].blocked = true;
|
||||
moved = true;
|
||||
}
|
||||
else if( !board[x + d][y].val && board[x][y].val )
|
||||
{
|
||||
board[x + d][y].val = board[x][y].val;
|
||||
board[x][y].val = 0;
|
||||
moved = true;
|
||||
}
|
||||
if( d > 0 ) { if( x + d < 3 ) moveHori( x + d, y, 1 ); }
|
||||
else { if( x + d > 0 ) moveHori( x + d, y, -1 ); }
|
||||
}
|
||||
void move( movDir d )
|
||||
{
|
||||
switch( d )
|
||||
{
|
||||
case UP:
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
int y = 1;
|
||||
while( y < 4 )
|
||||
{ if( board[x][y].val ) moveVert( x, y, -1 ); y++;}
|
||||
}
|
||||
break;
|
||||
case DOWN:
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
int y = 2;
|
||||
while( y >= 0 )
|
||||
{ if( board[x][y].val ) moveVert( x, y, 1 ); y--;}
|
||||
}
|
||||
break;
|
||||
case LEFT:
|
||||
for( int y = 0; y < 4; y++ )
|
||||
{
|
||||
int x = 1;
|
||||
while( x < 4 )
|
||||
{ if( board[x][y].val ) moveHori( x, y, -1 ); x++;}
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
for( int y = 0; y < 4; y++ )
|
||||
{
|
||||
int x = 2;
|
||||
while( x >= 0 )
|
||||
{ if( board[x][y].val ) moveHori( x, y, 1 ); x--;}
|
||||
}
|
||||
}
|
||||
}
|
||||
tile board[4][4];
|
||||
bool win, done, moved;
|
||||
uint score;
|
||||
};
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
srand( static_cast<uint>( time( NULL ) ) );
|
||||
g2048 g; g.loop();
|
||||
return system( "pause" );
|
||||
}
|
||||
394
Task/2048/C-sharp/2048.cs
Normal file
394
Task/2048/C-sharp/2048.cs
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
using System;
|
||||
|
||||
namespace g2048_csharp
|
||||
{
|
||||
internal class Tile
|
||||
{
|
||||
public Tile()
|
||||
{
|
||||
Value = 0;
|
||||
IsBlocked = false;
|
||||
}
|
||||
|
||||
public int Value { get; set; }
|
||||
public bool IsBlocked { get; set; }
|
||||
}
|
||||
|
||||
internal enum MoveDirection
|
||||
{
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
internal class G2048
|
||||
{
|
||||
public G2048()
|
||||
{
|
||||
_isDone = false;
|
||||
_isWon = false;
|
||||
_isMoved = true;
|
||||
_score = 0;
|
||||
InitializeBoard();
|
||||
}
|
||||
|
||||
private void InitializeBoard()
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
_board[x, y] = new Tile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isDone;
|
||||
private bool _isWon;
|
||||
private bool _isMoved;
|
||||
private int _score;
|
||||
private readonly Tile[,] _board = new Tile[4, 4];
|
||||
private readonly Random _rand = new Random();
|
||||
|
||||
public void Loop()
|
||||
{
|
||||
AddTile();
|
||||
while (true)
|
||||
{
|
||||
if (_isMoved)
|
||||
{
|
||||
AddTile();
|
||||
}
|
||||
|
||||
DrawBoard();
|
||||
if (_isDone)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
WaitKey();
|
||||
}
|
||||
|
||||
string endMessage = _isWon ? "You've made it!" : "Game Over!";
|
||||
Console.WriteLine(endMessage);
|
||||
}
|
||||
|
||||
private void DrawBoard()
|
||||
{
|
||||
Console.Clear();
|
||||
Console.WriteLine("Score: " + _score + "\n");
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
Console.WriteLine("+------+------+------+------+");
|
||||
Console.Write("| ");
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
if (_board[x, y].Value == 0)
|
||||
{
|
||||
const string empty = " ";
|
||||
Console.Write(empty.PadRight(4));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(_board[x, y].Value.ToString().PadRight(4));
|
||||
}
|
||||
|
||||
Console.Write(" | ");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("+------+------+------+------+\n\n");
|
||||
}
|
||||
|
||||
private void WaitKey()
|
||||
{
|
||||
_isMoved = false;
|
||||
Console.WriteLine("(W) Up (S) Down (A) Left (D) Right");
|
||||
char input;
|
||||
char.TryParse(Console.ReadKey().Key.ToString(), out input);
|
||||
|
||||
switch (input)
|
||||
{
|
||||
case 'W':
|
||||
Move(MoveDirection.Up);
|
||||
break;
|
||||
case 'A':
|
||||
Move(MoveDirection.Left);
|
||||
break;
|
||||
case 'S':
|
||||
Move(MoveDirection.Down);
|
||||
break;
|
||||
case 'D':
|
||||
Move(MoveDirection.Right);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
_board[x, y].IsBlocked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddTile()
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
if (_board[x, y].Value != 0) continue;
|
||||
int a, b;
|
||||
do
|
||||
{
|
||||
a = _rand.Next(0, 4);
|
||||
b = _rand.Next(0, 4);
|
||||
} while (_board[a, b].Value != 0);
|
||||
|
||||
double r = _rand.NextDouble();
|
||||
_board[a, b].Value = r > 0.89f ? 4 : 2;
|
||||
|
||||
if (CanMove())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isDone = true;
|
||||
}
|
||||
|
||||
private bool CanMove()
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
if (_board[x, y].Value == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
if (TestAdd(x + 1, y, _board[x, y].Value)
|
||||
|| TestAdd(x - 1, y, _board[x, y].Value)
|
||||
|| TestAdd(x, y + 1, _board[x, y].Value)
|
||||
|| TestAdd(x, y - 1, _board[x, y].Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TestAdd(int x, int y, int value)
|
||||
{
|
||||
if (x < 0 || x > 3 || y < 0 || y > 3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _board[x, y].Value == value;
|
||||
}
|
||||
|
||||
private void MoveVertically(int x, int y, int d)
|
||||
{
|
||||
if (_board[x, y + d].Value != 0
|
||||
&& _board[x, y + d].Value == _board[x, y].Value
|
||||
&& !_board[x, y].IsBlocked
|
||||
&& !_board[x, y + d].IsBlocked)
|
||||
{
|
||||
_board[x, y].Value = 0;
|
||||
_board[x, y + d].Value *= 2;
|
||||
_score += _board[x, y + d].Value;
|
||||
_board[x, y + d].IsBlocked = true;
|
||||
_isMoved = true;
|
||||
}
|
||||
else if (_board[x, y + d].Value == 0
|
||||
&& _board[x, y].Value != 0)
|
||||
{
|
||||
_board[x, y + d].Value = _board[x, y].Value;
|
||||
_board[x, y].Value = 0;
|
||||
_isMoved = true;
|
||||
}
|
||||
|
||||
if (d > 0)
|
||||
{
|
||||
if (y + d < 3)
|
||||
{
|
||||
MoveVertically(x, y + d, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y + d > 0)
|
||||
{
|
||||
MoveVertically(x, y + d, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveHorizontally(int x, int y, int d)
|
||||
{
|
||||
if (_board[x + d, y].Value != 0
|
||||
&& _board[x + d, y].Value == _board[x, y].Value
|
||||
&& !_board[x + d, y].IsBlocked
|
||||
&& !_board[x, y].IsBlocked)
|
||||
{
|
||||
_board[x, y].Value = 0;
|
||||
_board[x + d, y].Value *= 2;
|
||||
_score += _board[x + d, y].Value;
|
||||
_board[x + d, y].IsBlocked = true;
|
||||
_isMoved = true;
|
||||
}
|
||||
else if (_board[x + d, y].Value == 0
|
||||
&& _board[x, y].Value != 0)
|
||||
{
|
||||
_board[x + d, y].Value = _board[x, y].Value;
|
||||
_board[x, y].Value = 0;
|
||||
_isMoved = true;
|
||||
}
|
||||
|
||||
if (d > 0)
|
||||
{
|
||||
if (x + d < 3)
|
||||
{
|
||||
MoveHorizontally(x + d, y, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x + d > 0)
|
||||
{
|
||||
MoveHorizontally(x + d, y, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Move(MoveDirection direction)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case MoveDirection.Up:
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
int y = 1;
|
||||
while (y < 4)
|
||||
{
|
||||
if (_board[x, y].Value != 0)
|
||||
{
|
||||
MoveVertically(x, y, -1);
|
||||
}
|
||||
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MoveDirection.Down:
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
int y = 2;
|
||||
while (y >= 0)
|
||||
{
|
||||
if (_board[x, y].Value != 0)
|
||||
{
|
||||
MoveVertically(x, y, 1);
|
||||
}
|
||||
|
||||
y--;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MoveDirection.Left:
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
int x = 1;
|
||||
while (x < 4)
|
||||
{
|
||||
if (_board[x, y].Value != 0)
|
||||
{
|
||||
MoveHorizontally(x, y, -1);
|
||||
}
|
||||
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MoveDirection.Right:
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
int x = 2;
|
||||
while (x >= 0)
|
||||
{
|
||||
if (_board[x, y].Value != 0)
|
||||
{
|
||||
MoveHorizontally(x, y, 1);
|
||||
}
|
||||
|
||||
x--;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
RunGame();
|
||||
}
|
||||
|
||||
private static void RunGame()
|
||||
{
|
||||
G2048 game = new G2048();
|
||||
game.Loop();
|
||||
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
private static void CheckRestart()
|
||||
{
|
||||
Console.WriteLine("(N) New game (P) Exit");
|
||||
while (true)
|
||||
{
|
||||
char input;
|
||||
char.TryParse(Console.ReadKey().Key.ToString(), out input);
|
||||
switch (input)
|
||||
{
|
||||
case 'N':
|
||||
RunGame();
|
||||
break;
|
||||
case 'P':
|
||||
return;
|
||||
default:
|
||||
ClearLastLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearLastLine()
|
||||
{
|
||||
Console.SetCursorPosition(0, Console.CursorTop);
|
||||
Console.Write(new string(' ', Console.BufferWidth));
|
||||
Console.SetCursorPosition(0, Console.CursorTop - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
279
Task/2048/C/2048-1.c
Normal file
279
Task/2048/C/2048-1.c
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define D_INVALID -1
|
||||
#define D_UP 1
|
||||
#define D_DOWN 2
|
||||
#define D_RIGHT 3
|
||||
#define D_LEFT 4
|
||||
|
||||
const long values[] = {
|
||||
0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048
|
||||
};
|
||||
|
||||
const char *colors[] = {
|
||||
"39", "31", "32", "33", "34", "35", "36", "37", "91", "92", "93", "94"
|
||||
};
|
||||
|
||||
struct gamestate_struct__ {
|
||||
int grid[4][4];
|
||||
int have_moved;
|
||||
long total_score;
|
||||
long score_last_move;
|
||||
int blocks_in_play;
|
||||
} game;
|
||||
|
||||
struct termios oldt, newt;
|
||||
|
||||
void do_draw(void)
|
||||
{
|
||||
printf("\033[2J\033[HScore: %ld", game.total_score);
|
||||
if (game.score_last_move)
|
||||
printf(" (+%ld)", game.score_last_move);
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 25; ++i)
|
||||
printf("-");
|
||||
printf("\n");
|
||||
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
printf("|");
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
if (game.grid[x][y])
|
||||
printf("\033[7m\033[%sm%*zd \033[0m|", colors[game.grid[x][y]],
|
||||
4, values[game.grid[x][y]]);
|
||||
else
|
||||
printf("%*s |", 4, "");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
printf("-");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void do_merge(int d)
|
||||
{
|
||||
/* These macros look pretty scary, but mainly demonstrate some space saving */
|
||||
#define MERGE_DIRECTION(_v1, _v2, _xs, _xc, _xi, _ys, _yc, _yi, _x, _y) \
|
||||
do { \
|
||||
for (int _v1 = _xs; _v1 _xc; _v1 += _xi) { \
|
||||
for (int _v2 = _ys; _v2 _yc; _v2 += _yi) { \
|
||||
if (game.grid[x][y] && (game.grid[x][y] == \
|
||||
game.grid[x + _x][y + _y])) { \
|
||||
game.grid[x][y] += (game.have_moved = 1); \
|
||||
game.grid[x + _x][y + _y] = (0 * game.blocks_in_play--);\
|
||||
game.score_last_move += values[game.grid[x][y]]; \
|
||||
game.total_score += values[game.grid[x][y]]; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
game.score_last_move = 0;
|
||||
|
||||
switch (d) {
|
||||
case D_LEFT:
|
||||
MERGE_DIRECTION(x, y, 0, < 3, 1, 0, < 4, 1, 1, 0);
|
||||
break;
|
||||
case D_RIGHT:
|
||||
MERGE_DIRECTION(x, y, 3, > 0, -1, 0, < 4, 1, -1, 0);
|
||||
break;
|
||||
case D_DOWN:
|
||||
MERGE_DIRECTION(y, x, 3, > 0, -1, 0, < 4, 1, 0, -1);
|
||||
break;
|
||||
case D_UP:
|
||||
MERGE_DIRECTION(y, x, 0, < 3, 1, 0, < 4, 1, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef MERGE_DIRECTION
|
||||
}
|
||||
|
||||
void do_gravity(int d)
|
||||
{
|
||||
#define GRAVITATE_DIRECTION(_v1, _v2, _xs, _xc, _xi, _ys, _yc, _yi, _x, _y) \
|
||||
do { \
|
||||
int break_cond = 0; \
|
||||
while (!break_cond) { \
|
||||
break_cond = 1; \
|
||||
for (int _v1 = _xs; _v1 _xc; _v1 += _xi) { \
|
||||
for (int _v2 = _ys; _v2 _yc; _v2 += _yi) { \
|
||||
if (!game.grid[x][y] && game.grid[x + _x][y + _y]) { \
|
||||
game.grid[x][y] = game.grid[x + _x][y + _y]; \
|
||||
game.grid[x + _x][y + _y] = break_cond = 0; \
|
||||
game.have_moved = 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
do_draw(); usleep(40000); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
switch (d) {
|
||||
case D_LEFT:
|
||||
GRAVITATE_DIRECTION(x, y, 0, < 3, 1, 0, < 4, 1, 1, 0);
|
||||
break;
|
||||
case D_RIGHT:
|
||||
GRAVITATE_DIRECTION(x, y, 3, > 0, -1, 0, < 4, 1, -1, 0);
|
||||
break;
|
||||
case D_DOWN:
|
||||
GRAVITATE_DIRECTION(y, x, 3, > 0, -1, 0, < 4, 1, 0, -1);
|
||||
break;
|
||||
case D_UP:
|
||||
GRAVITATE_DIRECTION(y, x, 0, < 3, 1, 0, < 4, 1, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef GRAVITATE_DIRECTION
|
||||
}
|
||||
|
||||
int do_check_end_condition(void)
|
||||
{
|
||||
int ret = -1;
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
if (values[game.grid[x][y]] == 2048)
|
||||
return 1;
|
||||
if (!game.grid[x][y] ||
|
||||
((x + 1 < 4) && (game.grid[x][y] == game.grid[x + 1][y])) ||
|
||||
((y + 1 < 4) && (game.grid[x][y] == game.grid[x][y + 1])))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_tick(int d)
|
||||
{
|
||||
game.have_moved = 0;
|
||||
do_gravity(d);
|
||||
do_merge(d);
|
||||
do_gravity(d);
|
||||
return game.have_moved;
|
||||
}
|
||||
|
||||
void do_newblock(void) {
|
||||
if (game.blocks_in_play >= 16) return;
|
||||
|
||||
int bn = rand() % (16 - game.blocks_in_play);
|
||||
int pn = 0;
|
||||
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
if (game.grid[x][y])
|
||||
continue;
|
||||
|
||||
if (pn == bn){
|
||||
game.grid[x][y] = rand() % 10 ? 1 : 2;
|
||||
game.blocks_in_play += 1;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
++pn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Initialize terminal settings */
|
||||
tcgetattr(STDIN_FILENO, &oldt);
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||
|
||||
srand(time(NULL));
|
||||
memset(&game, 0, sizeof(game));
|
||||
do_newblock();
|
||||
do_newblock();
|
||||
do_draw();
|
||||
|
||||
while (1) {
|
||||
int found_valid_key, direction, value;
|
||||
do {
|
||||
found_valid_key = 1;
|
||||
direction = D_INVALID;
|
||||
value = getchar();
|
||||
switch (value) {
|
||||
case 'h': case 'a':
|
||||
direction = D_LEFT;
|
||||
break;
|
||||
case 'l': case 'd':
|
||||
direction = D_RIGHT;
|
||||
break;
|
||||
case 'j': case 's':
|
||||
direction = D_DOWN;
|
||||
break;
|
||||
case 'k': case 'w':
|
||||
direction = D_UP;
|
||||
break;
|
||||
case 'q':
|
||||
goto game_quit;
|
||||
break;
|
||||
case 27:
|
||||
if (getchar() == 91) {
|
||||
value = getchar();
|
||||
switch (value) {
|
||||
case 65:
|
||||
direction = D_UP;
|
||||
break;
|
||||
case 66:
|
||||
direction = D_DOWN;
|
||||
break;
|
||||
case 67:
|
||||
direction = D_RIGHT;
|
||||
break;
|
||||
case 68:
|
||||
direction = D_LEFT;
|
||||
break;
|
||||
default:
|
||||
found_valid_key = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
found_valid_key = 0;
|
||||
break;
|
||||
}
|
||||
} while (!found_valid_key);
|
||||
|
||||
do_tick(direction);
|
||||
if (game.have_moved != 0){
|
||||
do_newblock();
|
||||
}
|
||||
do_draw();
|
||||
|
||||
switch (do_check_end_condition()) {
|
||||
case -1:
|
||||
goto game_lose;
|
||||
case 1:
|
||||
goto game_win;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0)
|
||||
game_lose:
|
||||
printf("You lose!\n");
|
||||
goto game_quit;
|
||||
if (0)
|
||||
game_win:
|
||||
printf("You win!\n");
|
||||
goto game_quit;
|
||||
if (0)
|
||||
game_quit:
|
||||
|
||||
/* Restore terminal settings */
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
return 0;
|
||||
}
|
||||
340
Task/2048/C/2048-2.c
Normal file
340
Task/2048/C/2048-2.c
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#define EMPTY_TILE 0
|
||||
#define ROWS 4
|
||||
#define COLUMNS 4
|
||||
|
||||
|
||||
/*
|
||||
* GENERAL CONCEPT
|
||||
*
|
||||
* How do you add up tiles when there is whitespace between them?
|
||||
* You sort the array so that there are no empty tiles between them while stacking them all to one side
|
||||
* then the addition function always adds up from left to right or up to bottom. It does not care
|
||||
* about the left movements or the down movement. This can be achieved by reversing the array
|
||||
* whenever the player chooses to move to the right or down, when the addition is finished
|
||||
* the array gets reversed back and its like it had been added from right to left or bottom to top
|
||||
* When the addition is done, the program scans for the number of empty tiles and uses that
|
||||
* in its selection of the next tile to be filled. 10% of times a tile gets occupied with a 4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* the remove_whitespace functions; it is pretty clear what they do.
|
||||
* they use a bubble short algorith to move the 0's or empty tiles to the end of the array
|
||||
* depending on the direction moved (without carring about going right or up
|
||||
*
|
||||
*/
|
||||
|
||||
void remove_whitespace_horizontaly(int board[ROWS][COLUMNS], int rows, int columns)
|
||||
{
|
||||
int a = columns;
|
||||
int tmp;
|
||||
|
||||
|
||||
for (; a < COLUMNS - 1; ++a) {
|
||||
tmp = board[rows][a];
|
||||
board[rows][a] = board[rows][a+1];
|
||||
board[rows][a+1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_whitespace_verticaly(int board[ROWS][COLUMNS], int columns, int rows)
|
||||
{
|
||||
int a = rows;
|
||||
int tmp;
|
||||
|
||||
for (; a < ROWS - 1; ++a) {
|
||||
tmp = board[a][columns];
|
||||
board[a][columns] = board[a+1][columns];
|
||||
board[a+1][columns] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the add_tiles functions. those functions do the heavy work of adding the tiles and
|
||||
* taking care of special situations such as when adding two equal tiles a 0 gets generated
|
||||
* they are quite difficult to understand i think (which means not that you need to be too clever
|
||||
* but that i have done a poor job of creating them) and it took around 4 hours to get the
|
||||
* proper result
|
||||
*/
|
||||
|
||||
void add_tiles_horizontaly(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, flag;
|
||||
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
for (b = 0, flag = 0; b < COLUMNS - 1 && flag != 4; ++b) {
|
||||
if (board[a][b] == EMPTY_TILE) {
|
||||
remove_whitespace_horizontaly(board, a, b);
|
||||
--b;
|
||||
++flag;
|
||||
}
|
||||
else {
|
||||
if (board[a][b+1] == EMPTY_TILE) {
|
||||
board[a][b+1] = board[a][b];
|
||||
board[a][b] = EMPTY_TILE;
|
||||
--b;
|
||||
} else if (board[a][b] == board[a][b+1]) {
|
||||
board[a][b] += board[a][b+1];
|
||||
board[a][b+1] = EMPTY_TILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_tiles_verticaly(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, flag;
|
||||
|
||||
for (a = 0; a < COLUMNS; ++a) {
|
||||
for (b = 0, flag = 0; b < ROWS-1 && flag != 4; ++b) {
|
||||
if (board[b][a] == EMPTY_TILE) {
|
||||
remove_whitespace_verticaly(board, a, b);
|
||||
--b;
|
||||
++flag;
|
||||
}
|
||||
else {
|
||||
if (board[b+1][a] == EMPTY_TILE) {
|
||||
board[b+1][a] = board[b][a];
|
||||
board[b][a] = EMPTY_TILE;
|
||||
--b;
|
||||
} else if (board[b][a] == board[b+1][a]) {
|
||||
board[b][a] += board[b+1][a];
|
||||
board[b+1][a] = EMPTY_TILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ... print the board
|
||||
*/
|
||||
|
||||
void print_board(int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b;
|
||||
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
printf("\n");
|
||||
for (b = 0; b < COLUMNS; ++b) {
|
||||
printf("%5i", board[a][b]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The reverse_board function reverses the array
|
||||
* if the movement is right or down reverse the array
|
||||
*/
|
||||
|
||||
void reverse_board(char input[], int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b, c, tmp;
|
||||
|
||||
if (!strcmp(input, "right")) {
|
||||
for (a = 0; a < ROWS; ++a) {
|
||||
for (b = 0, c = 3; b < 2; ++b, --c) {
|
||||
tmp = board[a][b];
|
||||
board[a][b] = board[a][c];
|
||||
board[a][c] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(input, "down")) {
|
||||
for (a = 0; a < COLUMNS; ++a) {
|
||||
for (b = 0, c = 3; b < 2; ++b, --c) {
|
||||
tmp = board[b][a];
|
||||
board[b][a] = board[c][a];
|
||||
board[c][a] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the check_board function is the one which evaluates the win or lose condition
|
||||
* for each turn and at the same time providing the number of empty tiles for the random generator
|
||||
* function
|
||||
*/
|
||||
|
||||
int check_board (int board[ROWS][COLUMNS])
|
||||
{
|
||||
int a, b;
|
||||
|
||||
int result = 0;
|
||||
int empty_tiles = 0;
|
||||
|
||||
|
||||
for (a = 0; a < ROWS; ++a)
|
||||
for (b = 0; b < COLUMNS; ++b)
|
||||
if (board[a][b] == 2048)
|
||||
result = -1;
|
||||
else if (board[a][b] == EMPTY_TILE)
|
||||
++empty_tiles;
|
||||
|
||||
result = result == -1 ? result : empty_tiles;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* the generate_random functin generates a random number between 0 and the number of
|
||||
* empty tiles. the generated number will assign to the Nth empty tile = (random_number)
|
||||
* the new value, it also takes care of the 10% chance for producing a 4 tile
|
||||
*/
|
||||
|
||||
void generate_random(int board[ROWS][COLUMNS], int empty_tiles )
|
||||
{
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
int a, b;
|
||||
int random = 0;
|
||||
int tile = 0;
|
||||
|
||||
random = rand() % empty_tiles;
|
||||
tile = (rand() % 9 == 4) ? 4 : 2;
|
||||
|
||||
for (a = 0; a < ROWS; ++a)
|
||||
for (b = 0; b < COLUMNS; ++b)
|
||||
if (board[a][b] == EMPTY_TILE && random != 0)
|
||||
--random;
|
||||
else if (board[a][b] == EMPTY_TILE && random == 0) {
|
||||
board[a][b] = tile;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* infinite loop, get the movements or exit code and act accordingly
|
||||
*/
|
||||
|
||||
int play_game(int board[ROWS][COLUMNS])
|
||||
{
|
||||
|
||||
char movement[81];
|
||||
int tiles = 0;
|
||||
|
||||
printf("this is the 2048 game\n" \
|
||||
"The goal of this game is make a tile reach the value of 2048\n"\
|
||||
"The board starts of with only one occupied tile.\n"\
|
||||
"On each round a new tile gets added with the value of 2\n"\
|
||||
"or at 10%% of the times with the value of 4\n"\
|
||||
"If you run out of tiles you lose\n"\
|
||||
"There are 4 movements you can supply to the game\n"\
|
||||
"right, left, up, and down.\n"\
|
||||
"For each of this movements the tiles move to the direction specified\n"\
|
||||
"If two tiles have the same value the get added up just once.\n"\
|
||||
"If 2 occupied tiles share the same row or column but are seperated by empty tiles\n"\
|
||||
"then the occupied tiles travel along the empty tiles stacking in the direction\n"\
|
||||
"they were directed\n"\
|
||||
"For a more visual explanation you can check the wikipedia entry\n"
|
||||
" if you search for 2058 board game\n" \
|
||||
"Here we go\n");
|
||||
|
||||
print_board(board);
|
||||
while (1) {
|
||||
printf("(enter: left,right,up,down,exit)>> ");
|
||||
scanf("%s", movement);
|
||||
if (!strcmp(movement, "down")) {
|
||||
reverse_board(movement,board);
|
||||
add_tiles_verticaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
reverse_board(movement, board);
|
||||
}
|
||||
else if (!strcmp(movement, "up")) {
|
||||
add_tiles_verticaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
}
|
||||
else if (!strcmp(movement, "right")) {
|
||||
reverse_board(movement,board);
|
||||
add_tiles_horizontaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
reverse_board(movement, board);
|
||||
}
|
||||
else if (!strcmp(movement, "left")) {
|
||||
add_tiles_horizontaly(board);
|
||||
tiles = check_board(board);
|
||||
if (tiles == -1)
|
||||
return -1;
|
||||
else if (tiles == 0)
|
||||
return 0;
|
||||
generate_random(board,tiles);
|
||||
}
|
||||
else if (!strcmp(movement, "exit")) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("Do not recognize this movement please type again\n");
|
||||
continue;
|
||||
}
|
||||
print_board(board);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int play_game(int board[ROWS][COLUMNS]);
|
||||
void generate_random(int board[ROWS][COLUMNS], int empty_tiles );
|
||||
int check_board (int board[ROWS][COLUMNS]);
|
||||
void reverse_board(char input[], int board[ROWS][COLUMNS]);
|
||||
void print_board(int board[ROWS][COLUMNS]);
|
||||
void add_tiles_verticaly(int board[ROWS][COLUMNS]);
|
||||
void add_tiles_horizontaly(int board[ROWS][COLUMNS]);
|
||||
void remove_whitespace_verticaly(int board[ROWS][COLUMNS], int columns, int rows);
|
||||
void remove_whitespace_horizontaly(int board[ROWS][COLUMNS], int rows, int columns);
|
||||
|
||||
int win_condition;
|
||||
int board[ROWS][COLUMNS] = {
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,0,0},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
|
||||
generate_random(board, 16); /* initialize the board */
|
||||
|
||||
win_condition = play_game(board);
|
||||
switch (win_condition) {
|
||||
case 1:
|
||||
printf("But you are not done yet!!!\n" \
|
||||
"Fine, see you another day\n");
|
||||
break;
|
||||
case 0:
|
||||
printf("Ohh noo, you run out of tiles\n" \
|
||||
"Run me agan to play some more\n" \
|
||||
"Byyyeee\n");
|
||||
break;
|
||||
case -1:
|
||||
printf("WooooW you did it, Good job!!!\n" \
|
||||
"See ya later homie\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
119
Task/2048/Clojure/2048.clj
Normal file
119
Task/2048/Clojure/2048.clj
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
(ns 2048
|
||||
(:require [clojure.string :as str]))
|
||||
|
||||
;Preferences
|
||||
(def textures {:wall "----+"
|
||||
:cell "%4s|"
|
||||
:cell-edge "|"
|
||||
:wall-edge "+"})
|
||||
|
||||
(def directions {:w :up
|
||||
:s :down
|
||||
:a :left
|
||||
:d :right})
|
||||
|
||||
(def field-size {:y 4 :x 4})
|
||||
|
||||
;Output
|
||||
(defn cells->str [line]
|
||||
(str (:cell-edge textures)
|
||||
(str/join (map (partial format (:cell textures)) line))
|
||||
"\n"))
|
||||
|
||||
(defn walls->str [width]
|
||||
(str (:wall-edge textures)
|
||||
(str/join (repeat width (:wall textures)))
|
||||
"\n"))
|
||||
|
||||
(defn field->str [field]
|
||||
(let [height (count field)
|
||||
width (count (first field))]
|
||||
(str (str/join (interleave (repeat height (walls->str width))
|
||||
(map cells->str field)))
|
||||
(walls->str width))))
|
||||
|
||||
;Misc
|
||||
(defn handle-input []
|
||||
(let [input (read)
|
||||
try-dir ((keyword input) directions)]
|
||||
(if try-dir try-dir (recur))))
|
||||
|
||||
(defn get-columns [field]
|
||||
(vec (for [x (range (count (first field)))]
|
||||
(vec (for [y (range (count field))]
|
||||
(get-in field [y x]))))))
|
||||
|
||||
(defn reverse-lines [field]
|
||||
(mapv #(vec (reverse %)) field))
|
||||
|
||||
(defn padding [coll n sym]
|
||||
(vec (concat coll (repeat n sym))))
|
||||
|
||||
(defn find-empties [field]
|
||||
(remove
|
||||
nil?
|
||||
(for [y (range (count field))
|
||||
x (range (count (nth field y)))]
|
||||
(when (= (get-in field [y x]) \space) [y x]))))
|
||||
|
||||
(defn random-add [field]
|
||||
(let [empties (vec (find-empties field))]
|
||||
(assoc-in field
|
||||
(rand-nth empties)
|
||||
(rand-nth (conj (vec (repeat 9 2)) 4)))))
|
||||
|
||||
(defn win-check [field]
|
||||
(= 2048
|
||||
(transduce
|
||||
(filter number?)
|
||||
(completing max)
|
||||
0
|
||||
(flatten field))))
|
||||
|
||||
(defn lose-check [field]
|
||||
(empty? (filter (partial = \space) (flatten field))))
|
||||
|
||||
(defn create-start-field [y x]
|
||||
(->> (vec (repeat y (vec (repeat x \space))))
|
||||
(random-add)
|
||||
(random-add)))
|
||||
|
||||
;Algo
|
||||
(defn lines-by-dir [back? direction field]
|
||||
(case direction
|
||||
:left field
|
||||
:right (reverse-lines field)
|
||||
:down (if back?
|
||||
(get-columns (reverse-lines field))
|
||||
(reverse-lines (get-columns field)))
|
||||
:up (get-columns field)))
|
||||
|
||||
(defn shift-line [line]
|
||||
(let [len (count line)
|
||||
line (vec (filter number? line))
|
||||
max-idx (dec (count line))]
|
||||
(loop [new [] idx 0]
|
||||
(if (> idx max-idx)
|
||||
(padding new (- len (count new)) \space)
|
||||
(if (= (nth line idx) (get line (inc idx)))
|
||||
(recur (conj new (* 2 (nth line idx))) (+ 2 idx))
|
||||
(recur (conj new (nth line idx)) (inc idx)))))))
|
||||
|
||||
(defn shift-field [direction field]
|
||||
(->> (lines-by-dir false direction field)
|
||||
(mapv shift-line)
|
||||
(lines-by-dir true direction)))
|
||||
|
||||
(defn handle-turn [field]
|
||||
(let [direction (handle-input)]
|
||||
(->> (shift-field direction field)
|
||||
(random-add))))
|
||||
|
||||
(defn play-2048 []
|
||||
(loop [field (create-start-field (:y field-size) (:x field-size))]
|
||||
(println (field->str field))
|
||||
(cond (win-check field) (println "You win")
|
||||
(lose-check field) (println "You lose")
|
||||
:default (recur (handle-turn field)))))
|
||||
|
||||
(play-2048)
|
||||
201
Task/2048/Common-Lisp/2048.lisp
Normal file
201
Task/2048/Common-Lisp/2048.lisp
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
(ql:quickload '(cffi alexandria))
|
||||
|
||||
(defpackage :2048-lisp
|
||||
(:use :common-lisp :cffi :alexandria))
|
||||
|
||||
(in-package :2048-lisp)
|
||||
|
||||
(defvar *lib-loaded* nil)
|
||||
|
||||
(unless *lib-loaded*
|
||||
;; Load msvcrt.dll to access _getch.
|
||||
(define-foreign-library msvcrt
|
||||
(:windows (:default "msvcrt")))
|
||||
|
||||
(use-foreign-library msvcrt)
|
||||
|
||||
(defcfun "_getch" :int)
|
||||
|
||||
(setf *lib-loaded* t))
|
||||
|
||||
(defun read-arrow ()
|
||||
"Get an arrow key from input as UP, DOWN, LEFT, or RIGHT, otherwise
|
||||
return a char of whatever was pressed."
|
||||
(let ((first-char (-getch)))
|
||||
(if (= 224 first-char)
|
||||
(case (-getch)
|
||||
(75 'left)
|
||||
(80 'down)
|
||||
(77 'right)
|
||||
(72 'up))
|
||||
(code-char first-char))))
|
||||
|
||||
(defmacro swap (place1 place2)
|
||||
"Exchange the values of two places."
|
||||
(let ((temp (gensym "TEMP")))
|
||||
`(cl:let ((,temp ,place1))
|
||||
(cl:setf ,place1 ,place2)
|
||||
(cl:setf ,place2 ,temp))))
|
||||
|
||||
(defun nflip (board &optional (left-right t))
|
||||
"Flip the elements of a BOARD left and right or optionally up and down."
|
||||
(let* ((y-len (array-dimension board 0))
|
||||
(x-len (array-dimension board 1))
|
||||
(y-max (if left-right y-len (truncate y-len 2)))
|
||||
(x-max (if left-right (truncate x-len 2) x-len)))
|
||||
(loop for y from 0 below y-max
|
||||
for y-place = (- y-len 1 y) do
|
||||
(loop for x from 0 below x-max
|
||||
for x-place = (- x-len 1 x) do
|
||||
(if left-right
|
||||
(swap (aref board y x) (aref board y x-place))
|
||||
(swap (aref board y x) (aref board y-place x)))))
|
||||
board))
|
||||
|
||||
(defun flip (board &optional (left-right t))
|
||||
"Flip the elements of a BOARD left and right or optionally up and down.
|
||||
Non-destructive version."
|
||||
(nflip (copy-array board) left-right))
|
||||
|
||||
(defun transpose (board)
|
||||
"Transpose the elements of BOARD into a new array."
|
||||
(let* ((y-len (array-dimension board 0))
|
||||
(x-len (array-dimension board 1))
|
||||
(new-board (make-array (reverse (array-dimensions board)))))
|
||||
(loop for y from 0 below y-len do
|
||||
(loop for x from 0 below x-len do
|
||||
(setf (aref new-board x y) (aref board y x))))
|
||||
new-board))
|
||||
|
||||
(defun add-random-piece (board)
|
||||
"Find a random empty spot on the BOARD to add a new piece.
|
||||
Return T if successful, NIL otherwise."
|
||||
(loop
|
||||
for x from 0 below (array-total-size board)
|
||||
unless (row-major-aref board x)
|
||||
count 1 into count
|
||||
and collect x into indices
|
||||
finally
|
||||
(unless (= 0 count)
|
||||
(setf (row-major-aref board (nth (random count) indices))
|
||||
(if (= 0 (random 10)) 4 2))
|
||||
(return t))))
|
||||
|
||||
(defun squash-line (line)
|
||||
"Reduce a sequence of numbers from left to right according to
|
||||
the rules of 2048. Return the score of squashing as well."
|
||||
(let* ((squashed
|
||||
(reduce
|
||||
(lambda (acc x)
|
||||
(if (equal x (car acc))
|
||||
(cons (list (* 2 x)) (cdr acc))
|
||||
(cons x acc)))
|
||||
(nreverse (remove-if #'null line))
|
||||
:initial-value nil))
|
||||
(new-line (flatten squashed)))
|
||||
(list (append (make-list (- (length line) (length new-line))) new-line)
|
||||
(reduce #'+ (flatten (remove-if-not #'listp squashed))))))
|
||||
|
||||
(defun squash-board (board)
|
||||
"Reduce each row of a board from left to right according to
|
||||
the rules of 2048. Return the total score of squashing the board as well."
|
||||
(let ((y-len (array-dimension board 0))
|
||||
(x-len (array-dimension board 1))
|
||||
(total 0))
|
||||
(list (make-array (array-dimensions board) :initial-contents
|
||||
(loop for y from 0 below y-len
|
||||
for (line score) =
|
||||
(squash-line
|
||||
(make-array x-len
|
||||
:displaced-to board
|
||||
:displaced-index-offset
|
||||
(array-row-major-index board y 0)))
|
||||
collect line
|
||||
do (incf total score)))
|
||||
total)))
|
||||
|
||||
(defun make-move (board direction)
|
||||
"Make a move in the given DIRECTION on a new board."
|
||||
;; Move by always squashing right, but transforming the board as needed.
|
||||
(destructuring-bind (new-board score)
|
||||
(case direction
|
||||
(up (squash-board (flip (transpose board))))
|
||||
(down (squash-board (flip (transpose board) nil)))
|
||||
(left (squash-board (nflip (flip board nil))))
|
||||
(right (squash-board board)))
|
||||
(let ((new-board
|
||||
;; Reverse the transformation.
|
||||
(case direction
|
||||
(up (transpose (nflip new-board)))
|
||||
(down (transpose (nflip new-board nil)))
|
||||
(left (nflip (nflip new-board nil)))
|
||||
(right new-board))))
|
||||
(unless (equalp board new-board)
|
||||
(add-random-piece new-board)
|
||||
(list new-board score)))))
|
||||
|
||||
(defun winp (board winning-tile)
|
||||
"Determine if a BOARD is in a winning state."
|
||||
(loop for x from 0 below (array-total-size board)
|
||||
for val = (row-major-aref board x)
|
||||
when (eql val winning-tile) do (return t)))
|
||||
|
||||
(defun game-overp (board)
|
||||
"Determine if a BOARD is in a game over state."
|
||||
;; If a move is simulated in every direction and nothing changes,
|
||||
;; then we can assume there are no valid moves left.
|
||||
(notany (lambda (dir) (car (make-move board dir)))
|
||||
'(up down left right)))
|
||||
|
||||
(defun print-divider (cells cell-size)
|
||||
"A print helper function for PRINT-BOARD."
|
||||
(dotimes (_ cells)
|
||||
(princ "+")
|
||||
(dotimes (_ cell-size)
|
||||
(princ "-")))
|
||||
(princ "+")
|
||||
(terpri))
|
||||
|
||||
(defun print-board (board cell-size)
|
||||
"Pretty print the given BOARD with a particular CELL-SIZE."
|
||||
(let* ((y-len (array-dimension board 0))
|
||||
(x-len (array-dimension board 1))
|
||||
(super-size (+ 2 cell-size)))
|
||||
(loop for y from 0 below y-len do
|
||||
(print-divider x-len super-size)
|
||||
(loop for x from 0 below x-len
|
||||
for val = (aref board y x)
|
||||
do
|
||||
(princ "|")
|
||||
(if val
|
||||
(format t " ~VD " cell-size val)
|
||||
(dotimes (_ super-size) (princ " "))))
|
||||
(princ "|")
|
||||
(terpri))
|
||||
(print-divider x-len super-size)))
|
||||
|
||||
(defun init-board ()
|
||||
(let ((board (make-array '(4 4) :initial-element nil)))
|
||||
(setf (row-major-aref board (random (array-total-size board))) 2)
|
||||
board))
|
||||
|
||||
(defun prompt-input (board score &optional (check t))
|
||||
(cond
|
||||
((and check (winp board 2048)) (format t "You win!"))
|
||||
((and check (game-overp board)) (format t "Game over..."))
|
||||
(t (let ((choice (read-arrow)))
|
||||
(cond
|
||||
((symbolp choice)
|
||||
(destructuring-bind (&optional move (new-score 0))
|
||||
(make-move board choice)
|
||||
(if move
|
||||
(prompt move (+ score new-score))
|
||||
(prompt-input board score))))
|
||||
((find choice "qQ")
|
||||
(format t "Quitting."))
|
||||
(t (prompt-input board score nil)))))))
|
||||
|
||||
(defun prompt (&optional (board (init-board)) (score 0))
|
||||
(format t "~% Score: ~D~%" score)
|
||||
(print-board board 4)
|
||||
(prompt-input board score))
|
||||
192
Task/2048/D/2048.d
Normal file
192
Task/2048/D/2048.d
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
import std.stdio, std.string, std.random;
|
||||
import core.stdc.stdlib: exit;
|
||||
|
||||
struct G2048 {
|
||||
void gameLoop() {
|
||||
addTile;
|
||||
while (true) {
|
||||
if (moved)
|
||||
addTile;
|
||||
drawBoard;
|
||||
if (done)
|
||||
break;
|
||||
waitKey;
|
||||
}
|
||||
writeln(win ? "You win!" : "Game Over!");
|
||||
}
|
||||
|
||||
private:
|
||||
struct Tile {
|
||||
uint val = 0;
|
||||
bool blocked = false;
|
||||
}
|
||||
|
||||
enum moveDir { up, down, left, right }
|
||||
enum uint side = 4;
|
||||
|
||||
Tile[side][side] board;
|
||||
bool win = false, done = false, moved = true;
|
||||
uint score = 0;
|
||||
|
||||
void drawBoard() const {
|
||||
writeln("SCORE: ", score, "\n");
|
||||
foreach (y; 0 .. side) {
|
||||
write("+------+------+------+------+\n| ");
|
||||
foreach (x; 0 .. side) {
|
||||
if (board[x][y].val)
|
||||
writef("%4d", board[x][y].val);
|
||||
else
|
||||
writef("%4s", " ");
|
||||
write(" | ");
|
||||
}
|
||||
writeln;
|
||||
}
|
||||
writeln("+------+------+------+------+\n");
|
||||
}
|
||||
|
||||
void waitKey() /*@safe*/ {
|
||||
moved = false;
|
||||
write("(W)Up (S)Down (A)Left (D)Right (Q)Quit: ");
|
||||
auto c = readln.strip.toLower;
|
||||
|
||||
switch (c) {
|
||||
case "w": move(moveDir.up); break;
|
||||
case "a": move(moveDir.left); break;
|
||||
case "s": move(moveDir.down); break;
|
||||
case "d": move(moveDir.right); break;
|
||||
case "q": endGame; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
foreach (y; 0 .. side)
|
||||
foreach (x; 0 .. side)
|
||||
board[x][y].blocked = false;
|
||||
}
|
||||
|
||||
void endGame() const {
|
||||
writeln("Game ended with score: ", score);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void addTile() {
|
||||
foreach (y; 0 .. side) {
|
||||
foreach (x; 0 .. side) {
|
||||
if (!board[x][y].val) {
|
||||
uint a, b;
|
||||
do {
|
||||
a = uniform(0, side);
|
||||
b = uniform(0, side);
|
||||
} while (board[a][b].val);
|
||||
|
||||
board[a][b].val = (uniform01 > 0.89) ? side : 2;
|
||||
if (canMove)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
|
||||
bool canMove() const {
|
||||
foreach (y; 0 .. side)
|
||||
foreach (x; 0 .. side)
|
||||
if (!board[x][y].val)
|
||||
return true;
|
||||
|
||||
foreach (y; 0 .. side) {
|
||||
foreach (x; 0 .. side) {
|
||||
if (testAdd(x + 1, y, board[x][y].val) ||
|
||||
testAdd(x - 1, y, board[x][y].val) ||
|
||||
testAdd(x, y + 1, board[x][y].val) ||
|
||||
testAdd(x, y - 1, board[x][y].val))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool testAdd(uint x, uint y, uint v) const {
|
||||
if (x > 3 || y > 3)
|
||||
return false;
|
||||
return board[x][y].val == v;
|
||||
}
|
||||
|
||||
void moveVertically(uint x, uint y, uint d) {
|
||||
if (board[x][y + d].val && board[x][y + d].val == board[x][y].val &&
|
||||
!board[x][y].blocked && !board[x][y + d].blocked) {
|
||||
board[x][y].val = 0;
|
||||
board[x][y + d].val *= 2;
|
||||
score += board[x][y + d].val;
|
||||
board[x][y + d].blocked = true;
|
||||
moved = true;
|
||||
} else if (!board[x][y + d].val && board[x][y].val) {
|
||||
board[x][y + d].val = board[x][y].val;
|
||||
board[x][y].val = 0;
|
||||
moved = true;
|
||||
}
|
||||
|
||||
if (d > 0) {
|
||||
if (y + d < 3)
|
||||
moveVertically(x, y + d, 1);
|
||||
} else {
|
||||
if (y + d > 0)
|
||||
moveVertically(x, y + d, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void moveHorizontally(uint x, uint y, uint d) {
|
||||
if (board[x + d][y].val && board[x + d][y].val == board[x][y].val &&
|
||||
!board[x][y].blocked && !board[x + d][y].blocked) {
|
||||
board[x][y].val = 0;
|
||||
board[x + d][y].val *= 2;
|
||||
score += board[x + d][y].val;
|
||||
board[x + d][y].blocked = true;
|
||||
moved = true;
|
||||
} else if (!board[x + d][y].val && board[x][y].val) {
|
||||
board[x + d][y].val = board[x][y].val;
|
||||
board[x][y].val = 0;
|
||||
moved = true;
|
||||
}
|
||||
|
||||
if (d > 0) {
|
||||
if (x + d < 3)
|
||||
moveHorizontally(x + d, y, 1);
|
||||
} else {
|
||||
if (x + d > 0)
|
||||
moveHorizontally(x + d, y, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void move(moveDir d) {
|
||||
final switch (d) with(moveDir) {
|
||||
case up:
|
||||
foreach (x; 0 .. side)
|
||||
foreach (y; 1 .. side)
|
||||
if (board[x][y].val)
|
||||
moveVertically(x, y, -1);
|
||||
break;
|
||||
case down:
|
||||
foreach (x; 0 .. side)
|
||||
foreach_reverse (y; 0 .. 3)
|
||||
if (board[x][y].val)
|
||||
moveVertically(x, y, 1);
|
||||
break;
|
||||
case left:
|
||||
foreach (y; 0 .. side)
|
||||
foreach (x; 1 .. side)
|
||||
if (board[x][y].val)
|
||||
moveHorizontally(x, y, -1);
|
||||
break;
|
||||
case right:
|
||||
foreach (y; 0 .. side)
|
||||
foreach_reverse (x; 0 .. 3)
|
||||
if (board[x][y].val)
|
||||
moveHorizontally(x, y, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main() /*safe*/ {
|
||||
G2048 g;
|
||||
g.gameLoop;
|
||||
}
|
||||
405
Task/2048/Delphi/2048.delphi
Normal file
405
Task/2048/Delphi/2048.delphi
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
program Game2048;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Math,
|
||||
Velthuis.Console;
|
||||
|
||||
type
|
||||
TTile = class
|
||||
Value: integer;
|
||||
IsBlocked: Boolean;
|
||||
constructor Create;
|
||||
end;
|
||||
|
||||
TMoveDirection = (mdUp, mdDown, mdLeft, mdRight);
|
||||
|
||||
TG2048 = class
|
||||
FisDone, FisWon, FisMoved: boolean;
|
||||
Fscore: Cardinal;
|
||||
FBoard: array[0..3, 0..3] of TTile;
|
||||
function GetLine(aType: byte): string;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure InitializeBoard();
|
||||
procedure FinalizeBoard();
|
||||
procedure Loop;
|
||||
procedure DrawBoard();
|
||||
procedure WaitKey();
|
||||
procedure AddTile();
|
||||
function CanMove(): boolean;
|
||||
function TestAdd(x, y, value: Integer): boolean;
|
||||
procedure MoveHorizontally(x, y, d: integer);
|
||||
procedure MoveVertically(x, y, d: integer);
|
||||
procedure Move(direction: TMoveDirection);
|
||||
end;
|
||||
|
||||
|
||||
{ TTile }
|
||||
|
||||
constructor TTile.Create;
|
||||
begin
|
||||
Value := 0;
|
||||
IsBlocked := false;
|
||||
end;
|
||||
|
||||
{ TG2048 }
|
||||
|
||||
procedure TG2048.AddTile;
|
||||
var
|
||||
y, x, a, b: Integer;
|
||||
r: Double;
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
if Fboard[x, y].Value <> 0 then
|
||||
continue;
|
||||
repeat
|
||||
a := random(4);
|
||||
b := random(4);
|
||||
until not (Fboard[a, b].Value <> 0);
|
||||
r := Random;
|
||||
if r > 0.89 then
|
||||
Fboard[a, b].Value := 4
|
||||
else
|
||||
Fboard[a, b].Value := 2;
|
||||
if CanMove() then
|
||||
begin
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
FisDone := true;
|
||||
end;
|
||||
|
||||
function TG2048.CanMove: boolean;
|
||||
var
|
||||
y, x: Integer;
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
if Fboard[x, y].Value = 0 then
|
||||
begin
|
||||
Exit(true);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
if TestAdd(x + 1, y, Fboard[x, y].Value) or TestAdd(x - 1, y, Fboard[x, y].Value)
|
||||
or TestAdd(x, y + 1, Fboard[x, y].Value) or TestAdd(x, y - 1, Fboard[x,
|
||||
y].Value) then
|
||||
begin
|
||||
Exit(true);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
Exit(false);
|
||||
end;
|
||||
|
||||
constructor TG2048.Create;
|
||||
begin
|
||||
FisDone := false;
|
||||
FisWon := false;
|
||||
FisMoved := true;
|
||||
Fscore := 0;
|
||||
InitializeBoard();
|
||||
Randomize;
|
||||
end;
|
||||
|
||||
destructor TG2048.Destroy;
|
||||
begin
|
||||
FinalizeBoard;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TG2048.DrawBoard;
|
||||
var
|
||||
y, x: Integer;
|
||||
color: byte;
|
||||
lineFragment, line: string;
|
||||
begin
|
||||
ClrScr;
|
||||
HighVideo;
|
||||
writeln('Score: ', Fscore: 3, #10);
|
||||
TextBackground(White);
|
||||
TextColor(black);
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
if y = 0 then
|
||||
writeln(GetLine(0))
|
||||
else
|
||||
writeln(GetLine(1));
|
||||
|
||||
Write(' '#$2551' ');
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
if Fboard[x, y].Value = 0 then
|
||||
begin
|
||||
Write(' ');
|
||||
end
|
||||
else
|
||||
begin
|
||||
color := Round(Log2(Fboard[x, y].Value));
|
||||
TextColor(14 - color);
|
||||
Write(Fboard[x, y].Value: 4);
|
||||
TextColor(Black);
|
||||
end;
|
||||
Write(' '#$2551' ');
|
||||
end;
|
||||
writeln(' ');
|
||||
end;
|
||||
writeln(GetLine(2), #10#10);
|
||||
TextBackground(Black);
|
||||
TextColor(White);
|
||||
end;
|
||||
|
||||
procedure TG2048.FinalizeBoard;
|
||||
var
|
||||
y, x: integer;
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
for x := 0 to 3 do
|
||||
FBoard[x, y].Free;
|
||||
end;
|
||||
|
||||
function TG2048.GetLine(aType: byte): string;
|
||||
var
|
||||
fragment, line: string;
|
||||
bgChar, edChar, mdChar: char;
|
||||
begin
|
||||
|
||||
case aType of
|
||||
0:
|
||||
begin
|
||||
bgChar := #$2554;
|
||||
edChar := #$2557;
|
||||
mdChar := #$2566;
|
||||
end;
|
||||
1:
|
||||
begin
|
||||
bgChar := #$2560;
|
||||
edChar := #$2563;
|
||||
mdChar := #$256C;
|
||||
end;
|
||||
|
||||
2:
|
||||
begin
|
||||
bgChar := #$255A;
|
||||
edChar := #$255D;
|
||||
mdChar := #$2569;
|
||||
end;
|
||||
end;
|
||||
fragment := string.create(#$2550, 6);
|
||||
line := fragment + mdChar + fragment + mdChar + fragment + mdChar + fragment;
|
||||
Result := ' '+bgChar + line + edChar + ' ';
|
||||
end;
|
||||
|
||||
procedure TG2048.InitializeBoard;
|
||||
var
|
||||
y, x: integer;
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
for x := 0 to 3 do
|
||||
FBoard[x, y] := TTile.Create;
|
||||
end;
|
||||
|
||||
procedure TG2048.Loop;
|
||||
begin
|
||||
AddTile();
|
||||
while (true) do
|
||||
begin
|
||||
if (FisMoved) then
|
||||
AddTile();
|
||||
|
||||
DrawBoard();
|
||||
if (FisDone) then
|
||||
break;
|
||||
|
||||
WaitKey();
|
||||
end;
|
||||
|
||||
if FisWon then
|
||||
Writeln('You''ve made it!')
|
||||
else
|
||||
Writeln('Game Over!');
|
||||
end;
|
||||
|
||||
procedure TG2048.Move(direction: TMoveDirection);
|
||||
var
|
||||
x, y: Integer;
|
||||
begin
|
||||
case direction of
|
||||
mdUp:
|
||||
begin
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
y := 1;
|
||||
while y < 4 do
|
||||
begin
|
||||
if Fboard[x, y].Value <> 0 then
|
||||
MoveVertically(x, y, -1);
|
||||
Inc(y);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
mdDown:
|
||||
begin
|
||||
for x := 0 to 3 do
|
||||
begin
|
||||
y := 2;
|
||||
while y >= 0 do
|
||||
begin
|
||||
if Fboard[x, y].Value <> 0 then
|
||||
MoveVertically(x, y, 1);
|
||||
Dec(y);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
mdLeft:
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
x := 1;
|
||||
while x < 4 do
|
||||
begin
|
||||
if Fboard[x, y].Value <> 0 then
|
||||
MoveHorizontally(x, y, -1);
|
||||
Inc(x);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
mdRight:
|
||||
begin
|
||||
for y := 0 to 3 do
|
||||
begin
|
||||
x := 2;
|
||||
while x >= 0 do
|
||||
begin
|
||||
if Fboard[x, y].Value <> 0 then
|
||||
MoveHorizontally(x, y, 1);
|
||||
Dec(x);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TG2048.MoveHorizontally(x, y, d: integer);
|
||||
begin
|
||||
if (FBoard[x + d, y].Value <> 0) and (FBoard[x + d, y].Value = FBoard[x, y].Value)
|
||||
and (not FBoard[x + d, y].IsBlocked) and (not FBoard[x, y].IsBlocked) then
|
||||
begin
|
||||
FBoard[x, y].Value := 0;
|
||||
FBoard[x + d, y].Value := FBoard[x + d, y].Value * 2;
|
||||
Fscore := Fscore + (FBoard[x + d, y].Value);
|
||||
FBoard[x + d, y].IsBlocked := true;
|
||||
FisMoved := true;
|
||||
end
|
||||
else if ((FBoard[x + d, y].Value = 0) and (FBoard[x, y].Value <> 0)) then
|
||||
begin
|
||||
FBoard[x + d, y].Value := FBoard[x, y].Value;
|
||||
FBoard[x, y].Value := 0;
|
||||
FisMoved := true;
|
||||
end;
|
||||
if d > 0 then
|
||||
begin
|
||||
if x + d < 3 then
|
||||
begin
|
||||
MoveHorizontally(x + d, y, 1);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if x + d > 0 then
|
||||
begin
|
||||
MoveHorizontally(x + d, y, -1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TG2048.MoveVertically(x, y, d: integer);
|
||||
begin
|
||||
if (Fboard[x, y + d].Value <> 0) and (Fboard[x, y + d].Value = Fboard[x, y].Value)
|
||||
and (not Fboard[x, y].IsBlocked) and (not Fboard[x, y + d].IsBlocked) then
|
||||
begin
|
||||
Fboard[x, y].Value := 0;
|
||||
Fboard[x, y + d].Value := Fboard[x, y + d].Value * 2;
|
||||
Fscore := Fscore + (Fboard[x, y + d].Value);
|
||||
Fboard[x, y + d].IsBlocked := true;
|
||||
FisMoved := true;
|
||||
end
|
||||
else if ((Fboard[x, y + d].Value = 0) and (Fboard[x, y].Value <> 0)) then
|
||||
begin
|
||||
Fboard[x, y + d].Value := Fboard[x, y].Value;
|
||||
Fboard[x, y].Value := 0;
|
||||
FisMoved := true;
|
||||
end;
|
||||
if d > 0 then
|
||||
begin
|
||||
if y + d < 3 then
|
||||
begin
|
||||
MoveVertically(x, y + d, 1);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if y + d > 0 then
|
||||
begin
|
||||
MoveVertically(x, y + d, -1);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TG2048.TestAdd(x, y, value: Integer): boolean;
|
||||
begin
|
||||
if (x < 0) or (x > 3) or (y < 0) or (y > 3) then
|
||||
Exit(false);
|
||||
|
||||
Exit(Fboard[x, y].value = value);
|
||||
end;
|
||||
|
||||
procedure TG2048.WaitKey;
|
||||
var
|
||||
y, x: Integer;
|
||||
begin
|
||||
FisMoved := false;
|
||||
writeln('(W) Up (S) Down (A) Left (D) Right (ESC)Exit');
|
||||
case ReadKey of
|
||||
'W', 'w':
|
||||
Move(TMoveDirection.mdUp);
|
||||
'A', 'a':
|
||||
Move(TMoveDirection.mdLeft);
|
||||
'S', 's':
|
||||
Move(TMoveDirection.mdDown);
|
||||
'D', 'd':
|
||||
Move(TMoveDirection.mdRight);
|
||||
#27:
|
||||
FisDone := true;
|
||||
end;
|
||||
|
||||
for y := 0 to 3 do
|
||||
for x := 0 to 3 do
|
||||
Fboard[x, y].IsBlocked := false;
|
||||
end;
|
||||
|
||||
var
|
||||
Game: TG2048;
|
||||
begin
|
||||
with TG2048.Create do
|
||||
begin
|
||||
Loop;
|
||||
Free;
|
||||
end;
|
||||
Writeln('Press Enter to exit');
|
||||
Readln;
|
||||
end.
|
||||
115
Task/2048/Elixir/2048.elixir
Normal file
115
Task/2048/Elixir/2048.elixir
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
defmodule Game2048 do
|
||||
@size 4
|
||||
@range 0..@size-1
|
||||
|
||||
def play(goal \\ 2048), do: setup() |> play(goal)
|
||||
|
||||
defp play(board, goal) do
|
||||
show(board)
|
||||
cond do
|
||||
goal in Map.values(board) ->
|
||||
IO.puts "You win!"
|
||||
exit(:normal)
|
||||
0 in Map.values(board) or combinable?(board) ->
|
||||
moved = move(board, keyin())
|
||||
if moved == board, do: play(board, goal), else: add_tile(moved) |> play(goal)
|
||||
true ->
|
||||
IO.puts "Game Over!"
|
||||
exit(:normal)
|
||||
end
|
||||
end
|
||||
|
||||
defp setup do
|
||||
(for i <- @range, j <- @range, into: %{}, do: {{i,j},0})
|
||||
|> add_tile
|
||||
|> add_tile
|
||||
end
|
||||
|
||||
defp add_tile(board) do
|
||||
position = blank_space(board) |> Enum.random
|
||||
tile = if :rand.uniform(10)==1, do: 4, else: 2
|
||||
%{board | position => tile}
|
||||
end
|
||||
|
||||
defp blank_space(board) do
|
||||
for {key, 0} <- board, do: key
|
||||
end
|
||||
|
||||
defp keyin do
|
||||
key = IO.gets("key in wasd or q: ")
|
||||
case String.first(key) do
|
||||
"w" -> :up
|
||||
"a" -> :left
|
||||
"s" -> :down
|
||||
"d" -> :right
|
||||
"q" -> exit(:normal)
|
||||
_ -> keyin()
|
||||
end
|
||||
end
|
||||
|
||||
defp move(board, :up) do
|
||||
Enum.reduce(@range, board, fn j,acc ->
|
||||
Enum.map(@range, fn i -> acc[{i,j}] end)
|
||||
|> move_and_combine
|
||||
|> Enum.with_index
|
||||
|> Enum.reduce(acc, fn {v,i},map -> Map.put(map, {i,j}, v) end)
|
||||
end)
|
||||
end
|
||||
defp move(board, :down) do
|
||||
Enum.reduce(@range, board, fn j,acc ->
|
||||
Enum.map(@size-1..0, fn i -> acc[{i,j}] end)
|
||||
|> move_and_combine
|
||||
|> Enum.reverse
|
||||
|> Enum.with_index
|
||||
|> Enum.reduce(acc, fn {v,i},map -> Map.put(map, {i,j}, v) end)
|
||||
end)
|
||||
end
|
||||
defp move(board, :left) do
|
||||
Enum.reduce(@range, board, fn i,acc ->
|
||||
Enum.map(@range, fn j -> acc[{i,j}] end)
|
||||
|> move_and_combine
|
||||
|> Enum.with_index
|
||||
|> Enum.reduce(acc, fn {v,j},map -> Map.put(map, {i,j}, v) end)
|
||||
end)
|
||||
end
|
||||
defp move(board, :right) do
|
||||
Enum.reduce(@range, board, fn i,acc ->
|
||||
Enum.map(@size-1..0, fn j -> acc[{i,j}] end)
|
||||
|> move_and_combine
|
||||
|> Enum.reverse
|
||||
|> Enum.with_index
|
||||
|> Enum.reduce(acc, fn {v,j},map -> Map.put(map, {i,j}, v) end)
|
||||
end)
|
||||
end
|
||||
|
||||
defp move_and_combine(tiles) do
|
||||
(Enum.filter(tiles, &(&1>0)) ++ [0,0,0,0])
|
||||
|> Enum.take(@size)
|
||||
|> case do
|
||||
[a,a,b,b] -> [a*2, b*2, 0, 0]
|
||||
[a,a,b,c] -> [a*2, b, c, 0]
|
||||
[a,b,b,c] -> [a, b*2, c, 0]
|
||||
[a,b,c,c] -> [a, b, c*2, 0]
|
||||
x -> x
|
||||
end
|
||||
end
|
||||
|
||||
defp combinable?(board) do
|
||||
Enum.any?(for i <- @range, j <- 0..@size-2, do: board[{i,j}]==board[{i,j+1}]) or
|
||||
Enum.any?(for j <- @range, i <- 0..@size-2, do: board[{i,j}]==board[{i+1,j}])
|
||||
end
|
||||
|
||||
@frame String.duplicate("+----", @size) <> "+"
|
||||
@format (String.duplicate("|~4w", @size) <> "|") |> to_charlist # before 1.3 to_char_list
|
||||
|
||||
defp show(board) do
|
||||
Enum.each(@range, fn i ->
|
||||
IO.puts @frame
|
||||
row = for j <- @range, do: board[{i,j}]
|
||||
IO.puts (:io_lib.fwrite @format, row) |> to_string |> String.replace(" 0|", " |")
|
||||
end)
|
||||
IO.puts @frame
|
||||
end
|
||||
end
|
||||
|
||||
Game2048.play 512
|
||||
402
Task/2048/Elm/2048.elm
Normal file
402
Task/2048/Elm/2048.elm
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
module Main exposing (..)
|
||||
|
||||
import Html exposing (Html, div, p, text, button, span, h2)
|
||||
import Html.Attributes exposing (class, style)
|
||||
import Html.Events exposing (onClick)
|
||||
import Keyboard exposing (KeyCode)
|
||||
import Random
|
||||
import Tuple
|
||||
|
||||
|
||||
main =
|
||||
Html.program
|
||||
{ init = ( { initialModel | waitingForRandom = True }, generateRandomTiles 2 )
|
||||
, view = view
|
||||
, update = update
|
||||
, subscriptions = always (Keyboard.downs KeyPress)
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- MODEL
|
||||
|
||||
|
||||
-- tiles either have a value (2, 4, 8, ...) or are empty
|
||||
type alias Tile =
|
||||
Maybe Int
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ score : Int
|
||||
, tiles : List Tile
|
||||
, hasLost : Bool
|
||||
, winKeepPlaying : Bool
|
||||
, waitingForRandom : Bool -- prevent user from giving input while waiting for Random Cmd to return
|
||||
}
|
||||
|
||||
|
||||
initialModel : Model
|
||||
initialModel =
|
||||
{ score = 0, tiles = List.repeat 16 Nothing, waitingForRandom = False, hasLost = False, winKeepPlaying = False}
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type alias RandomTileInfo =
|
||||
( Int, Int )
|
||||
|
||||
|
||||
type Msg
|
||||
= KeyPress KeyCode
|
||||
| AddRandomTiles (List RandomTileInfo)
|
||||
| NewGame
|
||||
| KeepPlaying
|
||||
|
||||
|
||||
|
||||
-- asks the random generator to generate the information required for later adding random tiles
|
||||
-- generate a random position for the and value (4 10%, 2 90%) for each tile
|
||||
-- this uses Random.pair and Random.list to get a variable number of such pairs with one Cmd
|
||||
generateRandomTiles : Int -> Cmd Msg
|
||||
generateRandomTiles num =
|
||||
let
|
||||
randomPosition =
|
||||
Random.int 0 15
|
||||
|
||||
randomValue =
|
||||
Random.int 1 10
|
||||
|> Random.map
|
||||
(\rnd ->
|
||||
if rnd == 10 then
|
||||
4
|
||||
else
|
||||
2
|
||||
)
|
||||
|
||||
-- 10% chance
|
||||
randomPositionAndValue =
|
||||
Random.pair randomPosition randomValue
|
||||
in
|
||||
Random.list num randomPositionAndValue |> Random.generate AddRandomTiles
|
||||
|
||||
|
||||
|
||||
-- actually add a random tile to the model
|
||||
addRandomTile : RandomTileInfo -> List Tile -> List Tile
|
||||
addRandomTile ( newPosition, newValue ) tiles =
|
||||
let
|
||||
-- newPosition is a value between 0 and 15
|
||||
-- go through the list and count the amount of empty tiles we've seen.
|
||||
-- if we reached the newPosition % emptyTileCount'th empty tile, set its value to newValue
|
||||
emptyTileCount =
|
||||
List.filter ((==) Nothing) tiles |> List.length
|
||||
|
||||
-- if there are less than 16 empty tiles this is the number of empty tiles we pass
|
||||
targetCount =
|
||||
newPosition % emptyTileCount
|
||||
|
||||
set_ith_empty_tile tile ( countEmpty, newList ) =
|
||||
case tile of
|
||||
Just value ->
|
||||
( countEmpty, (Just value) :: newList )
|
||||
|
||||
Nothing ->
|
||||
if countEmpty == targetCount then
|
||||
-- replace this empty tile with the new value
|
||||
( countEmpty + 1, (Just newValue) :: newList )
|
||||
else
|
||||
( countEmpty + 1, Nothing :: newList )
|
||||
in
|
||||
List.foldr set_ith_empty_tile ( 0, [] ) tiles |> Tuple.second
|
||||
|
||||
|
||||
|
||||
-- core game mechanic: move numbers (to the left,
|
||||
-- moving to the right is equivalent to moving left on the reversed array)
|
||||
-- this function works on single columns/rows
|
||||
moveNumbers : List Tile -> ( List Tile, Int )
|
||||
moveNumbers tiles =
|
||||
let
|
||||
last =
|
||||
List.head << List.reverse
|
||||
|
||||
-- init is to last what tail is to head
|
||||
init =
|
||||
List.reverse << List.drop 1 << List.reverse
|
||||
|
||||
doMove tile ( newTiles, addScore ) =
|
||||
case tile of
|
||||
-- omit empty tiles when shifting
|
||||
Nothing ->
|
||||
( newTiles, addScore )
|
||||
|
||||
Just value ->
|
||||
case last newTiles of
|
||||
-- if the last already moved tile ...
|
||||
Just (Just value2) ->
|
||||
-- ... has the same value, add a tile with the summed value
|
||||
if value == value2 then
|
||||
( (init newTiles) ++ [ Just (2 * value) ]
|
||||
, addScore + 2 * value )
|
||||
else
|
||||
-- ... else just add the tile
|
||||
( newTiles ++ [ Just value ], addScore )
|
||||
|
||||
_ ->
|
||||
-- ... else just add the tile
|
||||
( newTiles ++ [ Just value ], addScore )
|
||||
|
||||
( movedTiles, addScore ) =
|
||||
List.foldl doMove ( [], 0 ) tiles
|
||||
in
|
||||
( movedTiles ++ List.repeat (4 - List.length movedTiles) Nothing, addScore )
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
-- new game button press
|
||||
NewGame ->
|
||||
if not model.waitingForRandom then
|
||||
( { initialModel | waitingForRandom = True }, generateRandomTiles 2 )
|
||||
else
|
||||
( model, Cmd.none )
|
||||
|
||||
-- "keep playing" button on win screen
|
||||
KeepPlaying ->
|
||||
( { model | winKeepPlaying = True }, Cmd.none)
|
||||
|
||||
-- Random generator Cmd response
|
||||
AddRandomTiles tileInfos ->
|
||||
let
|
||||
newTiles =
|
||||
List.foldl addRandomTile model.tiles tileInfos
|
||||
in
|
||||
( { model | tiles = newTiles, waitingForRandom = False }, Cmd.none )
|
||||
|
||||
|
||||
KeyPress code ->
|
||||
let
|
||||
-- zip list and indices, apply filter, unzip
|
||||
indexedFilter func list =
|
||||
List.map2 (,) (List.range 0 (List.length list - 1)) list
|
||||
|> List.filter func
|
||||
|> List.map Tuple.second
|
||||
|
||||
-- the i'th row (of 4) contains elements i*4, i*4+1, i*4+2, i*4+3
|
||||
-- so all elements for which index//4 == i
|
||||
i_th_row list i =
|
||||
indexedFilter (((==) i) << (flip (//) 4) << Tuple.first) list
|
||||
|
||||
-- the i'th col (of 4) contain elements i, i+4, i+2*4, i+3*4
|
||||
-- so all elements for which index%4 == i
|
||||
i_th_col list i =
|
||||
indexedFilter (((==) i) << (flip (%) 4) << Tuple.first) list
|
||||
|
||||
-- rows and columns of the grid
|
||||
rows list =
|
||||
List.map (i_th_row list) (List.range 0 3)
|
||||
|
||||
cols list =
|
||||
List.map (i_th_col list) (List.range 0 3)
|
||||
|
||||
-- move each row or column and unzip the results from each call to moveNumbers
|
||||
move =
|
||||
List.unzip << List.map moveNumbers
|
||||
|
||||
moveReverse =
|
||||
List.unzip << List.map (Tuple.mapFirst List.reverse << moveNumbers << List.reverse)
|
||||
|
||||
-- concat rows back into a flat array and sum all addScores
|
||||
unrows =
|
||||
Tuple.mapSecond List.sum << Tuple.mapFirst List.concat
|
||||
|
||||
-- turn columns back into a flat array and sum all addScores
|
||||
uncols =
|
||||
Tuple.mapSecond List.sum << Tuple.mapFirst (List.concat << cols << List.concat)
|
||||
|
||||
|
||||
-- when shifting left or right each row can be (reverse-) shifted separately
|
||||
-- when shifting up or down each column can be (reveerse-) shifted separately
|
||||
( newTiles, addScore ) =
|
||||
case code of
|
||||
37 ->
|
||||
-- left
|
||||
unrows <| move <| rows model.tiles
|
||||
|
||||
38 ->
|
||||
-- up
|
||||
uncols <| move <| cols model.tiles
|
||||
|
||||
39 ->
|
||||
-- right
|
||||
unrows <| moveReverse <| rows model.tiles
|
||||
|
||||
40 ->
|
||||
-- down
|
||||
uncols <| moveReverse <| cols model.tiles
|
||||
|
||||
_ ->
|
||||
( model.tiles, 0 )
|
||||
|
||||
|
||||
containsEmptyTiles =
|
||||
List.any ((==) Nothing)
|
||||
|
||||
containsAnySameNeighbours : List Tile -> Bool
|
||||
containsAnySameNeighbours list =
|
||||
let
|
||||
tail = List.drop 1 list
|
||||
init = List.reverse <| List.drop 1 <| List.reverse list
|
||||
in
|
||||
List.any (uncurry (==)) <| List.map2 (,) init tail
|
||||
hasLost =
|
||||
-- grid full
|
||||
(not (containsEmptyTiles newTiles))
|
||||
-- and no left/right move possible
|
||||
&& (not <| List.any containsAnySameNeighbours <| rows newTiles)
|
||||
-- and no up/down move possible
|
||||
&& (not <| List.any containsAnySameNeighbours <| cols newTiles)
|
||||
|
||||
( cmd, waiting ) =
|
||||
if List.all identity <| List.map2 (==) model.tiles newTiles then
|
||||
( Cmd.none, False )
|
||||
else
|
||||
( generateRandomTiles 1, True )
|
||||
|
||||
score =
|
||||
model.score + addScore
|
||||
in
|
||||
-- unsure whether this actually happens but regardless:
|
||||
-- keep the program from accepting a new keyboard input when a new tile hasn't been spawned yet
|
||||
if model.waitingForRandom then
|
||||
( model, Cmd.none )
|
||||
else
|
||||
( { model | tiles = newTiles, waitingForRandom = waiting, score = score, hasLost = hasLost }, cmd )
|
||||
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
containerStyle : List ( String, String )
|
||||
containerStyle =
|
||||
[ ( "width", "450px" )
|
||||
, ( "height", "450px" )
|
||||
, ( "background-color", "#bbada0" )
|
||||
, ( "float", "left" )
|
||||
, ( "border-radius", "6px")
|
||||
]
|
||||
|
||||
|
||||
tileStyle : Int -> List ( String, String )
|
||||
tileStyle value =
|
||||
let
|
||||
color =
|
||||
case value of
|
||||
0 ->
|
||||
"#776e65"
|
||||
|
||||
2 ->
|
||||
"#eee4da"
|
||||
|
||||
4 ->
|
||||
"#ede0c8"
|
||||
|
||||
8 ->
|
||||
"#f2b179"
|
||||
|
||||
16 ->
|
||||
"#f59563"
|
||||
|
||||
32 ->
|
||||
"#f67c5f"
|
||||
|
||||
64 ->
|
||||
"#f65e3b"
|
||||
|
||||
128 ->
|
||||
"#edcf72"
|
||||
|
||||
256 ->
|
||||
"#edcc61"
|
||||
|
||||
512 ->
|
||||
"#edc850"
|
||||
|
||||
1024 ->
|
||||
"#edc53f"
|
||||
|
||||
2048 ->
|
||||
"#edc22e"
|
||||
|
||||
_ ->
|
||||
"#edc22e"
|
||||
in
|
||||
[ ( "width", "100px" )
|
||||
, ( "height", "70px" )
|
||||
, ( "background-color", color )
|
||||
, ( "float", "left" )
|
||||
, ( "margin-left", "10px" )
|
||||
, ( "margin-top", "10px" )
|
||||
, ( "padding-top", "30px" )
|
||||
, ( "text-align", "center" )
|
||||
, ( "font-size", "30px" )
|
||||
, ( "font-weight", "bold" )
|
||||
, ( "border-radius", "6px")
|
||||
]
|
||||
|
||||
|
||||
viewTile : Tile -> Html Msg
|
||||
viewTile tile =
|
||||
div [ style <| tileStyle <| Maybe.withDefault 0 tile ]
|
||||
[ span [] [ text <| Maybe.withDefault "" <| Maybe.map toString tile ]
|
||||
]
|
||||
|
||||
|
||||
viewGrid : List Tile -> Html Msg
|
||||
viewGrid tiles =
|
||||
div [ style containerStyle ] <| List.map viewTile tiles
|
||||
|
||||
|
||||
viewLost : Html Msg
|
||||
viewLost =
|
||||
div
|
||||
[ style containerStyle ]
|
||||
[ div
|
||||
[ style [ ( "text-align", "center" ) ] ]
|
||||
[ h2 [] [ text "You lost!" ]
|
||||
]
|
||||
]
|
||||
|
||||
viewWin : Html Msg
|
||||
viewWin =
|
||||
div
|
||||
[ style containerStyle ]
|
||||
[ div
|
||||
[ style [ ( "text-align", "center" ) ] ]
|
||||
[ h2 [] [ text "Congratulations, You won!" ]
|
||||
, button
|
||||
[ style [ ( "margin-bottom", "16px" ), ( "margin-top", "16px" ) ], onClick KeepPlaying ]
|
||||
[ text "Keep playing" ]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div [ style [ ( "width", "450px" ) ] ]
|
||||
[ p [ style [ ( "float", "left" ) ] ] [ text <| "Your Score: " ++ toString model.score ]
|
||||
, button
|
||||
[ style [ ( "margin-bottom", "16px" ), ( "margin-top", "16px" ), ( "float", "right" ) ], onClick NewGame ]
|
||||
[ text "New Game" ]
|
||||
, if model.hasLost then
|
||||
viewLost
|
||||
else if List.any ((==) (Just 2048)) model.tiles && not model.winKeepPlaying then
|
||||
viewWin
|
||||
else
|
||||
viewGrid model.tiles
|
||||
]
|
||||
59
Task/2048/F-Sharp/2048.fs
Normal file
59
Task/2048/F-Sharp/2048.fs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// the board is represented with a list of 16 integers
|
||||
let empty = List.init 16 (fun _ -> 0)
|
||||
let win = List.contains 2048
|
||||
|
||||
// a single movement (a hit) consists of stacking and then possible joining
|
||||
let rec stack = function
|
||||
| 0 :: t -> stack t @ [0]
|
||||
| h :: t -> h :: stack t
|
||||
| [] -> []
|
||||
let rec join = function
|
||||
| a :: b :: c when a = b -> (a + b :: join c) @ [0]
|
||||
| a :: b -> a :: join b
|
||||
| [] -> []
|
||||
let hit = stack >> join
|
||||
let hitBack = List.rev >> hit >> List.rev
|
||||
let rows = List.chunkBySize 4
|
||||
let left = rows >> List.map hit >> List.concat
|
||||
let right = rows >> List.map hitBack >> List.concat
|
||||
let up = rows >> List.transpose >> List.map hit >> List.transpose >> List.concat
|
||||
let down = rows >> List.transpose >> List.map hitBack >> List.transpose >> List.concat
|
||||
|
||||
let lose g = left g = g && right g = g && up g = g && down g = g
|
||||
|
||||
// spawn a 2 or occasionally a 4 at a random unoccupied position
|
||||
let random = System.Random()
|
||||
let spawnOn g =
|
||||
let newTileValue = if random.Next 10 = 0 then 4 else 2
|
||||
let numZeroes = List.filter ((=) 0) >> List.length
|
||||
let newPosition = g |> numZeroes |> random.Next
|
||||
let rec insert what where = function
|
||||
| 0 :: tail when numZeroes tail = where -> what :: tail
|
||||
| h :: t -> h :: insert what where t
|
||||
| [] -> []
|
||||
insert newTileValue newPosition g
|
||||
|
||||
let show =
|
||||
let line = List.map (sprintf "%4i") >> String.concat " "
|
||||
rows >> List.map line >> String.concat "\n" >> printf "\n%s\n"
|
||||
|
||||
// use an empty list as a sign of user interrupt
|
||||
let quit _ = []
|
||||
let quitted = List.isEmpty
|
||||
|
||||
let dispatch = function | 'i' -> up | 'j' -> left | 'k' -> down | 'l' -> right | 'q' -> quit | _ -> id
|
||||
let key() = System.Console.ReadKey().KeyChar |> char
|
||||
let turn state =
|
||||
show state
|
||||
let nextState = (key() |> dispatch) state
|
||||
if nextState <> state && not (quitted nextState) then spawnOn nextState else nextState
|
||||
|
||||
let play() =
|
||||
let mutable state = spawnOn empty
|
||||
while not (win state || lose state || quitted state) do state <- turn state
|
||||
if quitted state then printfn "User interrupt" else
|
||||
show state
|
||||
if win state then printf "You win!"
|
||||
if lose state then printf "You lose!"
|
||||
|
||||
play()
|
||||
320
Task/2048/Factor/2048.factor
Normal file
320
Task/2048/Factor/2048.factor
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
USE: accessors
|
||||
FROM: arrays => <array> array ;
|
||||
FROM: assocs => assoc-filter keys zip ;
|
||||
FROM: combinators => case cleave cond ;
|
||||
FROM: combinators.short-circuit => 1|| 1&& 2&& ;
|
||||
FROM: continuations => cleanup ;
|
||||
FROM: formatting => printf sprintf ;
|
||||
FROM: fry => '[ _ ;
|
||||
FROM: grouping => all-equal? clump group ;
|
||||
FROM: io => bl flush nl readln write ;
|
||||
FROM: kernel => = 2bi 2dup 2drop and bi bi* bi@ boa boolean clone equal? dip drop dup if if* keep loop nip not over swap throw tri unless when with xor ;
|
||||
FROM: math => integer times * + > >= ;
|
||||
FROM: math.functions => ^ ;
|
||||
FROM: math.parser => hex> ;
|
||||
FROM: math.order => +lt+ +gt+ +eq+ ;
|
||||
FROM: random => random sample ;
|
||||
FROM: sequences => <iota> <repetition> any? all? append concat each first flip head if-empty interleave length map pop push reduce reverse second set-nth tail ;
|
||||
FROM: sorting => sort ;
|
||||
FROM: vectors => <vector> ;
|
||||
IN: 2048-game
|
||||
|
||||
|
||||
ERROR: invalid-board ;
|
||||
|
||||
SYMBOL: left
|
||||
SYMBOL: right
|
||||
SYMBOL: up
|
||||
SYMBOL: down
|
||||
|
||||
TUPLE: tile
|
||||
{ level integer }
|
||||
;
|
||||
|
||||
TUPLE: board
|
||||
{ width integer }
|
||||
{ height integer }
|
||||
{ tiles array }
|
||||
;
|
||||
|
||||
M: tile equal?
|
||||
{
|
||||
[ and ] ! test for f
|
||||
[ [ level>> ] bi@ = ]
|
||||
}
|
||||
2&&
|
||||
;
|
||||
|
||||
: valid-board? ( w h -- ? )
|
||||
* 0 > ! board with 0 tiles does not have a meaningful representation
|
||||
;
|
||||
|
||||
: <board> ( w h -- board )
|
||||
[ valid-board? [ invalid-board throw ] unless ]
|
||||
[ 2dup * f <array> board boa ] 2bi
|
||||
;
|
||||
|
||||
: <tile> ( n -- tile )
|
||||
tile boa
|
||||
;
|
||||
|
||||
! 1 in 10 tile starts as 4
|
||||
: new-tile ( -- tile )
|
||||
10 random 0 = [ 2 ] [ 1 ] if
|
||||
<tile>
|
||||
;
|
||||
|
||||
<PRIVATE
|
||||
|
||||
: space-left? ( board -- ? )
|
||||
tiles>> [ f = ] any?
|
||||
;
|
||||
|
||||
: rows>> ( board -- seq )
|
||||
dup tiles>>
|
||||
[ drop { } ] [ swap width>> group ] if-empty
|
||||
;
|
||||
|
||||
: rows<< ( seq board -- )
|
||||
[ concat ] dip tiles<<
|
||||
;
|
||||
|
||||
: columns>> ( board -- seq )
|
||||
rows>> flip
|
||||
;
|
||||
|
||||
: columns<< ( seq board -- )
|
||||
[ flip concat ] dip tiles<<
|
||||
;
|
||||
|
||||
: change-rows ( board quote -- board )
|
||||
over [ rows>> swap call( seq -- seq ) ] [ rows<< ] bi
|
||||
; inline
|
||||
|
||||
: change-columns ( board quote -- board )
|
||||
over [ columns>> swap call( seq -- seq ) ] [ columns<< ] bi
|
||||
; inline
|
||||
|
||||
: can-move-left? ( seq -- ? )
|
||||
{
|
||||
! one element seq cannot move
|
||||
[ length 1 = not ]
|
||||
! empty seq cannot move
|
||||
[ [ f = ] all? not ]
|
||||
[ 2 clump
|
||||
[
|
||||
{
|
||||
! test for identical adjescent tiles
|
||||
[ [ first ] [ second ] bi [ and ] [ = ] 2bi and ]
|
||||
! test for empty space on the left and tile on the right
|
||||
[ [ first ] [ second ] bi [ xor ] [ drop f = ] 2bi and ]
|
||||
} 1||
|
||||
] any?
|
||||
]
|
||||
} 1&&
|
||||
;
|
||||
|
||||
: can-move-direction? ( board direction -- ? )
|
||||
{
|
||||
{ left [ rows>> [ can-move-left? ] any? ] }
|
||||
{ right [ rows>> [ reverse can-move-left? ] any? ] }
|
||||
{ up [ columns>> [ can-move-left? ] any? ] }
|
||||
{ down [ columns>> [ reverse can-move-left? ] any? ] }
|
||||
} case
|
||||
;
|
||||
|
||||
: can-move-any? ( board -- ? )
|
||||
{ left right up down } [ can-move-direction? ] with any?
|
||||
;
|
||||
|
||||
: empty-indices ( seq -- seq )
|
||||
[ length <iota> ] keep zip
|
||||
[ nip f = ] assoc-filter keys
|
||||
;
|
||||
|
||||
: pick-random ( seq -- elem )
|
||||
1 sample first
|
||||
;
|
||||
|
||||
! create a new tile on an empty space
|
||||
: add-tile ( board -- )
|
||||
[ new-tile swap [ empty-indices pick-random ] keep [ set-nth ] keep ] change-tiles drop
|
||||
;
|
||||
|
||||
! combines equal tiles justified right or does nothing
|
||||
: combine-tiles ( tile1 tile2 -- tile3 tile4 )
|
||||
2dup { [ and ] [ = ] } 2&&
|
||||
[ drop [ 1 + ] change-level f swap ] when
|
||||
;
|
||||
|
||||
: justify-left ( seq -- seq )
|
||||
[
|
||||
{
|
||||
{ [ dup f = ] [ 2drop +lt+ ] }
|
||||
{ [ over f = ] [ 2drop +gt+ ] }
|
||||
[ 2drop +eq+ ]
|
||||
} cond
|
||||
] sort
|
||||
;
|
||||
|
||||
: collapse ( seq -- seq )
|
||||
justify-left
|
||||
|
||||
! combine adjescent
|
||||
dup length <vector>
|
||||
[ over
|
||||
[ swap [ push ] keep ]
|
||||
[
|
||||
{
|
||||
[ pop combine-tiles ]
|
||||
[ push ]
|
||||
[ push ]
|
||||
} cleave
|
||||
] if-empty
|
||||
] reduce
|
||||
|
||||
! fill in the gaps after combination
|
||||
justify-left
|
||||
;
|
||||
|
||||
! draws an object
|
||||
GENERIC: draw ( obj -- )
|
||||
|
||||
PRIVATE>
|
||||
|
||||
! a single tile is higher than 2048 (level 10)
|
||||
: won? ( board -- ? )
|
||||
tiles>> [ dup [ level>> 11 >= ] when ] any?
|
||||
;
|
||||
|
||||
! if there is no space left and no neightboring tiles are the same, end the board
|
||||
: lost? ( board -- ? )
|
||||
{
|
||||
[ space-left? ]
|
||||
[ won? ]
|
||||
[ can-move-any? ]
|
||||
} 1|| not
|
||||
;
|
||||
|
||||
: serialize ( board -- str )
|
||||
[ width>> ]
|
||||
[ height>> ]
|
||||
[ tiles>>
|
||||
[ dup f = [ drop 0 ] [ level>> ] if "%02x" sprintf ] map concat
|
||||
] tri
|
||||
"%02x%02x%s" sprintf
|
||||
;
|
||||
|
||||
: deserialize ( str -- board )
|
||||
[ 2 head hex> ] [ 2 tail ] bi
|
||||
[ 2 head hex> ] [ 2 tail ] bi
|
||||
2 group [ hex> dup 0 = [ drop f ] [ tile boa ] if ] map
|
||||
board boa
|
||||
;
|
||||
|
||||
: move ( board direction -- )
|
||||
{
|
||||
{ left [ [ [ collapse ] map ] change-rows ] }
|
||||
{ right [ [ [ reverse collapse reverse ] map ] change-rows ] }
|
||||
{ up [ [ [ collapse ] map ] change-columns ] }
|
||||
{ down [ [ [ reverse collapse reverse ] map ] change-columns ] }
|
||||
} case drop
|
||||
;
|
||||
|
||||
|
||||
: get-input ( -- line )
|
||||
readln
|
||||
;
|
||||
|
||||
: parse-input ( line -- direction/f )
|
||||
{
|
||||
{ "a" [ left ] }
|
||||
{ "d" [ right ] }
|
||||
{ "w" [ up ] }
|
||||
{ "s" [ down ] }
|
||||
{ "q" [ f ] }
|
||||
[ "Wrong input: %s\n" printf flush
|
||||
get-input parse-input ]
|
||||
} case
|
||||
;
|
||||
|
||||
<PRIVATE
|
||||
|
||||
: init ( board -- )
|
||||
'[ _ add-tile ] 2 swap times
|
||||
;
|
||||
|
||||
M: tile draw ( tile -- )
|
||||
level>> 2 swap ^ "% 4d" printf
|
||||
;
|
||||
|
||||
M: boolean draw ( _ -- )
|
||||
drop 4 [ bl ] times
|
||||
;
|
||||
|
||||
: horizontal-line ( board -- )
|
||||
width>>
|
||||
" " write
|
||||
"+------" <repetition> concat
|
||||
write "+ " write nl
|
||||
;
|
||||
|
||||
: separator ( -- )
|
||||
" | " write
|
||||
;
|
||||
|
||||
M: board draw ( board -- )
|
||||
[ horizontal-line ] keep
|
||||
[ rows>> ]
|
||||
[
|
||||
'[ _ horizontal-line ]
|
||||
[ separator
|
||||
[ separator ] [ draw ] interleave
|
||||
separator nl
|
||||
] interleave
|
||||
]
|
||||
[ horizontal-line ]
|
||||
tri
|
||||
flush
|
||||
;
|
||||
|
||||
: update ( board -- f )
|
||||
{
|
||||
[
|
||||
get-input parse-input [
|
||||
{
|
||||
[ can-move-direction? ]
|
||||
[ over [ move ] [ add-tile ] bi* t ]
|
||||
} 2&& drop t
|
||||
] [ drop f ] if*
|
||||
]
|
||||
[ can-move-any? ]
|
||||
} 1&&
|
||||
;
|
||||
|
||||
: exit ( board -- )
|
||||
{
|
||||
{ [ dup lost? ] [ "You lost! Better luck next time." write nl ] }
|
||||
{ [ dup won? ] [ "You won! Congratulations!" write nl ] }
|
||||
[ "Bye!" write nl ]
|
||||
} cond drop
|
||||
;
|
||||
|
||||
PRIVATE>
|
||||
|
||||
: start-2048 ( -- )
|
||||
4 4 <board>
|
||||
[
|
||||
! Initialization
|
||||
[ init ]
|
||||
[ draw ]
|
||||
! Event loop
|
||||
[ [ dup [ update ] [ draw ] bi ] loop ] tri
|
||||
]
|
||||
! Cleanup
|
||||
[ exit ]
|
||||
[ ]
|
||||
cleanup
|
||||
;
|
||||
|
||||
MAIN: start-2048
|
||||
235
Task/2048/Forth/2048.fth
Normal file
235
Task/2048/Forth/2048.fth
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
\ in Forth, you do many things on your own. This word is used to define 2D arrays
|
||||
: 2D-ARRAY ( height width )
|
||||
CREATE DUP ,
|
||||
* CELLS ALLOT
|
||||
DOES> ( y x baseaddress )
|
||||
ROT ( x baseaddress y )
|
||||
OVER @ ( x baseaddress y width )
|
||||
* ( x baseaddress y*width )
|
||||
ROT ( baseaddress y*width x )
|
||||
+ 1+ CELLS +
|
||||
;
|
||||
|
||||
require random.fs
|
||||
HERE SEED !
|
||||
|
||||
0 CONSTANT D-INVALID
|
||||
1 CONSTANT D-UP
|
||||
2 CONSTANT D-DOWN
|
||||
3 CONSTANT D-LEFT
|
||||
4 CONSTANT D-RIGHT
|
||||
|
||||
4 CONSTANT NROWS
|
||||
4 CONSTANT NCOLS
|
||||
|
||||
NROWS NCOLS * CONSTANT GRIDSIZE
|
||||
NROWS NCOLS 2D-ARRAY GRID
|
||||
CREATE HAVE-MOVED CELL ALLOT
|
||||
CREATE TOTAL-SCORE CELL ALLOT
|
||||
CREATE MOVE-SCORE CELL ALLOT
|
||||
|
||||
: DIE-DIRECTIONCONST ." Unknown direction constant:" . BYE ;
|
||||
: ESC #ESC EMIT ;
|
||||
: CLS
|
||||
ESC ." [2J"
|
||||
ESC ." [H"
|
||||
;
|
||||
|
||||
: GRID-VALUE 1 SWAP LSHIFT ;
|
||||
: DASHES 0 ?DO [CHAR] - EMIT LOOP ;
|
||||
|
||||
: DRAW ( -- )
|
||||
CLS ." Score: "
|
||||
TOTAL-SCORE @ 0 U.R
|
||||
MOVE-SCORE @ ?DUP IF
|
||||
." (+" 0 U.R ." )"
|
||||
THEN
|
||||
CR 25 DASHES CR
|
||||
|
||||
NROWS 0 ?DO
|
||||
." |"
|
||||
NCOLS 0 ?DO
|
||||
J I GRID @ ?DUP IF
|
||||
GRID-VALUE 4 U.R
|
||||
ELSE
|
||||
4 SPACES
|
||||
THEN
|
||||
." |"
|
||||
LOOP
|
||||
CR
|
||||
LOOP
|
||||
|
||||
25 DASHES CR
|
||||
;
|
||||
|
||||
: COUNT-FREE-SPACES ( -- free-spaces )
|
||||
0 ( count )
|
||||
NROWS 0 ?DO
|
||||
NCOLS 0 ?DO
|
||||
J I GRID @ 0= IF 1+ THEN
|
||||
LOOP
|
||||
LOOP
|
||||
;
|
||||
|
||||
: GET-FREE-SPACE ( index -- addr )
|
||||
0 0 GRID SWAP ( curr-addr index )
|
||||
0 0 GRID @ 0<> IF 1+ THEN
|
||||
0 ?DO ( find the next free space index times )
|
||||
BEGIN
|
||||
CELL+ DUP @ 0=
|
||||
UNTIL
|
||||
LOOP
|
||||
;
|
||||
|
||||
: NEW-BLOCK ( -- )
|
||||
COUNT-FREE-SPACES
|
||||
DUP 0<= IF DROP EXIT THEN
|
||||
RANDOM GET-FREE-SPACE
|
||||
10 RANDOM 0= IF 2 ELSE 1 THEN SWAP !
|
||||
;
|
||||
|
||||
: 2GRID ( a-y a-x b-y b-x -- a-addr b-addr ) GRID -ROT GRID SWAP ;
|
||||
: CAN-MERGE ( dest-addr other-addr -- can-merge? )
|
||||
@ SWAP @ ( other-val dest-val )
|
||||
DUP 0<> -ROT = AND
|
||||
;
|
||||
|
||||
: CAN-GRAVITY ( dest-addr other-addr -- can-gravity? )
|
||||
@ SWAP @ ( other-val dest-val )
|
||||
0= SWAP 0<> AND
|
||||
;
|
||||
|
||||
: TRY-MERGE ( dest-y dest-x other-y other-x -- )
|
||||
2GRID ( dest-addr other-addr )
|
||||
2DUP CAN-MERGE IF
|
||||
TRUE HAVE-MOVED !
|
||||
0 SWAP ! ( dest-addr )
|
||||
DUP @ 1+ DUP ( dest-addr dest-val dest-val )
|
||||
ROT ! ( dest-val )
|
||||
GRID-VALUE DUP ( score-diff score-diff )
|
||||
MOVE-SCORE +!
|
||||
TOTAL-SCORE +!
|
||||
ELSE
|
||||
2DROP
|
||||
THEN
|
||||
;
|
||||
|
||||
: TRY-GRAVITY ( did-something-before operator dest-y dest-x other-y other-x -- did-something-after operator )
|
||||
2GRID ( ... dest-addr other-addr )
|
||||
2DUP CAN-GRAVITY IF
|
||||
TRUE HAVE-MOVED !
|
||||
DUP @ ( ... dest-addr other-addr other-val )
|
||||
ROT ( ... other-addr other-val dest-addr ) ! ( ... other-addr )
|
||||
0 SWAP !
|
||||
NIP TRUE SWAP
|
||||
ELSE
|
||||
2DROP
|
||||
THEN
|
||||
;
|
||||
|
||||
: TRY-LOST? ( lost-before operator dy dx oy ox -- lost-after operator )
|
||||
2GRID CAN-MERGE INVERT ( lost-before operator lost-now )
|
||||
ROT AND SWAP ( lost-after operator )
|
||||
;
|
||||
|
||||
: MOVEMENT-LOOP ( direction operator -- ) CASE
|
||||
SWAP
|
||||
D-UP OF NROWS 1- 0 ?DO
|
||||
NCOLS 0 ?DO
|
||||
J I J 1+ I 4 PICK EXECUTE
|
||||
LOOP
|
||||
LOOP ENDOF
|
||||
D-DOWN OF 1 NROWS 1- ?DO
|
||||
NCOLS 0 ?DO
|
||||
J I J 1- I 4 PICK EXECUTE
|
||||
LOOP
|
||||
-1 +LOOP ENDOF
|
||||
D-LEFT OF NCOLS 1- 0 ?DO
|
||||
NROWS 0 ?DO
|
||||
I J I J 1+ 4 PICK EXECUTE
|
||||
LOOP
|
||||
LOOP ENDOF
|
||||
D-RIGHT OF 1 NCOLS 1- ?DO
|
||||
NROWS 0 ?DO
|
||||
I J I J 1- 4 PICK EXECUTE
|
||||
LOOP
|
||||
-1 +LOOP ENDOF
|
||||
DIE-DIRECTIONCONST
|
||||
ENDCASE DROP ;
|
||||
|
||||
: MERGE ( move -- ) ['] TRY-MERGE MOVEMENT-LOOP ;
|
||||
: GRAVITY-ONCE ( move -- success? ) FALSE SWAP ['] TRY-GRAVITY MOVEMENT-LOOP ;
|
||||
: GRAVITY ( move -- )
|
||||
BEGIN
|
||||
DUP GRAVITY-ONCE INVERT
|
||||
UNTIL DROP
|
||||
;
|
||||
|
||||
: MOVE-LOST? ( move -- lost? ) TRUE SWAP ['] TRY-LOST? MOVEMENT-LOOP ;
|
||||
: END-IF-LOST ( -- lost? )
|
||||
COUNT-FREE-SPACES 0= IF
|
||||
TRUE
|
||||
5 1 DO I MOVE-LOST? AND LOOP
|
||||
IF ." You lose!" CR BYE THEN
|
||||
THEN
|
||||
;
|
||||
|
||||
: END-IF-WON ( -- )
|
||||
NROWS 0 ?DO
|
||||
NCOLS 0 ?DO
|
||||
J I GRID @ GRID-VALUE 2048 = IF ." You win!" CR BYE THEN
|
||||
LOOP
|
||||
LOOP
|
||||
;
|
||||
|
||||
: TICK ( move -- )
|
||||
FALSE HAVE-MOVED !
|
||||
0 MOVE-SCORE !
|
||||
DUP GRAVITY DUP MERGE GRAVITY
|
||||
HAVE-MOVED @ IF NEW-BLOCK DRAW THEN
|
||||
END-IF-WON
|
||||
END-IF-LOST
|
||||
;
|
||||
|
||||
: GET-MOVE ( -- move )
|
||||
BEGIN
|
||||
KEY CASE
|
||||
#EOF OF BYE ENDOF
|
||||
#ESC OF BYE ENDOF
|
||||
[CHAR] q OF BYE ENDOF
|
||||
[CHAR] Q OF BYE ENDOF
|
||||
[CHAR] k OF D-UP TRUE ENDOF
|
||||
[CHAR] K OF D-UP TRUE ENDOF
|
||||
[CHAR] j OF D-DOWN TRUE ENDOF
|
||||
[CHAR] J OF D-DOWN TRUE ENDOF
|
||||
[CHAR] h OF D-LEFT TRUE ENDOF
|
||||
[CHAR] H OF D-LEFT TRUE ENDOF
|
||||
[CHAR] l OF D-RIGHT TRUE ENDOF
|
||||
[CHAR] L OF D-RIGHT TRUE ENDOF
|
||||
FALSE SWAP
|
||||
ENDCASE
|
||||
UNTIL
|
||||
;
|
||||
|
||||
: INIT ( -- )
|
||||
NROWS 0 ?DO
|
||||
NCOLS 0 ?DO
|
||||
0 J I GRID !
|
||||
LOOP
|
||||
LOOP
|
||||
|
||||
0 TOTAL-SCORE !
|
||||
0 MOVE-SCORE !
|
||||
NEW-BLOCK
|
||||
NEW-BLOCK
|
||||
DRAW
|
||||
;
|
||||
|
||||
: MAIN-LOOP ( -- )
|
||||
BEGIN
|
||||
GET-MOVE TICK
|
||||
AGAIN
|
||||
;
|
||||
|
||||
INIT
|
||||
MAIN-LOOP
|
||||
6
Task/2048/Fortran/2048-1.f
Normal file
6
Task/2048/Fortran/2048-1.f
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
WRITE (MSG,1) !Roll forth a top/bottom boundary. No corner characters (etc.), damnit.
|
||||
1 FORMAT ("|",<NC>(<W>("-"),"|")) !Heavy reliance on runtime values in NC and W. But see FORMAT 22.
|
||||
2 FORMAT ("|",<NC>(<W>(" "),"|")) !No horizontal markings within a tile. See FORMAT 1.
|
||||
WRITE (MSG,22) ((" ",L1 = 1,W),"|",C = 1,NC) !Compare to FORMAT 2.
|
||||
22 FORMAT ("|",666A1) !A constant FORMAT, a tricky WRITE.
|
||||
4 FORMAT ("|",<NC - 1>(<W>("-"),"+"),<W>("-"),"|") !With internal + rather than |.
|
||||
190
Task/2048/Fortran/2048-2.f
Normal file
190
Task/2048/Fortran/2048-2.f
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
SUBROUTINE SHOW(NR,NC,BOARD) !Mess about.
|
||||
INTEGER NR,NC !Number of rows and columns.
|
||||
INTEGER BOARD(NR,NC) !The board. Actual storage is transposed!
|
||||
INTEGER R,C !Steppers.
|
||||
INTEGER L,L1 !Fingers.
|
||||
INTEGER W !A width.
|
||||
PARAMETER (W = 6) !Six will suffice for 2048, even 524288.
|
||||
CHARACTER*(NC*(W + 1) + 1) ALINE
|
||||
CHARACTER*1 TL,TR,BL,BR !Corner characters: top left, etc. Code page 850, and 437?
|
||||
CHARACTER*1 LR,RL,TD,BU !Side joining: Left rightwards, right leftwards, top downwards, bottom upwards.
|
||||
CHARACTER*1 VL,HL,XX !Vertical and horizontal lines, line crossing.
|
||||
PARAMETER (TL=CHAR(218),TR=CHAR(191),BL=CHAR(192),BR=CHAR(217)) !Works for the "code page" 437, and 850.
|
||||
PARAMETER (LR=CHAR(195),RL=CHAR(180),TD=CHAR(194),BU=CHAR(193)) !Try the DOS command CHCP to see which is in use.
|
||||
PARAMETER (VL=CHAR(179),HL=CHAR(196),XX=CHAR(197)) !Attempts to change the code page no longer work...
|
||||
INTEGER MSG !I/O unit number.
|
||||
COMMON/IODEV/ MSG !I talk to the trees...
|
||||
WRITE (MSG,1) TL,((HL,L = 1,W),TD,C = 1,NC - 1),(HL,L = 1,W),TR !Write the top edge, with downwards ticks.
|
||||
1 FORMAT (666A1) !Surely long enough.
|
||||
DO R = 1,NR !Chug down the rows.
|
||||
WRITE (MSG,1) VL,((" ",L=1,W),VL,C = 1,NC - 1),(" ",L=1,W),VL !Space vertically to make the tile look less rectangular.
|
||||
WRITE (ALINE,3) (VL,BOARD(R,C),C = 1,NC),VL !The columns of the row. Usage is BOARD(row,col) despite storage adjacency.
|
||||
3 FORMAT (<NC>(A1,I<W>),A1) !Fixed sizes might suffice.
|
||||
DO C = 1,NC !Now inspect each cell along the line.
|
||||
L1 = 1 + (C - 1)*(W + 1) + 1 !Locate the first interior character.
|
||||
IF (BOARD(R,C).LE.0) THEN !Should this one be blank?
|
||||
ALINE(L1 + W - 1:L1 + W - 1) = " " !Yes. Scrub the lone zero at the end of the span.
|
||||
ELSE !Non blank, but, aligned right.
|
||||
L = L1 !So, look for the first digit.
|
||||
DO WHILE(ALINE(L:L).EQ." ") !There is surely one digit to be found.
|
||||
L = L + 1 !Not yet. Advance.
|
||||
END DO !End with L fingering the first digit.
|
||||
IF (L.GT.L1) ALINE(L1 + (L - L1 + 1)/2:L1 + W - 1) = !Halve (approx.) the spare space at the start.
|
||||
& ALINE(L:L1 + W - 1) !The first digit to the last digit.
|
||||
END IF !So much for that line segment.
|
||||
END DO !On to the next column.
|
||||
WRITE (MSG,"(A)") ALINE !Roll the fancy line, all in one go.
|
||||
WRITE (MSG,1) VL,((" ",L=1,W),VL,C = 1,NC - 1),(" ",L=1,W),VL !More vertical space.
|
||||
IF (R.LT.NR) WRITE (MSG,1) LR,((HL,L = 1,W),XX,C = 1,NC - 1), !Write an internal horizontal seam.
|
||||
& (HL,L = 1,W),RL !Starting and ending with a horizontal tick.
|
||||
END DO !On to the next row.
|
||||
WRITE (MSG,1) BL,((HL,L = 1,W),BU,C = 1,NC - 1),(HL,L = 1,W),BR !Write the bottom edge, witrh upwards ticks.
|
||||
END SUBROUTINE SHOW !That was nice.
|
||||
|
||||
PROGRAM PUZZLE !Some severe array juggling may indeed cause puzzlement.
|
||||
INTEGER NR,NC,N !Describes the shape of the board.
|
||||
PARAMETER (NR = 4, NC = 4, N = NR*NC) !Determines the shape of the board.
|
||||
INTEGER BOARD(NR,NC) !Thus transpose furrytran's column-major usage. Beware!!!
|
||||
INTEGER BORED(N) !This allows for consecutive comparisons.
|
||||
EQUIVALENCE (BOARD,BORED) !Because the arrays are in the same place.
|
||||
INTEGER BIJ,PB,CB !Juggles with the values of some squares.
|
||||
INTEGER STARTVALUE,STARTTILES,TARGET !Document the starting value.
|
||||
PARAMETER (TARGET = 2048,STARTVALUE = 2,STARTTILES = 2) !Why not start with one?
|
||||
INTEGER SCORE !Count them all.
|
||||
INTEGER I,IT,TRY !Odds and ends.
|
||||
INTEGER LIST(N) !A list.
|
||||
CHARACTER*1 WAYS(4),WAYC(4) !In two dimensions, there are four possible ways to move.
|
||||
CHARACTER*4 WAYI !There is no equivalent of INDEX for searching arrays.
|
||||
EQUIVALENCE (WAYS,WAYI) !But this enables two interpretations of the same storage.
|
||||
PARAMETER (WAYC = (/"R","U","L","D"/)) !These are the names for the available directions.
|
||||
INTEGER W,M,RC,CR,CIJ(2),PIJ(2),WAY(4,2),YAW(4,2) !Directions in array index terms.
|
||||
INTEGER RC1(4),RCN(4),RCI(4), CR1(4),CRN(4),CRI(4) !Loop control for the directions..
|
||||
PARAMETER (RC1 = (/ 1, 1,NR,NC/), CR1 = (/ 1,NR,NC, 1/)) !Start values of the first and second loops.
|
||||
PARAMETER (RCN = (/NR,NC, 1, 1/), CRN = (/NC, 1, 1,NR/)) !End values.
|
||||
PARAMETER (RCI = (/+1,+1,-1,-1/), CRI = (/+1,-1,-1,+1/)) !Incrementing or decrementing accordingly.
|
||||
PARAMETER (WAY = (/ 1, 0, 1, 0, 0, 1, 0, 1/)) !The first loop is either the row, or the column.
|
||||
PARAMETER (YAW = (/ 0, 1, 0, 1, 1, 0, 1, 0/)) !The second loop is the other way around.
|
||||
REAL VALUE !Humph. Yet another interface to a "random" number generator.
|
||||
CHARACTER*1 C !A monocharacter response is anticipated.
|
||||
INTEGER MSG,KBD !I/O unit numbers.
|
||||
COMMON/IODEV/ MSG,KBD !Pass the word.
|
||||
|
||||
KBD = 5 !Standard input. (Keyboard -> Display screen)
|
||||
MSG = 6 !Standard output. (Display screen)
|
||||
WRITE (MSG,1) TARGET,NR,NC,STARTVALUE !Announce.
|
||||
1 FORMAT ("To play '",I0,"' with ",I0," rows and ",I0," columns.",/,
|
||||
1"On each move, choose a direction (Up, Down, Left, Right)",/
|
||||
2 "by typing the single letter U, D, L, R, or, a space to quit."/
|
||||
3 "All squares will be pushed as far as possible that way.",/
|
||||
4 "Those meeting with the same number will form one square",/
|
||||
5 "with the sum of the numbers, and one becomes blank.",/
|
||||
6 "After each move, a random blank square becomes ",I0,/)
|
||||
WRITE (MSG,2) !Now for some annoyance.
|
||||
2 FORMAT ("An integer to start the 'random' number generator: ",$) !Not starting a new line.
|
||||
READ (KBD,*) TRY !Could use a time-of-day in microseconds, or similar.
|
||||
CALL SEED(TRY) !But this enables reproducibility. And cheating.
|
||||
|
||||
Concoct a board layout.
|
||||
10 BOARD = 0 !Clear for action.
|
||||
DO I = 1,STARTTILES !Place the initial tiles, with their starting values.
|
||||
11 CALL RANDOM(VALUE) !0 <= VALUE < 1.
|
||||
IT = VALUE*N + 1 !1 <= IT <= N. Don't round up!
|
||||
IF (BORED(IT).NE.0) GO TO 11 !Oops! Flounder towards another tile.
|
||||
BORED(IT) = STARTVALUE !The beginning.
|
||||
END DO !On to the next.
|
||||
SCORE = STARTVALUE*STARTTILES !Save some mental arithmetic.
|
||||
TRY = 0 !No moves made yet.
|
||||
|
||||
Consider possible moves. Think in (x,y) but convert those thimks to (row,column). Eurghf.
|
||||
20 TRY = TRY + 1 !Here we go again.
|
||||
CALL SHOW(NR,NC,BOARD) !The current state.
|
||||
WAYS = "" !No moveable directions are known.
|
||||
DO 21 W = 1,4 !One way or another, consider each possible direction.
|
||||
DO RC = RC1(W),RCN(W),RCI(W) !W = 1 = +x: consider each successive row.
|
||||
CIJ = RC*WAY(W,1:2) + CR1(W)*YAW(W,1:2) !Finger the first position.
|
||||
DO CR = CR1(W) + CRI(W),CRN(W),CRI(W) !W = 1; along the columns of the row.
|
||||
PIJ = CIJ !Retain the previous position.
|
||||
CIJ = RC*WAY(W,1:2) + CR*YAW(W,1:2) !Convert (RC,CR) to either (RC,CR) or (CR,RC).
|
||||
BIJ = BOARD(CIJ(1),CIJ(2)) !Grab the current position's board state.
|
||||
IF ((BOARD(PIJ(1),PIJ(2)).GT.0 .AND. BIJ.EQ.0) !A non-empty tile to move to an empty one?
|
||||
1 .OR.(BOARD(PIJ(1),PIJ(2)).EQ.BIJ .AND. BIJ.GT.0)) THEN !Or, there is a pair, BOARD(CIJ) = BOARD(PIJ),
|
||||
WAYS(W) = WAYC(W) !Then this direction is available.
|
||||
GO TO 21 !No need to seek further opportunities for its use.
|
||||
END IF !So much for the current position.
|
||||
END DO !Advance the scan along direction W.
|
||||
END DO !Advance to the next (row or column) at right angles to W.
|
||||
21 CONTINUE !Try another way.
|
||||
|
||||
Cast forth an invitation, and obtain a choice.
|
||||
30 WRITE (MSG,31) TRY,SCORE,WAYS !Summary.
|
||||
31 FORMAT ("Move",I4,", score ",I0,". Moves ",4A1,$) !The $, of course, says "don't end the line".
|
||||
IF (ALL(WAYS.EQ." ")) GO TO 600 !A gridlock?
|
||||
WRITE (MSG,32) !Nope. Invite a selection.
|
||||
32 FORMAT (" ... Your move: ",$) !Awaits input, with a new line after pressing "enter".
|
||||
IF (COUNT(WAYS.NE." ").EQ.1) THEN !Or, perhaps it is a choice you can't refuse.
|
||||
W = MAXLOC(ABS(ICHAR(WAYS) - ICHAR(" ")),DIM = 1) !One element's value differes from " "...
|
||||
WRITE (MSG,33) WAYS(W) !Sieze control!
|
||||
33 FORMAT (A1," is the only possibility!") !Just don't ask for input.
|
||||
ELSE !But often, the human can decide.
|
||||
READ (KBD,"(A)") C !Just one character. The first one typed.
|
||||
IF (C.LE." ") STOP "Oh well." !Bored, already?
|
||||
I = INDEX("ruld",C) !A lowercase letter may be presented.
|
||||
IF (I.GT.0) C = "RULD"(I:I) !So, convert to uppercase, if worthy.
|
||||
W = INDEX(WAYI,C) !What is it? There is no search of elements of the array WAYS.
|
||||
IF (W.LE.0) THEN !Perhaps it is blocked.
|
||||
WRITE (MSG,34) C !Alas.
|
||||
34 FORMAT ("Not a possible move! ",A) !Just so.
|
||||
GO TO 30 !Try again.
|
||||
END IF !So much for suspicion.
|
||||
END IF !A move has been chosen.
|
||||
|
||||
Complete the selected move. Carefully avoid enabling cascades, so 1122 is pulled right to ..24, not .222 then ..42.
|
||||
40 M = MOD(W + 1,4) + 1 !W is the direction of movement, its inverse, M, faces arrivals.
|
||||
DO RC = RC1(M),RCN(M),RCI(M) !Loop through the (rows/columns) at right angles to the selected anti-way.
|
||||
PIJ = RC*WAY(M,1:2) + CR1(M)*YAW(M,1:2) !Finger the first square, which may be empty.
|
||||
PB = BOARD(PIJ(1),PIJ(2)) !Load it into my two-element buffer: PB and CB.
|
||||
IF (PB.NE.0) BOARD(PIJ(1),PIJ(2)) = 0 !It may be returned to the board somewhere else.
|
||||
DO CR = CR1(M) + CRI(M),CRN(M),CRI(M) !Step along the (column/row) of the selected anti-direction.
|
||||
CIJ = RC*WAY(M,1:2) + CR*YAW(M,1:2) !Convert (RC,CR) to either CIJ = (RC,CR) or CIJ = (CR,RC).
|
||||
CB = BOARD(CIJ(1),CIJ(2)) !Inspect this square.
|
||||
IF (CB.EQ.0) CYCLE !From nothing comes nothing.
|
||||
BOARD(CIJ(1),CIJ(2)) = 0 !The board's value now lives precariously in CB.
|
||||
IF (PB.EQ.0) THEN !A waiting hole? (And, CB is not empty)
|
||||
PB = CB !Yes. Fill it. More may follow, after spaces.
|
||||
ELSE !Otherwise, two non-zero values are in hand.
|
||||
IF (PB.EQ.CB) THEN !If they match,
|
||||
PB = PB + CB !Combine the new with the old.
|
||||
CB = 0 !The new one is gone.
|
||||
END IF !So much for matches.
|
||||
BOARD(PIJ(1),PIJ(2)) = PB !Roll the trailing value.
|
||||
PIJ = PIJ + CRI(M)*YAW(M,1:2) !Advance the finger.
|
||||
PB = CB !Shuffle along one.
|
||||
END IF !So much for that square.
|
||||
END DO !On to the next one along.
|
||||
IF (PB.GT.0) BOARD(PIJ(1),PIJ(2)) = PB !A tail end value?
|
||||
END DO !On to the next set.
|
||||
|
||||
Choose a random blank square.
|
||||
50 IT = 0 !None have been located. (There is surely one, as a move was possible)
|
||||
DO I = 1,N !Step through all the possible squares.
|
||||
IF (BORED(I).LE.0) THEN !Empty?
|
||||
IT = IT + 1 !Yes. Augment my list.
|
||||
LIST(IT) = I !Recording available squares.
|
||||
END IF !So much for that square.
|
||||
END DO !On to the next.
|
||||
IF (IT.GT.1) THEN !If a choice s available,
|
||||
CALL RANDOM(VALUE) !Concoct another: 0 <= VALUE < 1.
|
||||
IT = VALUE*IT + 1 !And thus with integer truncation, choose an empty square.
|
||||
END IF !So much for choices.
|
||||
BORED(LIST(IT)) = STARTVALUE !Fill the square.
|
||||
SCORE = SCORE + STARTVALUE !Might as well keep count.
|
||||
Check for success.
|
||||
60 IF (ALL(BORED.LT.TARGET)) GO TO 20!Hi ho.
|
||||
WRITE (MSG,61) !A success message.
|
||||
61 FORMAT (I0," has been reached!") !No fancy colours nor flashing lights, nor even bells.
|
||||
GO TO 20 !Carry on, anyway.
|
||||
|
||||
Curses!
|
||||
600 WRITE (MSG,601) !Alas.
|
||||
601 FORMAT ("None! Oh dear.") !Nothing more can be done.
|
||||
END !That was fun.
|
||||
311
Task/2048/FreeBASIC/2048.basic
Normal file
311
Task/2048/FreeBASIC/2048.basic
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
#define EXTCHAR Chr(255)
|
||||
|
||||
'--- Declaration of global variables ---
|
||||
Dim Shared As Integer gGridSize = 4 'grid size (4 -> 4x4)
|
||||
Dim Shared As Integer gGrid(gGridSize, gGridSize)
|
||||
Dim Shared As Integer gScore
|
||||
Dim Shared As Integer curX, curY
|
||||
Dim Shared As Integer hasMoved, wasMerge
|
||||
' Don't touch these numbers, seriously
|
||||
Dim Shared As Integer gOriginX, gOriginY
|
||||
gOriginX = 75 'pixel X of top left of grid
|
||||
gOriginY = 12 'pixel Y of top right of grida
|
||||
Dim Shared As Integer gTextOriginX, gTextOriginY, gSquareSide
|
||||
gTextOriginX = 11
|
||||
gTextOriginY = 3
|
||||
gSquareSide = 38 'width/height of block in pixels
|
||||
|
||||
'set up all the things!
|
||||
Dim Shared As Integer gDebug = 0
|
||||
|
||||
'--- SUBroutines and FUNCtions ---
|
||||
Sub addblock
|
||||
Dim As Integer emptyCells(gGridSize * gGridSize, 2)
|
||||
Dim As Integer emptyCellCount = 0
|
||||
Dim As Integer x, y, index, num
|
||||
|
||||
For x = 0 To gGridSize - 1
|
||||
For y = 0 To gGridSize - 1
|
||||
If gGrid(x, y) = 0 Then
|
||||
emptyCells(emptyCellCount, 0) = x
|
||||
emptyCells(emptyCellCount, 1) = y
|
||||
emptyCellCount += 1
|
||||
End If
|
||||
Next y
|
||||
Next x
|
||||
|
||||
If emptyCellCount > 0 Then
|
||||
index = Int(Rnd * emptyCellCount)
|
||||
num = Cint(Rnd + 1) * 2
|
||||
gGrid(emptyCells(index, 0), emptyCells(index, 1)) = num
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Function pad(num As Integer) As String
|
||||
Dim As String strNum = Ltrim(Str(num))
|
||||
|
||||
Select Case Len(strNum)
|
||||
Case 1: Return " " + strNum + " "
|
||||
Case 2: Return " " + strNum + " "
|
||||
Case 3: Return " " + strNum
|
||||
Case 4: Return strNum
|
||||
End Select
|
||||
End Function
|
||||
|
||||
Sub drawNumber(num As Integer, xPos As Integer, yPos As Integer)
|
||||
Dim As Integer c, x, y
|
||||
Select Case num
|
||||
Case 0: c = 16
|
||||
Case 2: c = 2
|
||||
Case 4: c = 3
|
||||
Case 8: c = 4
|
||||
Case 16: c = 5
|
||||
Case 32: c = 6
|
||||
Case 64: c = 7
|
||||
Case 128: c = 8
|
||||
Case 256: c = 9
|
||||
Case 512: c = 10
|
||||
Case 1024: c = 11
|
||||
Case 2048: c = 12
|
||||
Case 4096: c = 13
|
||||
Case 8192: c = 13
|
||||
Case Else: c = 13
|
||||
End Select
|
||||
|
||||
x = xPos *(gSquareSide + 2) + gOriginX + 1
|
||||
y = yPos *(gSquareSide + 2) + gOriginY + 1
|
||||
Line(x + 1, y + 1)-(x + gSquareSide - 1, y + gSquareSide - 1), c, BF
|
||||
|
||||
If num > 0 Then
|
||||
Locate gTextOriginY + 1 +(yPos * 5), gTextOriginX +(xPos * 5) : Print " "
|
||||
Locate gTextOriginY + 2 +(yPos * 5), gTextOriginX +(xPos * 5) : Print pad(num)
|
||||
Locate gTextOriginY + 3 +(yPos * 5), gTextOriginX +(xPos * 5)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Function getAdjacentCell(x As Integer, y As Integer, d As String) As Integer
|
||||
If (d = "l" And x = 0) Or (d = "r" And x = gGridSize - 1) Or (d = "u" And y = 0) Or (d = "d" And y = gGridSize - 1) Then
|
||||
getAdjacentCell = -1
|
||||
Else
|
||||
Select Case d
|
||||
Case "l": getAdjacentCell = gGrid(x - 1, y)
|
||||
Case "r": getAdjacentCell = gGrid(x + 1, y)
|
||||
Case "u": getAdjacentCell = gGrid(x, y - 1)
|
||||
Case "d": getAdjacentCell = gGrid(x, y + 1)
|
||||
End Select
|
||||
End If
|
||||
End Function
|
||||
|
||||
'Draws the outside grid(doesn't render tiles)
|
||||
Sub initGraphicGrid
|
||||
Dim As Integer x, y, gridSide =(gSquareSide + 2) * gGridSize
|
||||
|
||||
Line(gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 14, BF 'outer square, 3 thick
|
||||
Line(gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 1, B 'outer square, 3 thick
|
||||
Line(gOriginX - 1, gOriginY - 1)-(gOriginX + gridSide + 1, gOriginY + gridSide + 1), 1, B
|
||||
Line(gOriginX - 2, gOriginY - 2)-(gOriginX + gridSide + 2, gOriginY + gridSide + 2), 1, B
|
||||
|
||||
For x = gOriginX + gSquareSide + 2 To gOriginX +(gSquareSide + 2) * gGridSize Step gSquareSide + 2 ' horizontal lines
|
||||
Line(x, gOriginY)-(x, gOriginY + gridSide), 1
|
||||
Next x
|
||||
|
||||
For y = gOriginY + gSquareSide + 2 To gOriginY +(gSquareSide + 2) * gGridSize Step gSquareSide + 2 ' vertical lines
|
||||
Line(gOriginX, y)-(gOriginX + gridSide, y), 1
|
||||
Next y
|
||||
End Sub
|
||||
|
||||
'Init the(data) grid with 0s
|
||||
Sub initGrid
|
||||
Dim As Integer x, y
|
||||
For x = 0 To 3
|
||||
For y = 0 To 3
|
||||
gGrid(x, y) = 0
|
||||
Next y
|
||||
Next x
|
||||
|
||||
addblock
|
||||
addblock
|
||||
End Sub
|
||||
|
||||
Sub moveBlock(sourceX As Integer, sourceY As Integer, targetX As Integer, targetY As Integer, merge As Integer)
|
||||
If sourceX < 0 Or sourceX >= gGridSize Or sourceY < 0 Or sourceY >= gGridSize And gDebug = 1 Then
|
||||
Locate 0, 0 : Print "moveBlock: source coords out of bounds"
|
||||
End If
|
||||
|
||||
If targetX < 0 Or targetX >= gGridSize Or targetY < 0 Or targetY >= gGridSize And gDebug = 1 Then
|
||||
Locate 0, 0 : Print "moveBlock: source coords out of bounds"
|
||||
End If
|
||||
|
||||
Dim As Integer sourceSquareValue = gGrid(sourceX, sourceY)
|
||||
Dim As Integer targetSquareValue = gGrid(targetX, targetY)
|
||||
|
||||
If merge = 1 Then
|
||||
If sourceSquareValue = targetSquareValue Then
|
||||
gGrid(sourceX, sourceY) = 0
|
||||
gGrid(targetX, targetY) = targetSquareValue * 2
|
||||
gScore += targetSquareValue * 2 ' Points!
|
||||
Elseif gDebug = 1 Then
|
||||
Locate 0, 0 : Print "moveBlock: Attempted to merge unequal sqs"
|
||||
End If
|
||||
Else
|
||||
If targetSquareValue = 0 Then
|
||||
gGrid(sourceX, sourceY) = 0
|
||||
gGrid(targetX, targetY) = sourceSquareValue
|
||||
Elseif gDebug = 1 Then
|
||||
Locate 0, 0 : Print "moveBlock: Attempted to move to non-empty block"
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Function pColor(r As Integer, g As Integer, b As Integer) As Integer
|
||||
Return (r + g * 256 + b * 65536)
|
||||
End Function
|
||||
|
||||
Sub moveToObstacle(x As Integer, y As Integer, direcc As String)
|
||||
curX = x : curY = y
|
||||
|
||||
Do While getAdjacentCell(curX, curY, direcc) = 0
|
||||
Select Case direcc
|
||||
Case "l": curX -= 1
|
||||
Case "r": curX += 1
|
||||
Case "u": curY -= 1
|
||||
Case "d": curY += 1
|
||||
End Select
|
||||
Loop
|
||||
End Sub
|
||||
|
||||
Sub processBlock(x As Integer, y As Integer, direcc As String)
|
||||
Dim As Integer merge = 0, mergeDirX, mergeDirY
|
||||
If gGrid(x, y) <> 0 Then ' have block
|
||||
moveToObstacle(x, y, direcc) ' figure out where it can be moved to
|
||||
If getAdjacentCell(curX, curY, direcc) = gGrid(x, y) And wasMerge = 0 Then ' obstacle can be merged with
|
||||
merge = 1
|
||||
wasMerge = 1
|
||||
Else
|
||||
wasMerge = 0
|
||||
End If
|
||||
|
||||
If curX <> x Or curY <> y Or merge = 1 Then
|
||||
mergeDirX = 0
|
||||
mergeDirY = 0
|
||||
If merge = 1 Then
|
||||
Select Case direcc
|
||||
Case "l": mergeDirX = -1
|
||||
Case "r": mergeDirX = 1
|
||||
Case "u": mergeDirY = -1
|
||||
Case "d": mergeDirY = 1
|
||||
End Select
|
||||
End If
|
||||
|
||||
moveBlock(x, y, curX + mergeDirX, curY + mergeDirY, merge) ' move to before obstacle or merge
|
||||
hasMoved = 1
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Sub renderGrid
|
||||
Dim As Integer x, y
|
||||
For x = 0 To gGridSize - 1
|
||||
For y = 0 To gGridSize - 1
|
||||
drawNumber(gGrid(x, y), x, y)
|
||||
Next y
|
||||
Next x
|
||||
End Sub
|
||||
|
||||
Sub updateScore
|
||||
Locate 1, 10 : Print Using "Score: #####"; gScore
|
||||
End Sub
|
||||
|
||||
Sub processMove(direcc As String) '' direcc can be 'l', 'r', 'u', or 'd'
|
||||
Dim As Integer x, y
|
||||
hasMoved = 0
|
||||
|
||||
If direcc = "l" Then
|
||||
For y = 0 To gGridSize - 1
|
||||
wasMerge = 0
|
||||
For x = 0 To gGridSize - 1
|
||||
processBlock(x,y,direcc)
|
||||
Next x
|
||||
Next y
|
||||
Elseif direcc = "r" Then
|
||||
For y = 0 To gGridSize - 1
|
||||
wasMerge = 0
|
||||
For x = gGridSize - 1 To 0 Step -1
|
||||
processBlock(x,y,direcc)
|
||||
Next x
|
||||
Next y
|
||||
Elseif direcc = "u" Then
|
||||
For x = 0 To gGridSize - 1
|
||||
wasMerge = 0
|
||||
For y = 0 To gGridSize - 1
|
||||
processBlock(x,y,direcc)
|
||||
Next y
|
||||
Next x
|
||||
Elseif direcc = "d" Then
|
||||
For x = 0 To gGridSize - 1
|
||||
wasMerge = 0
|
||||
For y = gGridSize - 1 To 0 Step -1
|
||||
processBlock(x,y,direcc)
|
||||
Next y
|
||||
Next x
|
||||
End If
|
||||
|
||||
If hasMoved = 1 Then addblock
|
||||
renderGrid
|
||||
updateScore
|
||||
End Sub
|
||||
|
||||
|
||||
'--- Main Program ---
|
||||
Screen 8
|
||||
Windowtitle "2048"
|
||||
Palette 1, pColor(35, 33, 31)
|
||||
Palette 2, pColor(46, 46, 51)
|
||||
Palette 3, pColor(59, 56, 50)
|
||||
Palette 4, pColor(61, 44, 30)
|
||||
Palette 5, pColor(61, 37, 25)
|
||||
Palette 6, pColor(62, 31, 24)
|
||||
Palette 7, pColor(62, 24, 15)
|
||||
Palette 8, pColor(59, 52, 29)
|
||||
Palette 9, pColor(59, 51, 24)
|
||||
Palette 10, pColor(59, 50, 20)
|
||||
Palette 11, pColor(59, 49, 16)
|
||||
Palette 12, pColor(59, 49, 12)
|
||||
Palette 13, pColor(15, 15, 13)
|
||||
Palette 14, pColor(23, 22, 20)
|
||||
|
||||
Randomize Timer
|
||||
Cls
|
||||
Do
|
||||
initGrid
|
||||
initGraphicGrid
|
||||
renderGrid
|
||||
updateScore
|
||||
|
||||
gScore = 0
|
||||
|
||||
Locate 23, 10 : Print "Move with arrow keys."
|
||||
Locate 24, 12 : Print "(R)estart, (Q)uit"
|
||||
|
||||
Dim As String k
|
||||
Do
|
||||
Do
|
||||
k = Inkey
|
||||
Loop Until k <> ""
|
||||
|
||||
Select Case k
|
||||
Case EXTCHAR + Chr(72) 'up
|
||||
processMove("u")
|
||||
Case EXTCHAR + Chr(80) 'down
|
||||
processMove("d")
|
||||
Case EXTCHAR + Chr(77) 'right
|
||||
processMove("r")
|
||||
Case EXTCHAR + Chr(75) 'left
|
||||
processMove("l")
|
||||
Case "q", "Q", Chr(27) 'escape
|
||||
End
|
||||
Case "r", "R"
|
||||
Exit Do
|
||||
End Select
|
||||
Loop
|
||||
Loop
|
||||
269
Task/2048/Go/2048.go
Normal file
269
Task/2048/Go/2048.go
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
const maxPoints = 2048
|
||||
const (
|
||||
fieldSizeX = 4
|
||||
fieldSizeY = 4
|
||||
)
|
||||
const tilesAtStart = 2
|
||||
const probFor2 = 0.9
|
||||
|
||||
type button int
|
||||
|
||||
const (
|
||||
_ button = iota
|
||||
up
|
||||
down
|
||||
right
|
||||
left
|
||||
quit
|
||||
)
|
||||
|
||||
var labels = func() map[button]rune {
|
||||
m := make(map[button]rune, 4)
|
||||
m[up] = 'W'
|
||||
m[down] = 'S'
|
||||
m[right] = 'D'
|
||||
m[left] = 'A'
|
||||
return m
|
||||
}()
|
||||
var keybinding = func() map[rune]button {
|
||||
m := make(map[rune]button, 8)
|
||||
for b, r := range labels {
|
||||
m[r] = b
|
||||
if unicode.IsUpper(r) {
|
||||
r = unicode.ToLower(r)
|
||||
} else {
|
||||
r = unicode.ToUpper(r)
|
||||
}
|
||||
m[r] = b
|
||||
}
|
||||
m[0x03] = quit
|
||||
return m
|
||||
}()
|
||||
|
||||
var model = struct {
|
||||
Score int
|
||||
Field [fieldSizeY][fieldSizeX]int
|
||||
}{}
|
||||
|
||||
var view = func() *template.Template {
|
||||
maxWidth := 1
|
||||
for i := maxPoints; i >= 10; i /= 10 {
|
||||
maxWidth++
|
||||
}
|
||||
|
||||
w := maxWidth + 3
|
||||
r := make([]byte, fieldSizeX*w+1)
|
||||
for i := range r {
|
||||
if i%w == 0 {
|
||||
r[i] = '+'
|
||||
} else {
|
||||
r[i] = '-'
|
||||
}
|
||||
}
|
||||
rawBorder := string(r)
|
||||
|
||||
v, err := template.New("").Parse(`SCORE: {{.Score}}
|
||||
{{range .Field}}
|
||||
` + rawBorder + `
|
||||
|{{range .}} {{if .}}{{printf "%` + strconv.Itoa(maxWidth) + `d" .}}{{else}}` +
|
||||
strings.Repeat(" ", maxWidth) + `{{end}} |{{end}}{{end}}
|
||||
` + rawBorder + `
|
||||
|
||||
(` + string(labels[up]) + `)Up (` +
|
||||
string(labels[down]) + `)Down (` +
|
||||
string(labels[left]) + `)Left (` +
|
||||
string(labels[right]) + `)Right
|
||||
`)
|
||||
check(err)
|
||||
return v
|
||||
}()
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clear() {
|
||||
c := exec.Command("clear")
|
||||
c.Stdout = os.Stdout
|
||||
check(c.Run())
|
||||
}
|
||||
|
||||
func draw() {
|
||||
clear()
|
||||
check(view.Execute(os.Stdout, model))
|
||||
}
|
||||
|
||||
func addRandTile() (full bool) {
|
||||
free := make([]*int, 0, fieldSizeX*fieldSizeY)
|
||||
|
||||
for x := 0; x < fieldSizeX; x++ {
|
||||
for y := 0; y < fieldSizeY; y++ {
|
||||
if model.Field[y][x] == 0 {
|
||||
free = append(free, &model.Field[y][x])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val := 4
|
||||
if rand.Float64() < probFor2 {
|
||||
val = 2
|
||||
}
|
||||
*free[rand.Intn(len(free))] = val
|
||||
|
||||
return len(free) == 1
|
||||
}
|
||||
|
||||
type point struct{ x, y int }
|
||||
|
||||
func (p point) get() int { return model.Field[p.y][p.x] }
|
||||
func (p point) set(n int) { model.Field[p.y][p.x] = n }
|
||||
func (p point) inField() bool { return p.x >= 0 && p.y >= 0 && p.x < fieldSizeX && p.y < fieldSizeY }
|
||||
func (p *point) next(n point) { p.x += n.x; p.y += n.y }
|
||||
|
||||
func controller(key rune) (gameOver bool) {
|
||||
b := keybinding[key]
|
||||
|
||||
if b == 0 {
|
||||
return false
|
||||
}
|
||||
if b == quit {
|
||||
return true
|
||||
}
|
||||
|
||||
var starts []point
|
||||
var next point
|
||||
|
||||
switch b {
|
||||
case up:
|
||||
next = point{0, 1}
|
||||
starts = make([]point, fieldSizeX)
|
||||
for x := 0; x < fieldSizeX; x++ {
|
||||
starts[x] = point{x, 0}
|
||||
}
|
||||
case down:
|
||||
next = point{0, -1}
|
||||
starts = make([]point, fieldSizeX)
|
||||
for x := 0; x < fieldSizeX; x++ {
|
||||
starts[x] = point{x, fieldSizeY - 1}
|
||||
}
|
||||
case right:
|
||||
next = point{-1, 0}
|
||||
starts = make([]point, fieldSizeY)
|
||||
for y := 0; y < fieldSizeY; y++ {
|
||||
starts[y] = point{fieldSizeX - 1, y}
|
||||
}
|
||||
case left:
|
||||
next = point{1, 0}
|
||||
starts = make([]point, fieldSizeY)
|
||||
for y := 0; y < fieldSizeY; y++ {
|
||||
starts[y] = point{0, y}
|
||||
}
|
||||
}
|
||||
|
||||
moved := false
|
||||
winning := false
|
||||
|
||||
for _, s := range starts {
|
||||
n := s
|
||||
move := func(set int) {
|
||||
moved = true
|
||||
s.set(set)
|
||||
n.set(0)
|
||||
}
|
||||
for n.next(next); n.inField(); n.next(next) {
|
||||
if s.get() != 0 {
|
||||
if n.get() == s.get() {
|
||||
score := s.get() * 2
|
||||
model.Score += score
|
||||
winning = score >= maxPoints
|
||||
|
||||
move(score)
|
||||
s.next(next)
|
||||
} else if n.get() != 0 {
|
||||
s.next(next)
|
||||
if s.get() == 0 {
|
||||
move(n.get())
|
||||
}
|
||||
}
|
||||
} else if n.get() != 0 {
|
||||
move(n.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !moved {
|
||||
return false
|
||||
}
|
||||
|
||||
lost := false
|
||||
if addRandTile() {
|
||||
lost = true
|
||||
Out:
|
||||
for x := 0; x < fieldSizeX; x++ {
|
||||
for y := 0; y < fieldSizeY; y++ {
|
||||
if (y > 0 && model.Field[y][x] == model.Field[y-1][x]) ||
|
||||
(x > 0 && model.Field[y][x] == model.Field[y][x-1]) {
|
||||
lost = false
|
||||
break Out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
draw()
|
||||
|
||||
if winning {
|
||||
fmt.Println("You win!")
|
||||
return true
|
||||
}
|
||||
if lost {
|
||||
fmt.Println("Game Over")
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
oldState, err := terminal.MakeRaw(0)
|
||||
check(err)
|
||||
defer terminal.Restore(0, oldState)
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
for i := tilesAtStart; i > 0; i-- {
|
||||
addRandTile()
|
||||
}
|
||||
draw()
|
||||
|
||||
stdin := bufio.NewReader(os.Stdin)
|
||||
|
||||
readKey := func() rune {
|
||||
r, _, err := stdin.ReadRune()
|
||||
check(err)
|
||||
return r
|
||||
}
|
||||
|
||||
for !controller(readKey()) {
|
||||
}
|
||||
}
|
||||
132
Task/2048/Haskell/2048.hs
Normal file
132
Task/2048/Haskell/2048.hs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import System.IO
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import Control.Monad
|
||||
import Data.Random
|
||||
import Data.Random.Distribution.Categorical
|
||||
import System.Console.ANSI
|
||||
import Control.Lens
|
||||
|
||||
-- Logic
|
||||
|
||||
-- probability to get a 4
|
||||
prob4 :: Double
|
||||
prob4 = 0.1
|
||||
|
||||
type Position = [[Int]]
|
||||
|
||||
combine, shift :: [Int]->[Int]
|
||||
combine (x:y:l) | x==y = (2*x) : combine l
|
||||
combine (x:l) = x : combine l
|
||||
combine [] = []
|
||||
|
||||
shift l = take (length l) $ combine (filter (>0) l) ++ [0,0..]
|
||||
|
||||
reflect :: [[a]] ->[[a]]
|
||||
reflect = map reverse
|
||||
|
||||
type Move = Position -> Position
|
||||
|
||||
left, right, up, down :: Move
|
||||
left = map shift
|
||||
right = reflect . left . reflect
|
||||
up = transpose . left . transpose
|
||||
down = transpose . right . transpose
|
||||
|
||||
progress :: Eq a => (a -> a) -> a -> Maybe a
|
||||
progress f pos = if pos==next_pos then Nothing else Just next_pos where next_pos= f pos
|
||||
|
||||
lost, win:: Position -> Bool
|
||||
lost pos = all isNothing [progress move pos| move<-[left,right,up,down] ]
|
||||
|
||||
win = any $ any (>=2048)
|
||||
|
||||
go :: Position -> Maybe Move -> Maybe Position
|
||||
go pos move = move >>= flip progress pos
|
||||
|
||||
|
||||
{-
|
||||
-- Adding 2 or 4 without lens:
|
||||
update l i a = l1 ++ a : l2 where (l1,_:l2)=splitAt i l
|
||||
indicesOf l = [0..length l-1]
|
||||
|
||||
add a x y pos = update pos y $ update (pos !! y) x a
|
||||
|
||||
add2or4 :: Position -> RVar Position
|
||||
add2or4 pos = do
|
||||
(x,y) <- randomElement [(x,y) | y<-indicesOf pos, x<-indicesOf (pos!!y), pos!!y!!x ==0 ]
|
||||
a <- categorical [(0.9::Double,2), (0.1,4) ]
|
||||
return $ add a x y pos
|
||||
-}
|
||||
|
||||
-- or with lens:
|
||||
indicesOf :: [a] -> [ReifiedTraversal' [a] a]
|
||||
indicesOf l = [ Traversal $ ix i | i <- [0..length l - 1] ]
|
||||
|
||||
indices2Of :: [[a]] -> [ReifiedTraversal' [[a]] a]
|
||||
indices2Of ls = [ Traversal $ i.j | Traversal i <- indicesOf ls, let Just l = ls ^? i, Traversal j <- indicesOf l]
|
||||
|
||||
add2or4 :: Position -> RVar Position
|
||||
add2or4 pos = do
|
||||
xy <- randomElement [ xy | Traversal xy <- indices2Of pos, pos ^? xy == Just 0 ]
|
||||
a <- categorical [(1-prob4, 2), (prob4, 4) ]
|
||||
return $ pos & xy .~ a
|
||||
-- Easy, is'n it'?
|
||||
|
||||
-- Main loop
|
||||
play :: Position -> IO ()
|
||||
play pos = do
|
||||
c <- getChar
|
||||
case go pos $ lookup c [('D',left),('C',right),('A',up),('B',down)] of
|
||||
Nothing -> play pos
|
||||
Just pos1 -> do
|
||||
pos2 <- sample $ add2or4 pos1
|
||||
draw pos2
|
||||
when (win pos2 && not (win pos)) $ putStrLn $ "You win! You may keep going."
|
||||
if lost pos2 then putStrLn "You lost!"
|
||||
else play pos2
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
pos <- sample $ add2or4 $ replicate 4 (replicate 4 0)
|
||||
draw pos
|
||||
play pos
|
||||
|
||||
-- Rendering
|
||||
-- See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
||||
colors =
|
||||
[(0,"\ESC[38;5;234;48;5;250m ")
|
||||
,(2,"\ESC[38;5;234;48;5;255m 2 ")
|
||||
,(4,"\ESC[38;5;234;48;5;230m 4 ")
|
||||
,(8,"\ESC[38;5;15;48;5;208m 8 ")
|
||||
,(16,"\ESC[38;5;15;48;5;209m 16 ")
|
||||
,(32,"\ESC[38;5;15;48;5;203m 32 ")
|
||||
,(64,"\ESC[38;5;15;48;5;9m 64 ")
|
||||
,(128,"\ESC[38;5;15;48;5;228m 128 ")
|
||||
,(256,"\ESC[38;5;15;48;5;227m 256 ")
|
||||
,(512,"\ESC[38;5;15;48;5;226m 512 ")
|
||||
,(1024,"\ESC[38;5;15;48;5;221m 1024")
|
||||
,(2048,"\ESC[38;5;15;48;5;220m 2048")
|
||||
,(4096,"\ESC[38;5;15;48;5;0m 4096")
|
||||
,(8192,"\ESC[38;5;15;48;5;0m 8192")
|
||||
,(16384,"\ESC[38;5;15;48;5;0m16384")
|
||||
,(32768,"\ESC[38;5;15;48;5;0m32768")
|
||||
,(65536,"\ESC[38;5;15;48;5;0m65536")
|
||||
,(131072,"\ESC[38;5;15;48;5;90m131072")
|
||||
]
|
||||
|
||||
showTile x = fromJust (lookup x colors) ++ "\ESC[B\^H\^H\^H\^H\^H \ESC[A\ESC[C"
|
||||
|
||||
draw :: Position -> IO ()
|
||||
draw pos = do
|
||||
setSGR [Reset]
|
||||
clearScreen
|
||||
hideCursor
|
||||
hSetEcho stdin False
|
||||
hSetBuffering stdin NoBuffering
|
||||
setSGR [SetConsoleIntensity BoldIntensity]
|
||||
putStr "\ESC[38;5;234;48;5;248m" -- set board color
|
||||
setCursorPosition 0 0
|
||||
replicateM_ 13 $ putStrLn $ replicate 26 ' '
|
||||
setCursorPosition 1 1
|
||||
putStrLn $ intercalate "\n\n\n\ESC[C" $ concatMap showTile `map` pos
|
||||
106
Task/2048/J/2048-1.j
Normal file
106
Task/2048/J/2048-1.j
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
NB. 2048.ijs script
|
||||
NB. =========================================================
|
||||
NB. 2048 game engine
|
||||
|
||||
require 'guid'
|
||||
([ 9!:1) _2 (3!:4) , guids 1 NB. randomly set initial random seed
|
||||
|
||||
coclass 'g2048'
|
||||
Target=: 2048
|
||||
|
||||
new2048=: verb define
|
||||
Gridsz=: 4 4
|
||||
Points=: Score=: 0
|
||||
Grid=: newnum^:2 ] Gridsz $ 0
|
||||
)
|
||||
|
||||
newnum=: verb define
|
||||
num=. 2 4 {~ 0.1 > ?0 NB. 10% chance of 4
|
||||
idx=. 4 $. $. 0 = y NB. indicies of 0s
|
||||
if. #idx do. NB. handle full grid
|
||||
idx=. ,/ ({~ 1 ? #) idx NB. choose an index
|
||||
num (<idx)} y
|
||||
else. return. y
|
||||
end.
|
||||
)
|
||||
|
||||
mskmerge=: [: >/\.&.|. 2 =/\ ,&_1
|
||||
mergerow=: ((* >:) #~ _1 |. -.@]) mskmerge
|
||||
scorerow=: +/@(+: #~ mskmerge)
|
||||
|
||||
compress=: -.&0
|
||||
toLeft=: 1 :'4&{.@(u@compress)"1'
|
||||
toRight=: 1 : '_4&{.@(u@compress&.|.)"1'
|
||||
toUp=: 1 : '(4&{.@(u@compress)"1)&.|:'
|
||||
toDown=: 1 : '(_4&{.@(u@compress&.|.)"1)&.|:'
|
||||
|
||||
move=: conjunction define
|
||||
Points=: +/@, v Grid
|
||||
update newnum^:(Grid -.@-: ]) u Grid
|
||||
)
|
||||
|
||||
noMoves=: (0 -.@e. ,)@(mergerow toRight , mergerow toLeft , mergerow toUp ,: mergerow toDown)
|
||||
hasWon=: Target e. ,
|
||||
|
||||
eval=: verb define
|
||||
Score=: Score + Points
|
||||
isend=. (noMoves , hasWon) y
|
||||
msg=. isend # 'You lost!!';'You Won!!'
|
||||
if. -. isend=. +./ isend do.
|
||||
Points=: 0
|
||||
msg=. 'Score is ',(": Score)
|
||||
end.
|
||||
isend;msg
|
||||
)
|
||||
|
||||
showGrid=: echo
|
||||
|
||||
NB. =========================================================
|
||||
NB. Console user interface
|
||||
|
||||
g2048Con_z_=: conew&'g2048con'
|
||||
|
||||
coclass 'g2048con'
|
||||
coinsert 'g2048'
|
||||
|
||||
create=: verb define
|
||||
echo Instructions
|
||||
startnew y
|
||||
)
|
||||
|
||||
destroy=: codestroy
|
||||
quit=: destroy
|
||||
|
||||
startnew=: update@new2048
|
||||
|
||||
left=: 3 :'mergerow toLeft move (scorerow toLeft)'
|
||||
right=: 3 :'mergerow toRight move (scorerow toRight)'
|
||||
up=: 3 :'mergerow toUp move (scorerow toUp)'
|
||||
down=: 3 :'mergerow toDown move (scorerow toDown)'
|
||||
|
||||
update=: verb define
|
||||
Grid=: y NB. update global Grid
|
||||
'isend msg'=. eval y
|
||||
echo msg
|
||||
showGrid y
|
||||
if. isend do. destroy '' end.
|
||||
empty''
|
||||
)
|
||||
|
||||
Instructions=: noun define
|
||||
=== 2048 ===
|
||||
Object:
|
||||
Create the number 2048 by merging numbers.
|
||||
|
||||
How to play:
|
||||
When 2 numbers the same touch, they merge.
|
||||
- move numbers using the commands below:
|
||||
right__grd ''
|
||||
left__grd ''
|
||||
up__grd ''
|
||||
down__grd ''
|
||||
- quit a game:
|
||||
quit__grd ''
|
||||
- start a new game:
|
||||
grd=: g2048Con ''
|
||||
)
|
||||
20
Task/2048/J/2048-2.j
Normal file
20
Task/2048/J/2048-2.j
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
grd=: g2048Con ''
|
||||
|
||||
Score is 0
|
||||
0 0 0 2
|
||||
0 2 0 0
|
||||
0 0 0 0
|
||||
0 0 0 0
|
||||
right__grd ''
|
||||
Score is 0
|
||||
0 0 0 2
|
||||
0 0 0 2
|
||||
0 0 0 0
|
||||
0 0 0 2
|
||||
down__grd ''
|
||||
Score is 4
|
||||
0 0 0 0
|
||||
0 0 0 0
|
||||
0 0 4 4
|
||||
0 0 0 2
|
||||
...
|
||||
298
Task/2048/Java/2048.java
Normal file
298
Task/2048/Java/2048.java
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Random;
|
||||
import javax.swing.*;
|
||||
|
||||
public class Game2048 extends JPanel {
|
||||
|
||||
enum State {
|
||||
start, won, running, over
|
||||
}
|
||||
|
||||
final Color[] colorTable = {
|
||||
new Color(0x701710), new Color(0xFFE4C3), new Color(0xfff4d3),
|
||||
new Color(0xffdac3), new Color(0xe7b08e), new Color(0xe7bf8e),
|
||||
new Color(0xffc4c3), new Color(0xE7948e), new Color(0xbe7e56),
|
||||
new Color(0xbe5e56), new Color(0x9c3931), new Color(0x701710)};
|
||||
|
||||
final static int target = 2048;
|
||||
|
||||
static int highest;
|
||||
static int score;
|
||||
|
||||
private Color gridColor = new Color(0xBBADA0);
|
||||
private Color emptyColor = new Color(0xCDC1B4);
|
||||
private Color startColor = new Color(0xFFEBCD);
|
||||
|
||||
private Random rand = new Random();
|
||||
|
||||
private Tile[][] tiles;
|
||||
private int side = 4;
|
||||
private State gamestate = State.start;
|
||||
private boolean checkingAvailableMoves;
|
||||
|
||||
public Game2048() {
|
||||
setPreferredSize(new Dimension(900, 700));
|
||||
setBackground(new Color(0xFAF8EF));
|
||||
setFont(new Font("SansSerif", Font.BOLD, 48));
|
||||
setFocusable(true);
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
startGame();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
switch (e.getKeyCode()) {
|
||||
case KeyEvent.VK_UP:
|
||||
moveUp();
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
moveDown();
|
||||
break;
|
||||
case KeyEvent.VK_LEFT:
|
||||
moveLeft();
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
moveRight();
|
||||
break;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics gg) {
|
||||
super.paintComponent(gg);
|
||||
Graphics2D g = (Graphics2D) gg;
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
drawGrid(g);
|
||||
}
|
||||
|
||||
void startGame() {
|
||||
if (gamestate != State.running) {
|
||||
score = 0;
|
||||
highest = 0;
|
||||
gamestate = State.running;
|
||||
tiles = new Tile[side][side];
|
||||
addRandomTile();
|
||||
addRandomTile();
|
||||
}
|
||||
}
|
||||
|
||||
void drawGrid(Graphics2D g) {
|
||||
g.setColor(gridColor);
|
||||
g.fillRoundRect(200, 100, 499, 499, 15, 15);
|
||||
|
||||
if (gamestate == State.running) {
|
||||
|
||||
for (int r = 0; r < side; r++) {
|
||||
for (int c = 0; c < side; c++) {
|
||||
if (tiles[r][c] == null) {
|
||||
g.setColor(emptyColor);
|
||||
g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7);
|
||||
} else {
|
||||
drawTile(g, r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.setColor(startColor);
|
||||
g.fillRoundRect(215, 115, 469, 469, 7, 7);
|
||||
|
||||
g.setColor(gridColor.darker());
|
||||
g.setFont(new Font("SansSerif", Font.BOLD, 128));
|
||||
g.drawString("2048", 310, 270);
|
||||
|
||||
g.setFont(new Font("SansSerif", Font.BOLD, 20));
|
||||
|
||||
if (gamestate == State.won) {
|
||||
g.drawString("you made it!", 390, 350);
|
||||
|
||||
} else if (gamestate == State.over)
|
||||
g.drawString("game over", 400, 350);
|
||||
|
||||
g.setColor(gridColor);
|
||||
g.drawString("click to start a new game", 330, 470);
|
||||
g.drawString("(use arrow keys to move tiles)", 310, 530);
|
||||
}
|
||||
}
|
||||
|
||||
void drawTile(Graphics2D g, int r, int c) {
|
||||
int value = tiles[r][c].getValue();
|
||||
|
||||
g.setColor(colorTable[(int) (Math.log(value) / Math.log(2)) + 1]);
|
||||
g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7);
|
||||
String s = String.valueOf(value);
|
||||
|
||||
g.setColor(value < 128 ? colorTable[0] : colorTable[1]);
|
||||
|
||||
FontMetrics fm = g.getFontMetrics();
|
||||
int asc = fm.getAscent();
|
||||
int dec = fm.getDescent();
|
||||
|
||||
int x = 215 + c * 121 + (106 - fm.stringWidth(s)) / 2;
|
||||
int y = 115 + r * 121 + (asc + (106 - (asc + dec)) / 2);
|
||||
|
||||
g.drawString(s, x, y);
|
||||
}
|
||||
|
||||
|
||||
private void addRandomTile() {
|
||||
int pos = rand.nextInt(side * side);
|
||||
int row, col;
|
||||
do {
|
||||
pos = (pos + 1) % (side * side);
|
||||
row = pos / side;
|
||||
col = pos % side;
|
||||
} while (tiles[row][col] != null);
|
||||
|
||||
int val = rand.nextInt(10) == 0 ? 4 : 2;
|
||||
tiles[row][col] = new Tile(val);
|
||||
}
|
||||
|
||||
private boolean move(int countDownFrom, int yIncr, int xIncr) {
|
||||
boolean moved = false;
|
||||
|
||||
for (int i = 0; i < side * side; i++) {
|
||||
int j = Math.abs(countDownFrom - i);
|
||||
|
||||
int r = j / side;
|
||||
int c = j % side;
|
||||
|
||||
if (tiles[r][c] == null)
|
||||
continue;
|
||||
|
||||
int nextR = r + yIncr;
|
||||
int nextC = c + xIncr;
|
||||
|
||||
while (nextR >= 0 && nextR < side && nextC >= 0 && nextC < side) {
|
||||
|
||||
Tile next = tiles[nextR][nextC];
|
||||
Tile curr = tiles[r][c];
|
||||
|
||||
if (next == null) {
|
||||
|
||||
if (checkingAvailableMoves)
|
||||
return true;
|
||||
|
||||
tiles[nextR][nextC] = curr;
|
||||
tiles[r][c] = null;
|
||||
r = nextR;
|
||||
c = nextC;
|
||||
nextR += yIncr;
|
||||
nextC += xIncr;
|
||||
moved = true;
|
||||
|
||||
} else if (next.canMergeWith(curr)) {
|
||||
|
||||
if (checkingAvailableMoves)
|
||||
return true;
|
||||
|
||||
int value = next.mergeWith(curr);
|
||||
if (value > highest)
|
||||
highest = value;
|
||||
score += value;
|
||||
tiles[r][c] = null;
|
||||
moved = true;
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (moved) {
|
||||
if (highest < target) {
|
||||
clearMerged();
|
||||
addRandomTile();
|
||||
if (!movesAvailable()) {
|
||||
gamestate = State.over;
|
||||
}
|
||||
} else if (highest == target)
|
||||
gamestate = State.won;
|
||||
}
|
||||
|
||||
return moved;
|
||||
}
|
||||
|
||||
boolean moveUp() {
|
||||
return move(0, -1, 0);
|
||||
}
|
||||
|
||||
boolean moveDown() {
|
||||
return move(side * side - 1, 1, 0);
|
||||
}
|
||||
|
||||
boolean moveLeft() {
|
||||
return move(0, 0, -1);
|
||||
}
|
||||
|
||||
boolean moveRight() {
|
||||
return move(side * side - 1, 0, 1);
|
||||
}
|
||||
|
||||
void clearMerged() {
|
||||
for (Tile[] row : tiles)
|
||||
for (Tile tile : row)
|
||||
if (tile != null)
|
||||
tile.setMerged(false);
|
||||
}
|
||||
|
||||
boolean movesAvailable() {
|
||||
checkingAvailableMoves = true;
|
||||
boolean hasMoves = moveUp() || moveDown() || moveLeft() || moveRight();
|
||||
checkingAvailableMoves = false;
|
||||
return hasMoves;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JFrame f = new JFrame();
|
||||
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
f.setTitle("2048");
|
||||
f.setResizable(true);
|
||||
f.add(new Game2048(), BorderLayout.CENTER);
|
||||
f.pack();
|
||||
f.setLocationRelativeTo(null);
|
||||
f.setVisible(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class Tile {
|
||||
private boolean merged;
|
||||
private int value;
|
||||
|
||||
Tile(int val) {
|
||||
value = val;
|
||||
}
|
||||
|
||||
int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
void setMerged(boolean m) {
|
||||
merged = m;
|
||||
}
|
||||
|
||||
boolean canMergeWith(Tile other) {
|
||||
return !merged && other != null && !other.merged && value == other.getValue();
|
||||
}
|
||||
|
||||
int mergeWith(Tile other) {
|
||||
if (canMergeWith(other)) {
|
||||
value *= 2;
|
||||
merged = true;
|
||||
return value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
179
Task/2048/JavaScript/2048.js
Normal file
179
Task/2048/JavaScript/2048.js
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/* Tile object: */
|
||||
|
||||
function Tile(pos, val, puzzle){
|
||||
this.pos = pos;
|
||||
this.val = val;
|
||||
this.puzzle = puzzle;
|
||||
this.merging = false;
|
||||
|
||||
this.getCol = () => Math.round(this.pos % 4);
|
||||
this.getRow = () => Math.floor(this.pos / 4);
|
||||
|
||||
/* draw tile on a P5.js canvas: */
|
||||
|
||||
this.show = function(){
|
||||
let padding = this.merging ? 0 : 5;
|
||||
let size = 0.25*width;
|
||||
noStroke();
|
||||
colorMode(HSB, 255);
|
||||
fill(10*(11 - Math.log2(this.val)), 50 + 15*Math.log2(this.val), 200);
|
||||
rect(this.getCol()*size + padding, this.getRow()*size + padding, size - 2*padding, size - 2*padding);
|
||||
fill(255);
|
||||
textSize(0.1*width);
|
||||
textAlign(CENTER, CENTER);
|
||||
text(this.val, (this.getCol() + 0.5)*size, (this.getRow() + 0.5)*size);
|
||||
}
|
||||
|
||||
/* move tile in a given direction: */
|
||||
|
||||
this.move = function(dir){
|
||||
let col = this.getCol() + (1 - 2*(dir < 0))*Math.abs(dir)%4;
|
||||
let row = this.getRow() + (1 - 2*(dir < 0))*Math.floor(Math.abs(dir)/4);
|
||||
let target = this.puzzle.getTile(this.pos + dir);
|
||||
|
||||
if (col < 0 || col > 3 || row < 0 || row > 3) {
|
||||
/* target position out of bounds */
|
||||
return false;
|
||||
} else if (target){
|
||||
/* tile blocked by other tile */
|
||||
if(this.merging || target.merging || target.val !== this.val)
|
||||
return false;
|
||||
|
||||
/* merge with target tile (equal values):*/
|
||||
target.val += this.val;
|
||||
target.merging = true;
|
||||
this.puzzle.score += target.val;
|
||||
this.puzzle.removeTile(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* move tile: */
|
||||
this.pos += dir;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Puzzle object: */
|
||||
|
||||
function Puzzle(){
|
||||
this.tiles = [];
|
||||
this.dir = 0;
|
||||
this.score = 0;
|
||||
this.hasMoved = false;
|
||||
this.validPositions = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
|
||||
|
||||
this.getOpenPositions = () => this.validPositions.filter(i => this.tiles.map(x => x.pos).indexOf(i) === -1);
|
||||
this.getTile = pos => this.tiles.filter(x => x.pos === pos)[0];
|
||||
this.removeTile = tile => this.tiles.splice(this.tiles.indexOf(tile), 1);
|
||||
this.winCondition = () => this.tiles.some(x => x.val === 2048);
|
||||
|
||||
/* check for valid moves: */
|
||||
|
||||
this.validMoves = function(){
|
||||
/* return true if there are empty spaces */
|
||||
if(this.tiles.length < 16)
|
||||
return true;
|
||||
|
||||
/* otherwise check for neighboring tiles with the same value */
|
||||
let res = false;
|
||||
this.tiles.sort((x,y) => x.pos - y.pos);
|
||||
for(let i = 0; i < 16; i++)
|
||||
res = res || ( (i%4 < 3) ? this.tiles[i].val === this.tiles[i+1].val : false )
|
||||
|| ( (i < 12) ? this.tiles[i].val === this.tiles[i+4].val : false );
|
||||
return res;
|
||||
}
|
||||
|
||||
/* check win and lose condition: */
|
||||
|
||||
this.checkGameState = function(){
|
||||
if(this.winCondition()){
|
||||
alert('You win!');
|
||||
} else if (!this.validMoves()){
|
||||
alert('You Lose!');
|
||||
this.restart();
|
||||
}
|
||||
}
|
||||
|
||||
this.restart = function(){
|
||||
this.tiles = [];
|
||||
this.dir = 0;
|
||||
this.score = 0;
|
||||
this.hasMoved = false;
|
||||
this.generateTile();
|
||||
this.generateTile();
|
||||
}
|
||||
|
||||
/* draw the board on the p5.js canvas: */
|
||||
|
||||
this.show = function(){
|
||||
background(200);
|
||||
fill(255);
|
||||
textSize(0.05*width);
|
||||
textAlign(CENTER, TOP);
|
||||
text("SCORE: " + this.score, 0.5*width, width);
|
||||
|
||||
for(let tile of this.tiles)
|
||||
tile.show();
|
||||
}
|
||||
|
||||
/* update the board: */
|
||||
|
||||
this.animate = function(){
|
||||
if(this.dir === 0)
|
||||
return;
|
||||
|
||||
/* move all tiles in a given direction */
|
||||
let moving = false;
|
||||
this.tiles.sort((x,y) => this.dir*(y.pos - x.pos));
|
||||
for(let tile of this.tiles)
|
||||
moving = moving || tile.move(this.dir);
|
||||
|
||||
/* check if the move is finished and generate a new tile */
|
||||
if(this.hasMoved && !moving){
|
||||
this.dir = 0;
|
||||
this.generateTile();
|
||||
|
||||
for(let tile of this.tiles)
|
||||
tile.merging = false;
|
||||
}
|
||||
this.hasMoved = moving;
|
||||
}
|
||||
|
||||
this.generateTile = function(){
|
||||
let positions = this.getOpenPositions();
|
||||
let pos = positions[Math.floor(Math.random()*positions.length)];
|
||||
let val = 2 + 2*Math.floor(Math.random()*1.11);
|
||||
this.tiles.push(new Tile(pos, val, this));
|
||||
}
|
||||
this.generateTile();
|
||||
this.generateTile();
|
||||
|
||||
/* process key inputs: */
|
||||
|
||||
this.keyHandler = function(key){
|
||||
if (key === UP_ARROW) this.dir = -4
|
||||
else if (key === DOWN_ARROW) this.dir = 4
|
||||
else if (key === RIGHT_ARROW) this.dir = 1
|
||||
else if (key === LEFT_ARROW) this.dir = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let game;
|
||||
|
||||
function setup() {
|
||||
createCanvas(400, 420);
|
||||
game = new Puzzle();
|
||||
}
|
||||
|
||||
/* game loop: */
|
||||
|
||||
function draw() {
|
||||
game.checkGameState();
|
||||
game.animate();
|
||||
game.show();
|
||||
}
|
||||
|
||||
function keyPressed(){
|
||||
game.keyHandler(keyCode);
|
||||
}
|
||||
171
Task/2048/Julia/2048.julia
Normal file
171
Task/2048/Julia/2048.julia
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
using Gtk.ShortNames
|
||||
|
||||
@enum Direction2048 Right Left Up Down
|
||||
|
||||
"""
|
||||
shifttiles!
|
||||
The adding and condensing code is for a leftward shift, so if the move is not
|
||||
leftward, this will rotate matrix to make move leftward, move, then undo rotation.
|
||||
"""
|
||||
function shifttiles!(b, siz, direction)
|
||||
if direction == Right
|
||||
tmpb = rot180(b); points, winner = leftshift!(tmpb, siz); tmpb = rot180(tmpb)
|
||||
elseif direction == Up
|
||||
tmpb = rotl90(b); points, winner = leftshift!(tmpb, siz); tmpb = rotr90(tmpb)
|
||||
elseif direction == Down
|
||||
tmpb = rotr90(b); points, winner = leftshift!(tmpb, siz); tmpb = rotl90(tmpb)
|
||||
else # left movement function as coded
|
||||
return leftshift!(b, siz)
|
||||
end
|
||||
for i in 1:siz, j in 1:siz
|
||||
b[i,j] = tmpb[i,j] # copy tmpb contents back to b (modifies b)
|
||||
end
|
||||
points, winner
|
||||
end
|
||||
|
||||
|
||||
function compactleft!(b, siz, row)
|
||||
tmprow = zeros(Int, siz)
|
||||
tmppos = 1
|
||||
for j in 1:siz
|
||||
if b[row,j] != 0
|
||||
tmprow[tmppos] = b[row,j]
|
||||
tmppos += 1
|
||||
end
|
||||
end
|
||||
b[row,:] = tmprow
|
||||
end
|
||||
|
||||
"""
|
||||
leftshift!
|
||||
Work row by row. First, compact tiles to the left if possible. Second, find and
|
||||
replace paired tiles in the row, then re-compact. Keep score of merges and return
|
||||
as pointsgained. If a 2048 value tile is created, return a winner true value.
|
||||
"""
|
||||
function leftshift!(b, siz)
|
||||
pointsgained = 0
|
||||
winner = false
|
||||
for i in 1:siz
|
||||
compactleft!(b, siz, i)
|
||||
tmprow = zeros(Int, siz)
|
||||
tmppos = 1
|
||||
for j in 1:siz-1
|
||||
if b[i,j] == b[i,j+1]
|
||||
b[i,j] = 2 * b[i,j]
|
||||
b[i,j+1] = 0
|
||||
pointsgained += b[i,j]
|
||||
if b[i,j] == 2048 # made a 2048 tile, which wins game
|
||||
winner = true
|
||||
end
|
||||
end
|
||||
if b[i,j] != 0
|
||||
tmprow[tmppos] = b[i,j]
|
||||
tmppos += 1
|
||||
end
|
||||
end
|
||||
tmprow[siz] = b[i,siz]
|
||||
b[i,:] = tmprow
|
||||
compactleft!(b, siz, i)
|
||||
end
|
||||
pointsgained, winner
|
||||
end
|
||||
|
||||
"""
|
||||
app2048
|
||||
Run game app, with boardsize (choose 4 for original game) as an argument.
|
||||
"""
|
||||
function app2048(bsize)
|
||||
win = Window("2048 Game", 400, 400) |> (Frame() |> (box = Box(:v)))
|
||||
toolbar = Toolbar()
|
||||
newgame = ToolButton("New Game")
|
||||
set_gtk_property!(newgame, :label, "New Game")
|
||||
set_gtk_property!(newgame, :is_important, true)
|
||||
undomove = ToolButton("Undo Move")
|
||||
set_gtk_property!(undomove, :label, "Undo Move")
|
||||
set_gtk_property!(undomove, :is_important, true)
|
||||
map(w->push!(toolbar,w),[newgame,undomove])
|
||||
grid = Grid()
|
||||
map(w -> push!(box, w),[toolbar, grid])
|
||||
buttons = Array{Gtk.GtkButtonLeaf,2}(undef, bsize, bsize)
|
||||
for i in 1:bsize, j in 1:bsize
|
||||
grid[i,j] = buttons[i,j] = Button()
|
||||
set_gtk_property!(buttons[i,j], :expand, true)
|
||||
end
|
||||
board = zeros(Int, (bsize,bsize))
|
||||
pastboardstates = []
|
||||
score = 0
|
||||
gameover = false
|
||||
condition = Condition()
|
||||
won = ""
|
||||
|
||||
function update!()
|
||||
for i in 1:bsize, j in 1:bsize
|
||||
label = (board[i,j] > 0) ? board[i,j] : " "
|
||||
set_gtk_property!(buttons[i,j], :label, label)
|
||||
end
|
||||
set_gtk_property!(win, :title, "$won 2048 Game (Score: $score)")
|
||||
end
|
||||
function newrandomtile!()
|
||||
blanks = Array{Tuple{Int,Int},1}()
|
||||
for i in 1:bsize, j in 1:bsize
|
||||
if board[i,j] == 0
|
||||
push!(blanks, (i,j))
|
||||
end
|
||||
end
|
||||
if length(blanks) == 0
|
||||
gameover = true
|
||||
else
|
||||
i,j = rand(blanks)
|
||||
board[i,j] = (rand() > 0.8) ? 4 : 2
|
||||
end
|
||||
end
|
||||
function initialize!(w)
|
||||
won = ""
|
||||
gameover = false
|
||||
for i in 1:bsize, j in 1:bsize
|
||||
board[i,j] = 0
|
||||
set_gtk_property!(buttons[i,j], :label, " ")
|
||||
end
|
||||
newrandomtile!()
|
||||
update!()
|
||||
end
|
||||
function undo!(w)
|
||||
if gameover == false
|
||||
board = pop!(pastboardstates)
|
||||
update!()
|
||||
end
|
||||
end
|
||||
function keypress(w, event)
|
||||
presses = Dict(37 => Up, # code rotated 90 degrees
|
||||
38 => Left, # because of Gtk coordinates
|
||||
39 => Down, # y is downward positive
|
||||
40 => Right)
|
||||
keycode = event.hardware_keycode
|
||||
if haskey(presses, keycode) && gameover == false
|
||||
push!(pastboardstates, copy(board))
|
||||
newpoints, havewon = shifttiles!(board, bsize, presses[keycode])
|
||||
score += newpoints
|
||||
if havewon && won != "Winning"
|
||||
won = "Winning"
|
||||
info_dialog("You have won the game.")
|
||||
end
|
||||
newrandomtile!()
|
||||
update!()
|
||||
if gameover
|
||||
info_dialog("Game over.\nScore: $score")
|
||||
end
|
||||
end
|
||||
end
|
||||
endit(w) = notify(condition)
|
||||
initialize!(win)
|
||||
signal_connect(initialize!, newgame, :clicked)
|
||||
signal_connect(undo!,undomove, :clicked)
|
||||
signal_connect(endit, win, :destroy)
|
||||
signal_connect(keypress, win, "key-press-event")
|
||||
Gtk.showall(win)
|
||||
wait(condition)
|
||||
end
|
||||
|
||||
|
||||
const boardsize = 4
|
||||
app2048(boardsize)
|
||||
170
Task/2048/Kotlin/2048.kotlin
Normal file
170
Task/2048/Kotlin/2048.kotlin
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
|
||||
const val positiveGameOverMessage = "So sorry, but you won the game."
|
||||
const val negativeGameOverMessage = "So sorry, but you lost the game."
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val grid = arrayOf(
|
||||
arrayOf(0, 0, 0, 0),
|
||||
arrayOf(0, 0, 0, 0),
|
||||
arrayOf(0, 0, 0, 0),
|
||||
arrayOf(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
val gameOverMessage = run2048(grid)
|
||||
println(gameOverMessage)
|
||||
}
|
||||
|
||||
fun run2048(grid: Array<Array<Int>>): String {
|
||||
if (isGridSolved(grid)) return positiveGameOverMessage
|
||||
else if (isGridFull(grid)) return negativeGameOverMessage
|
||||
|
||||
val populatedGrid = spawnNumber(grid)
|
||||
display(populatedGrid)
|
||||
|
||||
return run2048(manipulateGrid(populatedGrid, waitForValidInput()))
|
||||
}
|
||||
|
||||
fun isGridSolved(grid: Array<Array<Int>>): Boolean = grid.any { row -> row.contains(2048) }
|
||||
fun isGridFull(grid: Array<Array<Int>>): Boolean = grid.all { row -> !row.contains(0) }
|
||||
|
||||
fun spawnNumber(grid: Array<Array<Int>>): Array<Array<Int>> {
|
||||
val coordinates = locateSpawnCoordinates(grid)
|
||||
val number = generateNumber()
|
||||
|
||||
return updateGrid(grid, coordinates, number)
|
||||
}
|
||||
|
||||
fun locateSpawnCoordinates(grid: Array<Array<Int>>): Pair<Int, Int> {
|
||||
val emptyCells = arrayListOf<Pair<Int, Int>>()
|
||||
grid.forEachIndexed { x, row ->
|
||||
row.forEachIndexed { y, cell ->
|
||||
if (cell == 0) emptyCells.add(Pair(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
return emptyCells[(Math.random() * (emptyCells.size - 1)).toInt()]
|
||||
}
|
||||
|
||||
fun generateNumber(): Int = if (Math.random() > 0.10) 2 else 4
|
||||
|
||||
fun updateGrid(grid: Array<Array<Int>>, at: Pair<Int, Int>, value: Int): Array<Array<Int>> {
|
||||
val updatedGrid = grid.copyOf()
|
||||
updatedGrid[at.first][at.second] = value
|
||||
return updatedGrid
|
||||
}
|
||||
|
||||
fun waitForValidInput(): String {
|
||||
val input = waitForInput()
|
||||
return if (isValidInput(input)) input else waitForValidInput()
|
||||
}
|
||||
|
||||
fun isValidInput(input: String): Boolean = arrayOf("a", "s", "d", "w").contains(input)
|
||||
|
||||
fun waitForInput(): String {
|
||||
val reader = BufferedReader(InputStreamReader(System.`in`))
|
||||
println("Direction? ")
|
||||
return reader.readLine()
|
||||
}
|
||||
|
||||
fun manipulateGrid(grid: Array<Array<Int>>, input: String): Array<Array<Int>> = when (input) {
|
||||
"a" -> shiftCellsLeft(grid)
|
||||
"s" -> shiftCellsDown(grid)
|
||||
"d" -> shiftCellsRight(grid)
|
||||
"w" -> shiftCellsUp(grid)
|
||||
else -> throw IllegalArgumentException("Expected one of [a, s, d, w]")
|
||||
}
|
||||
|
||||
fun shiftCellsLeft(grid: Array<Array<Int>>): Array<Array<Int>> =
|
||||
grid.map(::mergeAndOrganizeCells).toTypedArray()
|
||||
|
||||
fun shiftCellsRight(grid: Array<Array<Int>>): Array<Array<Int>> =
|
||||
grid.map { row -> mergeAndOrganizeCells(row.reversed().toTypedArray()).reversed().toTypedArray() }.toTypedArray()
|
||||
|
||||
fun shiftCellsUp(grid: Array<Array<Int>>): Array<Array<Int>> {
|
||||
val rows: Array<Array<Int>> = arrayOf(
|
||||
arrayOf(grid[0][0], grid[1][0], grid[2][0], grid[3][0]),
|
||||
arrayOf(grid[0][1], grid[1][1], grid[2][1], grid[3][1]),
|
||||
arrayOf(grid[0][2], grid[1][2], grid[2][2], grid[3][2]),
|
||||
arrayOf(grid[0][3], grid[1][3], grid[2][3], grid[3][3])
|
||||
)
|
||||
|
||||
val updatedGrid = grid.copyOf()
|
||||
|
||||
rows.map(::mergeAndOrganizeCells).forEachIndexed { rowIdx, row ->
|
||||
updatedGrid[0][rowIdx] = row[0]
|
||||
updatedGrid[1][rowIdx] = row[1]
|
||||
updatedGrid[2][rowIdx] = row[2]
|
||||
updatedGrid[3][rowIdx] = row[3]
|
||||
}
|
||||
|
||||
return updatedGrid
|
||||
}
|
||||
|
||||
fun shiftCellsDown(grid: Array<Array<Int>>): Array<Array<Int>> {
|
||||
val rows: Array<Array<Int>> = arrayOf(
|
||||
arrayOf(grid[3][0], grid[2][0], grid[1][0], grid[0][0]),
|
||||
arrayOf(grid[3][1], grid[2][1], grid[1][1], grid[0][1]),
|
||||
arrayOf(grid[3][2], grid[2][2], grid[1][2], grid[0][2]),
|
||||
arrayOf(grid[3][3], grid[2][3], grid[1][3], grid[0][3])
|
||||
)
|
||||
|
||||
val updatedGrid = grid.copyOf()
|
||||
|
||||
rows.map(::mergeAndOrganizeCells).forEachIndexed { rowIdx, row ->
|
||||
updatedGrid[3][rowIdx] = row[0]
|
||||
updatedGrid[2][rowIdx] = row[1]
|
||||
updatedGrid[1][rowIdx] = row[2]
|
||||
updatedGrid[0][rowIdx] = row[3]
|
||||
}
|
||||
|
||||
return updatedGrid
|
||||
}
|
||||
|
||||
fun mergeAndOrganizeCells(row: Array<Int>): Array<Int> = organize(merge(row.copyOf()))
|
||||
|
||||
fun merge(row: Array<Int>, idxToMatch: Int = 0, idxToCompare: Int = 1): Array<Int> {
|
||||
if (idxToMatch >= row.size) return row
|
||||
if (idxToCompare >= row.size) return merge(row, idxToMatch + 1, idxToMatch + 2)
|
||||
if (row[idxToMatch] == 0) return merge(row, idxToMatch + 1, idxToMatch + 2)
|
||||
|
||||
return if (row[idxToMatch] == row[idxToCompare]) {
|
||||
row[idxToMatch] *= 2
|
||||
row[idxToCompare] = 0
|
||||
merge(row, idxToMatch + 1, idxToMatch + 2)
|
||||
} else {
|
||||
if (row[idxToCompare] != 0) merge(row, idxToMatch + 1, idxToMatch + 2)
|
||||
else merge(row, idxToMatch, idxToCompare + 1)
|
||||
}
|
||||
}
|
||||
|
||||
fun organize(row: Array<Int>, idxToMatch: Int = 0, idxToCompare: Int = 1): Array<Int> {
|
||||
if (idxToMatch >= row.size) return row
|
||||
if (idxToCompare >= row.size) return organize(row, idxToMatch + 1, idxToMatch + 2)
|
||||
if (row[idxToMatch] != 0) return organize(row, idxToMatch + 1, idxToMatch + 2)
|
||||
|
||||
return if (row[idxToCompare] != 0) {
|
||||
row[idxToMatch] = row[idxToCompare]
|
||||
row[idxToCompare] = 0
|
||||
organize(row, idxToMatch + 1, idxToMatch + 2)
|
||||
} else {
|
||||
organize(row, idxToMatch, idxToCompare + 1)
|
||||
}
|
||||
}
|
||||
|
||||
fun display(grid: Array<Array<Int>>) {
|
||||
val prettyPrintableGrid = grid.map { row ->
|
||||
row.map { cell ->
|
||||
if (cell == 0) " " else java.lang.String.format("%4d", cell)
|
||||
}
|
||||
}
|
||||
|
||||
println("New Grid:")
|
||||
prettyPrintableGrid.forEach { row ->
|
||||
println("+----+----+----+----+")
|
||||
row.forEach { print("|$it") }
|
||||
println("|")
|
||||
}
|
||||
println("+----+----+----+----+")
|
||||
}
|
||||
226
Task/2048/Latitude/2048.latitude
Normal file
226
Task/2048/Latitude/2048.latitude
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
use 'format import '[format].
|
||||
use 'random.
|
||||
|
||||
Pos := Object clone tap {
|
||||
|
||||
self x := 0.
|
||||
self y := 0.
|
||||
|
||||
self move := {
|
||||
localize.
|
||||
case ($1) do {
|
||||
when 'left do { pos (this x - 1, this y). }.
|
||||
when 'right do { pos (this x + 1, this y). }.
|
||||
when 'down do { pos (this x, this y + 1). }.
|
||||
when 'up do { pos (this x, this y - 1). }.
|
||||
}.
|
||||
}.
|
||||
|
||||
self == := {
|
||||
(self x == $1 x) and (self y == $1 y).
|
||||
}.
|
||||
|
||||
self inBounds? := {
|
||||
(self x >= 0) and (self x < 4) and (self y >= 0) and (self y < 4).
|
||||
}.
|
||||
|
||||
self toString := {
|
||||
format "pos (~S, ~S)" call (self x, self y).
|
||||
}.
|
||||
|
||||
}.
|
||||
|
||||
pos := {
|
||||
takes '[x, y].
|
||||
Pos clone tap {
|
||||
self x := x.
|
||||
self y := y.
|
||||
}.
|
||||
}.
|
||||
|
||||
allSquares := [] tap {
|
||||
localize.
|
||||
0 upto 4 visit {
|
||||
takes '[y].
|
||||
0 upto 4 visit {
|
||||
takes '[x].
|
||||
this pushBack (pos (x, y)).
|
||||
}.
|
||||
}.
|
||||
}.
|
||||
|
||||
sample := {
|
||||
$1 nth (random nextInt mod ($1 length)).
|
||||
}.
|
||||
|
||||
Grid ::= Object clone tap {
|
||||
|
||||
self grid := 16 times to (Array) map { 0. }.
|
||||
|
||||
self clone := {
|
||||
Parents above (parent self, 'clone) call tap {
|
||||
self grid := self grid clone.
|
||||
}.
|
||||
}.
|
||||
|
||||
toIndex := {
|
||||
$1 x + 4 * $1 y.
|
||||
}.
|
||||
|
||||
self at := {
|
||||
self grid nth (toIndex).
|
||||
}.
|
||||
|
||||
self at= := {
|
||||
self grid nth= (toIndex).
|
||||
}.
|
||||
|
||||
self isBlank? := {
|
||||
self at == 0.
|
||||
}.
|
||||
|
||||
self spawnNew := {
|
||||
localize.
|
||||
candidates := allSquares filter { this isBlank?. } to (Array).
|
||||
if (candidates empty?) then {
|
||||
'gameover.
|
||||
} else {
|
||||
p := sample (candidates).
|
||||
this at (p) = if (random nextInt mod 10 == 0) then 4 else 2.
|
||||
'okay.
|
||||
}.
|
||||
}.
|
||||
|
||||
canMoveCell := {
|
||||
takes '[grid, src, dir].
|
||||
dest := src move (dir).
|
||||
if (dest inBounds?) then {
|
||||
vs := grid at (src).
|
||||
vd := grid at (dest).
|
||||
(vs /= 0) and ((vd == 0) or (vs == vd)).
|
||||
} else {
|
||||
False.
|
||||
}.
|
||||
}.
|
||||
|
||||
self canMove := {
|
||||
localize.
|
||||
takes '[dir].
|
||||
allSquares any { canMoveCell (this, $1, dir). }.
|
||||
}.
|
||||
|
||||
self validMoves := {
|
||||
'[left, right, up, down] filter { parent self canMove. } to (Array).
|
||||
}.
|
||||
|
||||
;; Calculates the order of iteration for performing the moves
|
||||
axisCalc := {
|
||||
takes '[dir, major, minor].
|
||||
case (dir) do {
|
||||
when 'left do { pos (major, minor). }.
|
||||
when 'right do { pos (3 - major, minor). }.
|
||||
when 'up do { pos (minor, major). }.
|
||||
when 'down do { pos (minor, 3 - major). }.
|
||||
}.
|
||||
}.
|
||||
|
||||
moveFrom := {
|
||||
takes '[grid, src, dir, locked].
|
||||
dest := src move (dir).
|
||||
local 'result = Nil.
|
||||
dest inBounds? ifTrue {
|
||||
locked contains (dest) ifFalse {
|
||||
vs := grid at (src).
|
||||
vd := grid at (dest).
|
||||
cond {
|
||||
when (vd == 0) do {
|
||||
grid at (dest) = vs.
|
||||
grid at (src) = 0.
|
||||
result = moveFrom (grid, dest, dir, locked).
|
||||
}.
|
||||
when (vd == vs) do {
|
||||
grid at (dest) = vs + vd.
|
||||
grid at (src) = 0.
|
||||
result = moveFrom (grid, dest, dir, locked).
|
||||
;; We merged, so lock the final result cell.
|
||||
locked pushBack (result).
|
||||
}.
|
||||
}.
|
||||
}.
|
||||
}.
|
||||
(result) or (src).
|
||||
}.
|
||||
|
||||
self doMove := {
|
||||
localize.
|
||||
takes '[dir].
|
||||
locked := [].
|
||||
0 upto 4 do {
|
||||
takes '[major].
|
||||
0 upto 4 do {
|
||||
takes '[minor].
|
||||
src := axisCalc (dir, major, minor).
|
||||
moveFrom: this, src, dir, locked.
|
||||
}.
|
||||
}.
|
||||
}.
|
||||
|
||||
self pretty := {
|
||||
localize.
|
||||
lines := [].
|
||||
row := "+----+----+----+----+".
|
||||
lines pushBack (row).
|
||||
0 upto 4 visit {
|
||||
takes '[y].
|
||||
local 'line = "|".
|
||||
0 upto 4 visit {
|
||||
takes '[x].
|
||||
n := this at (pos (x, y)).
|
||||
if (n == 0) then {
|
||||
line = line ++ " |".
|
||||
} else {
|
||||
line = line ++ n toString padRight (" ", 4) ++ "|".
|
||||
}.
|
||||
}.
|
||||
lines pushBack (line).
|
||||
lines pushBack (row).
|
||||
}.
|
||||
lines joinText "\n".
|
||||
}.
|
||||
|
||||
self toArray := {
|
||||
allSquares map { parent self at. }.
|
||||
}.
|
||||
|
||||
}.
|
||||
|
||||
grid := Grid clone.
|
||||
endgame := loop* {
|
||||
;; Check for victory
|
||||
(grid toArray any { $1 >= 2048. }) ifTrue {
|
||||
last 'victory.
|
||||
}.
|
||||
;; Check for game over
|
||||
result := grid spawnNew.
|
||||
(result == 'gameover) ifTrue {
|
||||
last 'gameover.
|
||||
}.
|
||||
valid := grid validMoves.
|
||||
valid empty? ifTrue {
|
||||
last 'gameover.
|
||||
}.
|
||||
$stdout putln: grid pretty.
|
||||
move := loop* {
|
||||
$stdout puts: "Your move (left, right, up, down)> ".
|
||||
move := $stdin readln intern.
|
||||
valid contains (move) ifTrue { last (move). }.
|
||||
}.
|
||||
grid doMove (move).
|
||||
}.
|
||||
$stdout putln: grid pretty.
|
||||
|
||||
if (endgame == 'victory) then {
|
||||
$stdout putln: "You win!".
|
||||
} else {
|
||||
$stdout putln: "Better luck next time!".
|
||||
}.
|
||||
76
Task/2048/Lua/2048.lua
Normal file
76
Task/2048/Lua/2048.lua
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
-- 2048 for Lua 5.1-5.4, 12/3/2020 db
|
||||
local unpack = unpack or table.unpack -- for 5.3 +/- compatibility
|
||||
game = {
|
||||
cell = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
best = 0,
|
||||
draw = function(self)
|
||||
local t = self.cell
|
||||
print("+----+----+----+----+")
|
||||
for r=0,12,4 do
|
||||
print(string.format("|%4d|%4d|%4d|%4d|\n+----+----+----+----+",t[r+1],t[r+2],t[r+3],t[r+4]))
|
||||
end
|
||||
end,
|
||||
incr = function(self)
|
||||
local t,open = self.cell,{}
|
||||
for i=1,16 do if t[i]==0 then open[#open+1]=i end end
|
||||
t[open[math.random(#open)]] = math.random()<0.1 and 4 or 2
|
||||
end,
|
||||
pack = function(self,ofr,oto,ost,ifr,ito,ist)
|
||||
local t = self.cell
|
||||
for outer=ofr,oto,ost do
|
||||
local skip = 0
|
||||
for inner=ifr,ito,ist do
|
||||
local i = outer+inner
|
||||
if t[i]==0 then skip=skip+1 else if skip>0 then t[i-skip*ist],t[i],self.diff = t[i],0,true end end
|
||||
end
|
||||
end
|
||||
end,
|
||||
comb = function(self,ofr,oto,ost,ifr,ito,ist)
|
||||
local t = self.cell
|
||||
for outer=ofr,oto,ost do
|
||||
for inner=ifr,ito-ist,ist do
|
||||
local i,j = outer+inner,outer+inner+ist
|
||||
if t[i]>0 and t[i]==t[j] then t[i],t[j],self.diff,self.best = t[i]*2,0,true,math.max(self.best,t[i]*2) end
|
||||
end
|
||||
end
|
||||
end,
|
||||
move = function(self,dir)
|
||||
local loopdata = {{0,12,4,1,4,1},{0,12,4,4,1,-1},{1,4,1,0,12,4},{1,4,1,12,0,-4}}
|
||||
local ofr,oto,ost,ifr,ito,ist = unpack(loopdata[dir])
|
||||
self:pack(ofr,oto,ost,ifr,ito,ist)
|
||||
self:comb(ofr,oto,ost,ifr,ito,ist)
|
||||
self:pack(ofr,oto,ost,ifr,ito,ist)
|
||||
end,
|
||||
full = function(self)
|
||||
local t = self.cell
|
||||
for r=0,12,4 do
|
||||
for c=1,4 do
|
||||
local i,v = r+c,t[r+c]
|
||||
if (v==0) or (c>1 and t[i-1]==v) or (c<4 and t[i+1]==v) or (r>0 and t[i-4]==v) or (r<12 and t[i+4]==v) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
play = function(self)
|
||||
math.randomseed(os.time())
|
||||
self:incr()
|
||||
self:incr()
|
||||
while true do
|
||||
self:draw()
|
||||
if self.best==2048 then print("WIN!") break end
|
||||
if self:full() then print("LOSE!") break end
|
||||
io.write("Your move (wasd + enter, or q + enter to quit): ")
|
||||
local char = io.read()
|
||||
self.diff = false
|
||||
if (char=="a") then self:move(1)
|
||||
elseif (char=="d") then self:move(2)
|
||||
elseif (char=="w") then self:move(3)
|
||||
elseif (char=="s") then self:move(4)
|
||||
elseif (char=="q") then break end
|
||||
if self.diff then self:incr() end
|
||||
end
|
||||
end
|
||||
}
|
||||
game:play()
|
||||
123
Task/2048/M2000-Interpreter/2048.m2000
Normal file
123
Task/2048/M2000-Interpreter/2048.m2000
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
Module Game2048 {
|
||||
\\ 10% 4 and 90% 2
|
||||
Def GetTlleNumber()=If(Random(10)<2->4, 2)
|
||||
\\ tile
|
||||
Def Tile$(x)=If$(x=0->"[ ]", format$("[{0::-4}]", x))
|
||||
\\ empty board
|
||||
BoardTileRight=lambda (x, y)->x+y*4
|
||||
BoardTileLeft=lambda (x, y)->3-x+y*4
|
||||
BoardTileUp=lambda (x, y)->x*4+y
|
||||
BoardTileDown=lambda (x, y)->(3-x)*4+y
|
||||
Dim Board(0 to 15)
|
||||
Inventory EmptyTiles
|
||||
\\ Score is a statement but we can use it as a variable too.
|
||||
Score=0
|
||||
\\ Win is also a statement but we can use it as a variable too.
|
||||
Win=False
|
||||
ExitNow=False
|
||||
BoardDirection=BoardtileRight
|
||||
Process(BoardDirection)
|
||||
\\ Split Rem lines to insert start condition to check valid moves
|
||||
Rem : board(0)=2
|
||||
Rem : board(1)=2, 2, 2 ' place to (1), (2), (3)
|
||||
While len(EmptyTiles) {
|
||||
NewTile()
|
||||
DrawBoard()
|
||||
Action=False
|
||||
do {
|
||||
a$=key$
|
||||
if len(a$)=2 then {
|
||||
Action=true
|
||||
Select case Asc(mid$(a$,2))
|
||||
Case 72
|
||||
BoardDirection=BoardTileUp
|
||||
Case 75
|
||||
BoardDirection=BoardTileRight
|
||||
Case 77
|
||||
BoardDirection=BoardTileLeft
|
||||
Case 80
|
||||
BoardDirection=BoardTileDown
|
||||
Case 79 ' End key
|
||||
ExitNow=True
|
||||
Else
|
||||
Action=false
|
||||
end select
|
||||
}
|
||||
} until Action
|
||||
If ExitNow then exit
|
||||
Process(BoardDirection)
|
||||
}
|
||||
If Win then {
|
||||
Print "You Win"
|
||||
} Else {
|
||||
Print "You Loose"
|
||||
}
|
||||
End
|
||||
Sub Process(Boardtile)
|
||||
Inventory EmptyTiles ' clear inventory
|
||||
local where, i, j, k
|
||||
For i=0 to 3
|
||||
Gravity()
|
||||
k=boardtile(0,i)
|
||||
For j=1 to 3
|
||||
where=boardtile(j,i)
|
||||
if Board(where)<>0 then {
|
||||
if board(k)=board(where) then {
|
||||
board(k)*=2 : score+=board(where): board(where)=0
|
||||
if board(k)=2048 Then Win=True : ExitNow=true
|
||||
}
|
||||
}
|
||||
k=where
|
||||
Next j
|
||||
Gravity()
|
||||
For j=0 to 3
|
||||
where=boardtile(j,i)
|
||||
if board(where)=0 then Append EmptyTiles, where
|
||||
Next j
|
||||
Next i
|
||||
End Sub
|
||||
Sub NewTile()
|
||||
local m=EmptyTiles(Random(0, len(EmptyTiles)-1)!)
|
||||
Board(m)=GetTlleNumber()
|
||||
Delete EmptyTiles, m
|
||||
End Sub
|
||||
Sub DrawBoard()
|
||||
Refresh 2000
|
||||
Cls
|
||||
Cursor 0, 10
|
||||
Local Doc$, line$
|
||||
Document Doc$
|
||||
Doc$=Format$("Game 2048 Score {0}", score)
|
||||
\\ Using Report 2 we use rendering as text, with center justify
|
||||
Report 2, Doc$
|
||||
Doc$={
|
||||
}
|
||||
Local i, j
|
||||
For i=0 to 3
|
||||
line$=""
|
||||
For j=0 to 3
|
||||
line$+=Tile$(Board(BoardTileRight(j, i)))
|
||||
Next j
|
||||
Print Over $(2), Line$
|
||||
Print
|
||||
Doc$=Line$+{
|
||||
}
|
||||
Next i
|
||||
Report 2, "Next:Use Arrows | Exit: Press End"
|
||||
Refresh
|
||||
ClipBoard Doc$
|
||||
End Sub
|
||||
Sub Gravity()
|
||||
k=-1
|
||||
for j=0 to 3 {
|
||||
where=boardtile(j,i)
|
||||
if k=-1 then if board(where)=0 then k=j : continue
|
||||
if board(where)=0 then continue
|
||||
if k=-1 then continue
|
||||
board(boardtile(k,i))=board(where)
|
||||
board(where)=0
|
||||
k++
|
||||
}
|
||||
End Sub
|
||||
}
|
||||
Game2048
|
||||
132
Task/2048/MATLAB/2048-1.m
Normal file
132
Task/2048/MATLAB/2048-1.m
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
function field = puzzle2048(field)
|
||||
|
||||
if nargin < 1 || isempty(field)
|
||||
field = zeros(4);
|
||||
field = addTile(field);
|
||||
end
|
||||
|
||||
clc
|
||||
rng('shuffle')
|
||||
|
||||
while true
|
||||
oldField = field;
|
||||
clc
|
||||
score = displayField(field);
|
||||
|
||||
% check losing condition
|
||||
if isGameLost(field)
|
||||
sprintf('You lose with a score of %g.',score)
|
||||
return
|
||||
end
|
||||
|
||||
direction = input('Which direction? (w,a,s,d) (x for exit)\n','s');
|
||||
switch direction
|
||||
case 'w'
|
||||
field = moveUp(field);
|
||||
case 'a'
|
||||
field = rot90( moveUp( rot90(field,-1) ) );
|
||||
case 's'
|
||||
field = flipud( moveUp( flipud(field) ) );
|
||||
case 'd'
|
||||
field = rot90( moveUp( rot90(field) ), -1);
|
||||
case 'x'
|
||||
return
|
||||
end
|
||||
|
||||
if any(field>=2048,'all')
|
||||
disp('You win!')
|
||||
return
|
||||
end
|
||||
|
||||
if ~all(field==oldField,'all')
|
||||
field = addTile(field);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function gameIsLost = isGameLost(field)
|
||||
|
||||
if all(field,'all') && ...
|
||||
all(conv2(field,[1, -1],'same'),'all') && ...
|
||||
all(conv2(field,[1; -1],'same'),'all')
|
||||
gameIsLost = true;
|
||||
else
|
||||
gameIsLost = false;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function field = addTile(field)
|
||||
|
||||
freeIndices = find(~field);
|
||||
newIndex = freeIndices( randi(length(freeIndices)) );
|
||||
newNumber = 2 + 2 * (rand < 0.1);
|
||||
field(newIndex) = newNumber;
|
||||
|
||||
end
|
||||
|
||||
function score = displayField(field)
|
||||
|
||||
% Unicode characters for box drawings
|
||||
% 9484: U+250C Box Drawings Light Down and Right
|
||||
% 9472: U+2500 Box Drawings Light Horizontal
|
||||
% 9474: U+2502 Box Drawings Light Vertical
|
||||
% 9488: U+2510 Box Drawings Light Down and Left
|
||||
% 9492: U+2515 Box Drawings Light Up and Right
|
||||
% 9496: U+2518 Box Drawings Light Up and Left
|
||||
% 9500: U+251C Box Drawings Light Vertical and Right
|
||||
% 9508: U+2524 Box Drawings Light Vertical and Left
|
||||
% 9516: U+252C Box Drawings Light Down and Horizontal
|
||||
% 9524: U+2534 Box Drawings Light Up and Horizontal
|
||||
% 9532: U+253C Box Drawings Light Vertical and Horizontal
|
||||
score = sum(field(:));
|
||||
cellField = arrayfun(@num2str, field, 'UniformOutput', false);
|
||||
cellField = cellfun(@(x) [ char(9474) blanks(5-length(x)) x ' ' ], ...
|
||||
cellField, 'UniformOutput', false);
|
||||
topRow = repmat('-',1,7*size(field,2)+1);
|
||||
topRow(1:7:end) = char(9516);
|
||||
topRow([1 end]) = [ char(9484) char(9488) ];
|
||||
midRow = topRow;
|
||||
midRow(1:7:end) = char(9532);
|
||||
midRow([1 end]) = [ char(9500) char(9508) ];
|
||||
botRow = topRow;
|
||||
botRow(1:7:end) = char(9524);
|
||||
botRow([1 end]) = [ char(9492) char(9496) ];
|
||||
charField = topRow;
|
||||
for iRow = cellField'
|
||||
charField = [ charField; iRow{:} char(9474); midRow ];
|
||||
end
|
||||
charField(end,:) = botRow;
|
||||
charField(charField == '0') = ' ';
|
||||
|
||||
disp(charField)
|
||||
fprintf('\nYour score: %g\n', score)
|
||||
|
||||
end
|
||||
|
||||
function field = moveUp(field)
|
||||
|
||||
for iCol = 1:size(field,2)
|
||||
col = field(:,iCol);
|
||||
col = removeZeros(col);
|
||||
for iRow = 1:length(col)-1
|
||||
if col(iRow)==col(iRow+1)
|
||||
col(iRow:iRow+1) = [ 2*col(iRow); 0 ];
|
||||
end
|
||||
end
|
||||
col = removeZeros(col);
|
||||
if length(col) < length(field)
|
||||
col(end+1:length(field)) = 0;
|
||||
end
|
||||
field(:,iCol) = col;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function vector = removeZeros(vector)
|
||||
|
||||
vector(vector==0) = [];
|
||||
|
||||
end
|
||||
1
Task/2048/MATLAB/2048-2.m
Normal file
1
Task/2048/MATLAB/2048-2.m
Normal file
|
|
@ -0,0 +1 @@
|
|||
field = puzzle2048();
|
||||
1
Task/2048/MATLAB/2048-3.m
Normal file
1
Task/2048/MATLAB/2048-3.m
Normal file
|
|
@ -0,0 +1 @@
|
|||
field = puzzle2048(savedField);
|
||||
219
Task/2048/Maple/2048.maple
Normal file
219
Task/2048/Maple/2048.maple
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
macro(SP=DocumentTools:-SetProperty, GP=DocumentTools:-GetProperty);
|
||||
G := module()
|
||||
|
||||
export reset,f,getname;
|
||||
local a:=Matrix(4):
|
||||
local buttonpress:="False";
|
||||
local score:=0;
|
||||
local highscoreM,highscore,hscore,hname,M,j,k,z,e,move,r,c,q,w,checklose,loss,matrixtotextarea;
|
||||
|
||||
getname:=proc();
|
||||
hname:=GP("Name",value);
|
||||
buttonpress:="True";
|
||||
if score>hscore then
|
||||
M:=Matrix(1, 2, [[score, hname]]):
|
||||
ExportMatrix("this:///Score.csv",M);
|
||||
reset();
|
||||
else
|
||||
reset();
|
||||
end if;
|
||||
end proc;
|
||||
|
||||
matrixtotextarea:=proc(m)
|
||||
local m2,colors;
|
||||
colors:=["White","Beige","LightGrey",ColorTools:-Color("RGB", [255/255, 127/255, 80/255]),ColorTools:-Color("RGB", [255/255, 99/255, 71/255]),ColorTools:-Color("RGB", [255/255, 69/255, 0/255]),ColorTools:-Color("RGB", [255/255, 0/255, 0/255]),ColorTools:-Color("RGB", [255/255, 215/255, 0/255]), ColorTools:-Color("RGB", [255/255, 255/255, 0/255]),ColorTools:-Color("RGB", [204/255, 204/255, 0/255]),ColorTools:-Color("RGB", [153/255, 153/255, 0/255]),ColorTools:-Color("RGB", [102/255, 102/255, 0/255]), ColorTools:-Color("RGB", [0/255, 0/255, 0/255])];
|
||||
m2 := ArrayTools:-Reshape(m^%T, [16,1]):
|
||||
SP(seq([cat("TextArea",i),value,m2[i+1,1]],i=0..15));
|
||||
SP(seq(["Table1",fillcolor[(`if`(i+1<5,1,`if`(i+1<9 and i+1>4,2,`if`(i+1<13 and i+1>8,3, `if`(i+1<17 and i+1>12,4,1))))),(i mod 4)+1],`if`(m2[i+1,1]=0,colors[1],`if`(m2[i+1,1]=2,colors[2],`if`(m2[i+1,1]=4,colors[3],`if`(m2[i+1,1]=8,colors[4],`if`(m2[i+1,1]=16,colors[5],`if`(m2[i+1,1]=32,colors[6],`if`(m2[i+1,1]=64,colors[7],`if`(m2[i+1,1]=128,colors[8],`if`(m2[i+1,1]=256,colors[9],`if`(m2[i+1,1]=512,colors[10],`if`(m2[i+1,1]=1024,colors[11],`if`(m2[i+1,1]=2048,colors[12],`if`(m2[i+1,1]>2048,colors[13],"White")))))))))))))],i=0..15));
|
||||
SP(seq([cat("TextArea",i),fillcolor,`if`(m2[i+1,1]=0,colors[1],`if`(m2[i+1,1]=2,colors[2],`if`(m2[i+1,1]=4,colors[3],`if`(m2[i+1,1]=8,colors[4],`if`(m2[i+1,1]=16,colors[5],`if`(m2[i+1,1]=32,colors[6],`if`(m2[i+1,1]=64,colors[7],`if`(m2[i+1,1]=128,colors[8],`if`(m2[i+1,1]=256,colors[9],`if`(m2[i+1,1]=512,colors[10],`if`(m2[i+1,1]=1024,colors[11],`if`(m2[i+1,1]=2048,colors[12],`if`(m2[i+1,1]>2048,colors[13],"White")))))))))))))],i=0..15),refresh);
|
||||
SP(seq([cat("TextArea",i),fontcolor,`if`(m2[i+1,1]=0,colors[1],`if`(m2[i+1,1]=2,colors[13],`if`(m2[i+1,1]=4,colors[13],"White")))],i=0..15),refresh);
|
||||
end proc:
|
||||
|
||||
reset:=proc();
|
||||
highscoreM := Import("this:///Score.csv", output = Matrix);
|
||||
hscore := highscoreM[1,1];
|
||||
hname := highscoreM[1,2];
|
||||
highscore:=sprintf("%s",cat(hscore,"\n",hname));
|
||||
buttonpress:="False";
|
||||
a:=Matrix(4, 4, [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]):
|
||||
score:=0;
|
||||
matrixtotextarea(a);
|
||||
SP("Score/Lose",visible,true);
|
||||
SP("Score/Lose",enabled,true);
|
||||
SP("Score/Lose",caption,"Click an Arrow to begin.");
|
||||
SP("Score",value,score);
|
||||
SP("Highscore",value,highscore);
|
||||
SP(seq([j, enabled, false], j in ["Name","Enter"]));
|
||||
SP(seq([j, visible, false], j in ["Name","Enter"]));
|
||||
SP(seq([j, enabled, true], j in ["Score","Highscore", seq(cat("Button",k),k=0..4)]));
|
||||
SP(seq([j, visible, true], j in ["Score","Highscore", seq(cat("Button",k),k=0..4)]));
|
||||
end proc;
|
||||
|
||||
checklose:=proc();
|
||||
for q from 2 to 4 do
|
||||
for w from 4 to 1 by -1 do
|
||||
if a[q,w]=a[q-1,w] then
|
||||
loss:="False";
|
||||
return loss;
|
||||
end if;
|
||||
end do;
|
||||
end do;
|
||||
return loss;
|
||||
end proc;
|
||||
|
||||
f:=proc(keypress);
|
||||
SP("Score/Lose",visible,false);
|
||||
SP("Score/Lose",enabled,false);
|
||||
j := rand(1 .. 4);
|
||||
k := rand(1 .. 4);
|
||||
z := rand(1 .. 10);
|
||||
e := 0;
|
||||
move:=proc();
|
||||
for q from 4 to 2 by -1 do
|
||||
for w from 4 to 1 by -1 do
|
||||
if a[q,w]=a[q-1,w] then
|
||||
a[q-1,w]:=a[q-1,w]+a[q,w];
|
||||
score:=score+a[q-1,w];
|
||||
a[q,w]:=0;
|
||||
if q-1>1 and a[q-2,w]=0 then
|
||||
a[q-2,w]:=a[q-1,w];
|
||||
a[q-1,w]:=0;
|
||||
if q-2>1 and a[q-3,w]=0 then
|
||||
a[q-3,w]:=a[q-2,w];
|
||||
a[q-2,w]:=0;
|
||||
end if;
|
||||
end if;
|
||||
elif q-1>1 and a[q,w]=a[q-2,w] and a[q-1,w]=0 then
|
||||
a[q-2,w]:=a[q-2,w]+a[q,w];
|
||||
score:=score+a[q-2,w];
|
||||
a[q,w]:=0;
|
||||
if q-2>1 and a[q-3,w]=0 then
|
||||
a[q-3,w]:=a[q-2,w];
|
||||
a[q-2,w]:=0;
|
||||
end if;
|
||||
elif q-2>1 and a[q,w]=a[q-3,w] and a[q-1,w]=0 and a[q-2,w]=0 then
|
||||
a[q-3,w]:=a[q-3,w]+a[q,w];
|
||||
score:=score+a[q-3,w];
|
||||
a[q,w]:=0;
|
||||
elif a[q-1,w]=0 then
|
||||
a[q-1,w]:=a[q-1,w]+a[q,w];
|
||||
a[q,w]:=0;
|
||||
if q-1>1 and a[q-2,w]=0 then
|
||||
a[q-2,w]:=a[q-1,w];
|
||||
a[q-1,w]:=0;
|
||||
if q-2>1 and a[q-3,w]=0 then
|
||||
a[q-3,w]:=a[q-2,w];
|
||||
a[q-2,w]:=0;
|
||||
end if;
|
||||
end if;
|
||||
elif q-1>1 and a[q-2,w]=0 and a[q-1,w]=0 then
|
||||
a[q-2,w]:=a[q-2,w]+a[q,w];
|
||||
a[q,w]:=0;
|
||||
if q-2>1 and a[q-3,w]=0 then
|
||||
a[q-3,w]:=a[q-2,w];
|
||||
a[q-2,w]:=0;
|
||||
end if;
|
||||
elif q-2>1 and a[q-3,w]=0 and a[q-1,w]=0 and a[q-2,w]=0 then
|
||||
a[q-3,w]:=a[q-3,w]+a[q,w];
|
||||
a[q,w]:=0;
|
||||
end if;
|
||||
end do;
|
||||
end do;
|
||||
end proc;
|
||||
|
||||
r := j();
|
||||
c := k();
|
||||
if keypress="Up" then
|
||||
move();
|
||||
|
||||
elif keypress="Left" then
|
||||
a:=LinearAlgebra:-Transpose(a);
|
||||
move();
|
||||
a:=LinearAlgebra:-Transpose(a);
|
||||
|
||||
elif keypress="Right" then
|
||||
a := ArrayTools:-FlipDimension(LinearAlgebra:-Transpose(a),1);
|
||||
move();
|
||||
a := LinearAlgebra:-Transpose(ArrayTools:-FlipDimension(a,1));
|
||||
|
||||
elif keypress="Down" then
|
||||
a := ArrayTools:-FlipDimension(a, 1);
|
||||
move();
|
||||
a := ArrayTools:-FlipDimension(a, 1);
|
||||
end if;
|
||||
|
||||
if a[r, c] = 0 then
|
||||
if z() > 3 then
|
||||
a[r, c] := 2;
|
||||
else;
|
||||
a[r, c] := 4;
|
||||
end if;
|
||||
else
|
||||
for q to 4 do
|
||||
for w to 4 do
|
||||
if a[q, w] <> 0 then;
|
||||
e:=e+1;
|
||||
end if;
|
||||
end do;
|
||||
end do;
|
||||
if e = 16 then
|
||||
loss:="True";
|
||||
checklose();
|
||||
a:=LinearAlgebra:-Transpose(a);
|
||||
checklose();
|
||||
a:=LinearAlgebra:-Transpose(a);
|
||||
a := ArrayTools:-FlipDimension(LinearAlgebra:-Transpose(a),1);
|
||||
checklose();
|
||||
a := LinearAlgebra:-Transpose(ArrayTools:-FlipDimension(a,1));
|
||||
a := ArrayTools:-FlipDimension(a, 1);
|
||||
checklose();
|
||||
a := ArrayTools:-FlipDimension(a, 1);
|
||||
if loss="True" then
|
||||
SP("Score/Lose",visible,"True");
|
||||
SP("Score/Lose",enabled,"True");
|
||||
SP("Score/Lose",caption,"You Lose!");
|
||||
if score>hscore then
|
||||
SP("Score/Lose",caption,"Highscore! Enter your name below!");
|
||||
SP("Enter",caption,"Confirm");
|
||||
SP(seq([j, enabled, true], j in ["Name","Enter","Score/Lose"]));
|
||||
SP(seq([j, visible, true], j in ["Name","Enter","Score/Lose"]));
|
||||
SP(seq([j, enabled, false], j in [seq(cat("Button",k),k=0..4)]));
|
||||
SP(seq([j, visible, false], j in [seq(cat("Button",k),k=0..4)]));
|
||||
if buttonpress="True" then
|
||||
M:=Matrix(1, 2, [[score, hname]]):
|
||||
ExportMatrix("this:///Score.csv",M);
|
||||
buttonpress:="False";
|
||||
reset();
|
||||
end if;
|
||||
else
|
||||
SP("Score/Lose",caption,"Sorry, please try again.");
|
||||
SP("Enter",caption,"Restart");
|
||||
SP("Enter",visible,"True");
|
||||
SP("Enter",enabled,"True");
|
||||
SP(seq([j, enabled, false], j in [seq(cat("Button",k),k=0..4)]));
|
||||
SP(seq([j, visible, false], j in [seq(cat("Button",k),k=0..4)]));
|
||||
if buttonpress="True" then
|
||||
buttonpress:="False";
|
||||
reset();
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
e:=0;
|
||||
while a[r, c] <> 0 do
|
||||
r := j();
|
||||
c := k();
|
||||
end do;
|
||||
if z() > 1 then
|
||||
a[r, c] := 2;
|
||||
else
|
||||
a[r, c] := 4;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
matrixtotextarea(a);
|
||||
SP("Score",value,score,refresh);
|
||||
return a;
|
||||
end proc;
|
||||
end module;
|
||||
G:-reset();SP("Score/Lose",caption,"Click an Arrow to begin.");
|
||||
34
Task/2048/Mathematica/2048.math
Normal file
34
Task/2048/Mathematica/2048.math
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
SetOptions[InputNotebook[],NotebookEventActions->{
|
||||
"LeftArrowKeyDown":>(stat=Coalesce[stat];AddNew[]),
|
||||
"RightArrowKeyDown":>(stat=Reverse/@Coalesce[Reverse/@stat];AddNew[]),
|
||||
"UpArrowKeyDown":>(stat=Coalesce[stat\[Transpose]]\[Transpose];AddNew[]),
|
||||
"DownArrowKeyDown":>(stat=(Reverse/@(Coalesce[Reverse/@(stat\[Transpose])]))\[Transpose];AddNew[])
|
||||
}
|
||||
];
|
||||
|
||||
n=4;
|
||||
bgcolor=GrayLevel[0.84];
|
||||
colorfunc=Blend[{{0,Gray},{1/2,Red},{1,Blend[{Yellow,Orange}]}},#]&;
|
||||
|
||||
ClearAll[AddNew,PrintStat,Coalesce,SubCoalesce,AddRandomNumber]
|
||||
AddNew[]:=(stat=AddRandomNumber[stat])
|
||||
PrintStat[stat_]:=Module[{gr1,gr2,gr3,dr=0.2,cols,nstat=stat,positions},
|
||||
gr1={bgcolor,Rectangle[-dr{1,1},n+dr{1,1},RoundingRadius->dr]};
|
||||
cols=Map[If[#==0,0,Log2[#]]&,nstat,{2}];
|
||||
cols=Map[If[#==0,Lighter@bgcolor,colorfunc[#/Max[cols]]]&,cols,{2}];
|
||||
positions=Table[{i,n-j+1},{j,n},{i,n}];
|
||||
gr2=MapThread[{#2,Rectangle[#3-{1,1}(1-dr/3),#3-{1,1}dr/3,RoundingRadius->dr/2]}&,{stat,cols,positions},2];
|
||||
gr3=MapThread[If[#1>0,Style[Text[#1,#2-0.5{1,1}],20,White],{}]&,{stat,positions},2];
|
||||
Graphics[{gr1,gr2,gr3},PlotRange->{{-0.5,n+0.5},{-0.5,n+0.5}},ImageSize->500]
|
||||
]
|
||||
Coalesce[stat_]:=SubCoalesce/@stat
|
||||
SubCoalesce[statlist_]:=Module[{st=statlist,n=Length[statlist],pairs},
|
||||
st=Split[DeleteCases[st,0]];
|
||||
st=Partition[#,2,2,1,{}]&/@st;
|
||||
st=Map[If[Length[#]==2,Total[#],#]&,st,{2}];
|
||||
Join[Flatten[st],ConstantArray[0,n-Length[Flatten[st]]]]
|
||||
]
|
||||
AddRandomNumber[stat_,n_:2]:=With[{pos=Position[stat,0,{2}]},If[Length[pos]>0,ReplacePart[stat,RandomChoice[pos]->n],stat]]
|
||||
|
||||
stat=Nest[AddRandomNumber[#,RandomChoice[{2,4}]]&,ConstantArray[0,{n,n}],4];
|
||||
Dynamic[PrintStat@stat]
|
||||
185
Task/2048/Nim/2048.nim
Normal file
185
Task/2048/Nim/2048.nim
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
import random, strutils, terminal
|
||||
|
||||
const
|
||||
BoardLength = 4
|
||||
BoardSize = BoardLength * BoardLength
|
||||
Target = 2048
|
||||
|
||||
type
|
||||
Operation = enum
|
||||
opInvalid
|
||||
opUp
|
||||
opDown
|
||||
opLeft
|
||||
opRight
|
||||
opQuit
|
||||
opRestart
|
||||
|
||||
Board = object
|
||||
len: Natural
|
||||
largestNumber: Natural
|
||||
score: Natural
|
||||
rows: array[BoardLength, array[BoardLength, Natural]]
|
||||
|
||||
func handleKey(c: char): Operation =
|
||||
case c
|
||||
of 'w', 'W': opUp
|
||||
of 'a', 'A': opLeft
|
||||
of 's', 'S': opDown
|
||||
of 'd', 'D': opRight
|
||||
of 'q', 'Q': opQuit
|
||||
of 'r', 'R': opRestart
|
||||
else: opInvalid
|
||||
|
||||
proc getKey(): Operation =
|
||||
var c = getch()
|
||||
if c == '\e':
|
||||
c = getch()
|
||||
if c == '[':
|
||||
case getch()
|
||||
of 'A': opUp
|
||||
of 'D': opLeft
|
||||
of 'B': opDown
|
||||
of 'C': opRight
|
||||
else: opInvalid
|
||||
else: handleKey c
|
||||
else: handleKey c
|
||||
|
||||
proc spawnRandom(b: var Board) =
|
||||
if b.len < BoardSize:
|
||||
var
|
||||
x = rand 0..<BoardLength
|
||||
y = rand 0..<BoardLength
|
||||
while b.rows[y][x] != 0:
|
||||
x = rand 0..<BoardLength
|
||||
y = rand 0..<BoardLength
|
||||
b.rows[y][x] = if rand(1.0) < 0.9: 2 else: 4
|
||||
inc b.len
|
||||
b.largestNumber = max(b.rows[y][x], b.largestNumber)
|
||||
|
||||
proc initBoard(): Board =
|
||||
spawnRandom result
|
||||
|
||||
func `$`(b: Board): string =
|
||||
result = "┌────┬────┬────┬────┐\n"
|
||||
for idx, val in b.rows:
|
||||
for v in val:
|
||||
result.add "│"
|
||||
result.add center(if v != 0: $v else: "", 4)
|
||||
result.add "│\n"
|
||||
if idx < high(b.rows):
|
||||
result.add "├────┼────┼────┼────┤\n"
|
||||
else:
|
||||
result.add "└────┴────┴────┴────┘"
|
||||
|
||||
func shift(b: var Board; o: Operation; merge = true): bool =
|
||||
const BoardRange = 0..<BoardLength
|
||||
var
|
||||
x = 0
|
||||
y = 0
|
||||
vecX: range[-1..1] = 0
|
||||
vecY: range[-1..1] = 0
|
||||
case o
|
||||
of opUp:
|
||||
vecY = 1
|
||||
of opDown:
|
||||
vecY = -1
|
||||
y = BoardLength - 1
|
||||
of opLeft: vecX = 1
|
||||
of opRight:
|
||||
vecX = -1
|
||||
x = BoardLength - 1
|
||||
else: return
|
||||
|
||||
let
|
||||
startX = x
|
||||
startY = y
|
||||
while x in BoardRange and y in BoardRange:
|
||||
while b.len < BoardSize and x in BoardRange and y in BoardRange:
|
||||
let
|
||||
nextX = x + vecX
|
||||
nextY = y + vecY
|
||||
prevX = x - vecX
|
||||
prevY = y - vecY
|
||||
if b.rows[y][x] == 0:
|
||||
if nextX in BoardRange and nextY in BoardRange and
|
||||
b.rows[nextY][nextX] != 0:
|
||||
result = true
|
||||
swap b.rows[y][x], b.rows[nextY][nextX]
|
||||
if prevX in BoardRange and prevY in BoardRange:
|
||||
x = prevX
|
||||
y = prevY
|
||||
continue
|
||||
x = nextX
|
||||
y = nextY
|
||||
|
||||
if merge:
|
||||
x = if vecX != 0: startX else: x
|
||||
y = if vecY != 0: startY else: y
|
||||
while x in BoardRange and y in BoardRange:
|
||||
let
|
||||
nextX = x + vecX
|
||||
nextY = y + vecY
|
||||
if b.rows[y][x] != 0:
|
||||
if nextX in BoardRange and nextY in BoardRange and
|
||||
b.rows[nextY][nextX] == b.rows[y][x]:
|
||||
result = true
|
||||
b.rows[y][x] *= 2
|
||||
b.largestNumber = max(b.rows[y][x], b.largestNumber)
|
||||
b.score += b.rows[y][x]
|
||||
b.rows[nextY][nextX] = 0
|
||||
dec b.len
|
||||
x = nextX
|
||||
y = nextY
|
||||
|
||||
if vecX == 0:
|
||||
inc x
|
||||
y = startY
|
||||
elif vecY == 0:
|
||||
inc y
|
||||
x = startX
|
||||
if merge and result: discard b.shift(o, false)
|
||||
|
||||
func shiftable(b: Board): bool =
|
||||
for row in 0..<BoardLength:
|
||||
for col in 0..<BoardLength:
|
||||
result = result or b.rows[row][col] == 0
|
||||
if result: break
|
||||
if row < BoardLength - 1:
|
||||
result = result or b.rows[row][col] == b.rows[row + 1][col]
|
||||
if col < BoardLength - 1:
|
||||
result = result or b.rows[row][col] == b.rows[row][col + 1]
|
||||
|
||||
when isMainModule:
|
||||
randomize()
|
||||
var
|
||||
board = initBoard()
|
||||
highscore = 0
|
||||
block gameLoop:
|
||||
while true:
|
||||
let gameover = not board.shiftable or board.largestNumber >= Target
|
||||
echo board
|
||||
highscore = max(highscore, board.score)
|
||||
echo "Score = ", board.score, " Highscore = ", highscore
|
||||
if not gameover:
|
||||
echo "Press arrow keys or WASD to move, R to Restart, Q to Quit"
|
||||
elif board.largestNumber >= Target:
|
||||
echo "You win! Press R to Restart, Q to Quit"
|
||||
else:
|
||||
echo "Game over! Press R to Restart, Q to Quit"
|
||||
while true:
|
||||
let op = getKey()
|
||||
case op
|
||||
of opRestart:
|
||||
board = initBoard()
|
||||
break
|
||||
of opQuit: break gameLoop
|
||||
of opInvalid: continue
|
||||
elif gameover: continue
|
||||
else:
|
||||
if board.shift op:
|
||||
board.spawnRandom
|
||||
break
|
||||
for i in 1..BoardLength + 7:
|
||||
eraseLine()
|
||||
cursorUp()
|
||||
149
Task/2048/OCaml/2048.ocaml
Normal file
149
Task/2048/OCaml/2048.ocaml
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
let list_make x v =
|
||||
let rec aux acc i =
|
||||
if i <= 0 then acc else aux (v::acc) (i-1)
|
||||
in
|
||||
aux [] x
|
||||
|
||||
|
||||
let pad_right n line =
|
||||
let len = List.length line in
|
||||
let x = n - len in
|
||||
line @ (list_make x 0)
|
||||
|
||||
|
||||
let _move_left line =
|
||||
let n = List.length line in
|
||||
let line = List.filter ((<>) 0) line in
|
||||
let rec aux acc = function
|
||||
| x::y::tl ->
|
||||
if x = y
|
||||
then aux (x+y::acc) tl
|
||||
else aux (x::acc) (y::tl)
|
||||
| x::[] ->
|
||||
aux (x::acc) []
|
||||
| [] ->
|
||||
List.rev acc
|
||||
in
|
||||
pad_right n (aux [] line)
|
||||
|
||||
|
||||
let move_left grid =
|
||||
List.map _move_left grid
|
||||
|
||||
|
||||
let move_right grid =
|
||||
grid
|
||||
|> List.map List.rev
|
||||
|> List.map _move_left
|
||||
|> List.map List.rev
|
||||
|
||||
|
||||
let rec replace g n v =
|
||||
match g with
|
||||
| x::xs -> if n = 0 then v::xs else x::(replace xs (n-1) v)
|
||||
| [] -> raise (Invalid_argument "replace")
|
||||
|
||||
|
||||
(* add a new value in a random cell containing zero *)
|
||||
let rec new_value grid =
|
||||
let zeros = ref [] in
|
||||
List.iteri (fun y line ->
|
||||
List.iteri (fun x v ->
|
||||
if v = 0 then zeros := (x, y) :: !zeros
|
||||
) line;
|
||||
) grid;
|
||||
let n = List.length !zeros in
|
||||
if n = 0 then raise Exit;
|
||||
let x, y = List.nth !zeros (Random.int n) in
|
||||
let v = if Random.int 10 = 0 then 4 else 2 in
|
||||
let line = List.nth grid y in
|
||||
let new_line = replace line x v in
|
||||
replace grid y new_line
|
||||
|
||||
|
||||
(* turn counterclockwise *)
|
||||
let turn_ccw grid =
|
||||
let y = List.length grid in
|
||||
let x = List.length (List.nth grid 0) in
|
||||
List.init x (fun i ->
|
||||
List.init y (fun j ->
|
||||
List.nth (List.nth grid j) (x-i-1)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(* turn clockwise *)
|
||||
let turn_cw grid =
|
||||
let y = List.length grid in
|
||||
let x = List.length (List.nth grid 0) in
|
||||
List.init x (fun i ->
|
||||
List.init y (fun j ->
|
||||
List.nth (List.nth grid (y-j-1)) (i)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
let move_up grid =
|
||||
grid
|
||||
|> turn_ccw
|
||||
|> move_left
|
||||
|> turn_cw
|
||||
|
||||
|
||||
let move_down grid =
|
||||
grid
|
||||
|> turn_cw
|
||||
|> move_left
|
||||
|> turn_ccw
|
||||
|
||||
|
||||
let display grid =
|
||||
List.iter (fun line ->
|
||||
print_string " [";
|
||||
line
|
||||
|> List.map (Printf.sprintf "%4d")
|
||||
|> String.concat "; "
|
||||
|> print_string;
|
||||
print_endline "]"
|
||||
) grid
|
||||
|
||||
|
||||
let () =
|
||||
Random.self_init ();
|
||||
let width =
|
||||
try int_of_string Sys.argv.(1)
|
||||
with _ -> 4
|
||||
in
|
||||
let line = list_make width 0 in
|
||||
let grid = list_make width line in
|
||||
|
||||
let grid = new_value grid in
|
||||
let grid = new_value grid in
|
||||
|
||||
print_endline {|
|
||||
s -> left
|
||||
f -> right
|
||||
e -> up
|
||||
d -> down
|
||||
q -> quit
|
||||
|};
|
||||
let rec loop grid =
|
||||
display grid;
|
||||
let grid =
|
||||
match read_line () with
|
||||
| "s" -> move_left grid
|
||||
| "f" -> move_right grid
|
||||
| "e" -> move_up grid
|
||||
| "d" -> move_down grid
|
||||
| "q" -> exit 0
|
||||
| _ -> grid
|
||||
in
|
||||
let grid =
|
||||
try new_value grid
|
||||
with Exit ->
|
||||
print_endline "Game Over";
|
||||
exit 0
|
||||
in
|
||||
loop grid
|
||||
in
|
||||
loop grid
|
||||
227
Task/2048/PHP/2048.php
Normal file
227
Task/2048/PHP/2048.php
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
$game = new Game();
|
||||
|
||||
while(true) {
|
||||
$game->cycle();
|
||||
}
|
||||
|
||||
class Game {
|
||||
private $field;
|
||||
private $fieldSize;
|
||||
private $command;
|
||||
private $error;
|
||||
private $lastIndexX, $lastIndexY;
|
||||
private $score;
|
||||
private $finishScore;
|
||||
|
||||
function __construct() {
|
||||
$this->field = array();
|
||||
$this->fieldSize = 4;
|
||||
$this->finishScore = 2048;
|
||||
$this->score = 0;
|
||||
$this->addNumber();
|
||||
$this->render();
|
||||
}
|
||||
|
||||
public function cycle() {
|
||||
$this->command = strtolower($this->readchar('Use WASD, q exits'));
|
||||
$this->cls();
|
||||
|
||||
if($this->processCommand()) {
|
||||
$this->addNumber();
|
||||
} else {
|
||||
if(count($this->getFreeList()) == 0 ) {
|
||||
$this->error = 'No options left!, You Lose!!';
|
||||
} else {
|
||||
$this->error = 'Invalid move, try again!';
|
||||
}
|
||||
}
|
||||
$this->render();
|
||||
}
|
||||
|
||||
private function readchar($prompt) {
|
||||
readline_callback_handler_install($prompt, function() {});
|
||||
$char = stream_get_contents(STDIN, 1);
|
||||
readline_callback_handler_remove();
|
||||
return $char;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a number in an empty spot on the field
|
||||
*/
|
||||
private function addNumber() {
|
||||
$freeList = $this->getFreeList();
|
||||
if(count($freeList) == 0) {
|
||||
return;
|
||||
}
|
||||
$index = mt_rand(0, count($freeList)-1);
|
||||
$nr = (mt_rand(0,9) == 0)? 4 : 2;
|
||||
$this->field[$freeList[$index]['x']][$freeList[$index]['y']] = $nr;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array(array('x' => <x>, 'y' => <y>)) with empty positions in the field
|
||||
*/
|
||||
private function getFreeList() {
|
||||
$freeList = array();
|
||||
for($y =0; $y< $this->fieldSize;$y++) {
|
||||
for($x=0; $x < $this->fieldSize; $x++) {
|
||||
if(!isset($this->field[$x][$y])) {
|
||||
$freeList[] = array('x' => $x, 'y' => $y);
|
||||
} elseif($this->field[$x][$y] == $this->finishScore) {
|
||||
$this->error = 'You Win!!';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $freeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a command:
|
||||
* @return is the command valid (Did it cause a change in the field)
|
||||
*/
|
||||
private function processCommand() {
|
||||
if(!in_array($this->command, array('w','a','s','d','q'))) {
|
||||
$this->error = 'Invalid Command';
|
||||
return false;
|
||||
}
|
||||
if($this->command == 'q') {
|
||||
echo PHP_EOL. 'Bye!'. PHP_EOL;
|
||||
exit;
|
||||
}
|
||||
|
||||
// Determine over which axis and in which direction we move:
|
||||
$axis = 'x';
|
||||
$sDir = 1;
|
||||
|
||||
switch($this->command) {
|
||||
case 'w':
|
||||
$axis = 'y';
|
||||
$sDir = -1;
|
||||
break;
|
||||
case 'a':
|
||||
$sDir = -1;
|
||||
break;
|
||||
case 's':
|
||||
$axis = 'y';
|
||||
break;
|
||||
case 'd':
|
||||
break;
|
||||
}
|
||||
|
||||
$done = 0;
|
||||
// shift all numbers in that direction
|
||||
$done += $this->shift($axis, $sDir);
|
||||
// merge equal numbers in opposite direction
|
||||
$done += $this->merge($axis, $sDir * -1);
|
||||
// shift merged numbers in that direction
|
||||
$done += $this->shift($axis, $sDir);
|
||||
return $done >0;
|
||||
}
|
||||
|
||||
private function shift($axis, $dir) {
|
||||
$totalDone = 0;
|
||||
for($i = 0; $i <$this->fieldSize; $i++) {
|
||||
$done = 0;
|
||||
foreach($this->iterate($axis,$dir) as $xy) {
|
||||
if($xy['vDest'] === NULL && $xy['vSrc'] !== NULL) {
|
||||
$this->field[$xy['dX']][$xy['dY']] = $xy['vSrc'];
|
||||
$this->field[$xy['sX']][$xy['sY']] = NULL;
|
||||
$done++;
|
||||
}
|
||||
}
|
||||
$totalDone += $done;
|
||||
if($done == 0) {
|
||||
// nothing to shift anymore
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $totalDone;
|
||||
}
|
||||
|
||||
private function merge($axis, $dir) {
|
||||
$done = 0;
|
||||
foreach($this->iterate($axis,$dir) as $xy) {
|
||||
if($xy['vDest'] !== NULL && $xy['vDest'] === $xy['vSrc']) {
|
||||
$this->field[$xy['sX']][$xy['sY']] += $xy['vDest'];
|
||||
$this->field[$xy['dX']][$xy['dY']] = NULL;
|
||||
$this->score += $this->field[$xy['sX']][$xy['sY']];
|
||||
$done ++;
|
||||
}
|
||||
}
|
||||
return $done;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array List of src, dest pairs and their values to iterate over.
|
||||
*/
|
||||
private function iterate($axis, $dir) {
|
||||
$res = array();
|
||||
for($y = 0; $y < $this->fieldSize; $y++) {
|
||||
for($x=0; $x < $this->fieldSize; $x++) {
|
||||
$item = array('sX'=> $x,'sY' => $y, 'dX' => $x, 'dY' => $y, 'vDest' => NULL,'vSrc' => NULL);
|
||||
|
||||
if($axis == 'x') {
|
||||
$item['dX'] += $dir;
|
||||
} else {
|
||||
$item['dY'] += $dir;
|
||||
}
|
||||
|
||||
if($item['dX'] >= $this->fieldSize || $item['dY'] >=$this->fieldSize || $item['dX'] < 0 || $item['dY'] < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['vDest'] = (isset($this->field[$item['dX']][$item['dY']]))? $this->field[$item['dX']][$item['dY']] : NULL;
|
||||
$item['vSrc'] = (isset($this->field[$item['sX']][$item['sY']]))? $this->field[$item['sX']][$item['sY']] : NULL;
|
||||
$res[] = $item;
|
||||
}
|
||||
}
|
||||
if($dir < 0) {
|
||||
$res = array_reverse($res);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/// RENDER ///
|
||||
|
||||
/**
|
||||
* Clear terminal screen
|
||||
*/
|
||||
private function cls() {
|
||||
echo chr(27).chr(91).'H'.chr(27).chr(91).'J';
|
||||
}
|
||||
|
||||
private function render() {
|
||||
echo $this->finishScore . '! Current score: '. $this->score .PHP_EOL;
|
||||
|
||||
if(!empty($this->error)) {
|
||||
echo $this->error . PHP_EOL;
|
||||
$this->error = NULL;
|
||||
}
|
||||
$this->renderField();
|
||||
}
|
||||
|
||||
private function renderField() {
|
||||
$width = 5;
|
||||
$this->renderVSeperator($width);
|
||||
for($y =0; $y < $this->fieldSize; $y ++) {
|
||||
for($x = 0;$x < $this->fieldSize; $x++) {
|
||||
echo '|';
|
||||
if(!isset($this->field[$x][$y])) {
|
||||
echo str_repeat(' ', $width);
|
||||
continue;
|
||||
}
|
||||
printf('%'.$width.'s', $this->field[$x][$y]);
|
||||
}
|
||||
echo '|'. PHP_EOL;
|
||||
$this->renderVSeperator($width);
|
||||
}
|
||||
}
|
||||
|
||||
private function renderVSeperator($width) {
|
||||
echo str_repeat('+'. str_repeat('-', $width), $this->fieldSize) .'+' .PHP_EOL;
|
||||
}
|
||||
|
||||
}
|
||||
362
Task/2048/Pascal/2048.pas
Normal file
362
Task/2048/Pascal/2048.pas
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
program game2048;
|
||||
uses Crt;
|
||||
const
|
||||
SIZE_MAP = 4;
|
||||
SIZETOPBOT = SIZE_MAP*6+6; (* Calculate the length of the top and bottom to create a box around the game *)
|
||||
NOTHING = 0;
|
||||
UP = 93;
|
||||
RIGHT = 92;
|
||||
LEFT = 91;
|
||||
DOWN = 90;
|
||||
type
|
||||
type_vector = array [1..SIZE_MAP] of integer;
|
||||
type_game = record
|
||||
lin,col:integer;
|
||||
map: array [1..SIZE_MAP,1..SIZE_MAP] of integer;
|
||||
score:integer;
|
||||
end;
|
||||
type_coord = record
|
||||
lin,col:integer;
|
||||
end;
|
||||
|
||||
var
|
||||
game:type_game;
|
||||
end_game,movement:boolean;
|
||||
|
||||
procedure Create_Number(var game:type_game);
|
||||
(* Create the number(2 or 4) in a random position on the map *)
|
||||
(* The number 4 had a 10% of chance to be created *)
|
||||
var
|
||||
number:integer;
|
||||
RanP:type_coord;
|
||||
begin
|
||||
randomize;
|
||||
if random(9) = 1 then
|
||||
number:=4
|
||||
else
|
||||
number:=2;
|
||||
RanP.lin:=random(game.lin)+1;
|
||||
RanP.col:=random(game.col)+1;
|
||||
while game.map[RanP.lin,RanP.col] <> NOTHING do
|
||||
begin
|
||||
RanP.lin:=random(game.lin)+1;
|
||||
RanP.col:=random(game.col)+1;
|
||||
end;
|
||||
game.map[RanP.lin,Ranp.Col]:=number;
|
||||
end;
|
||||
|
||||
procedure initializing_game(var game:type_game);
|
||||
var i,j:integer;
|
||||
begin
|
||||
game.lin:=SIZE_MAP;
|
||||
game.col:=SIZE_MAP;
|
||||
game.score:=0;
|
||||
for i:=1 to game.lin do
|
||||
for j:=1 to game.col do
|
||||
game.map[i,j]:=NOTHING;
|
||||
|
||||
Create_Number(game);
|
||||
Create_Number(game);
|
||||
end;
|
||||
|
||||
function CountDigit(number:integer):integer;
|
||||
begin
|
||||
if number <> 0 then
|
||||
begin
|
||||
CountDigit:=0;
|
||||
while number <> 0 do
|
||||
begin
|
||||
CountDigit:=CountDigit+1;
|
||||
number:=number div 10;
|
||||
end;
|
||||
end
|
||||
else
|
||||
CountDigit:=1;
|
||||
end;
|
||||
|
||||
procedure print_number(number:integer);
|
||||
(* Print the number aligned with other numbers in the matrix *)
|
||||
var k,hwdigit:integer;
|
||||
begin
|
||||
hwdigit:=CountDigit(number);
|
||||
write(' ');
|
||||
write(number);
|
||||
(* The 4 is used to aling the numbers because the greatest number *)
|
||||
(* possible is 2048, which have 4 digits *)
|
||||
for k:=1 to 4-hwdigit do
|
||||
write(' ');
|
||||
write(' ');
|
||||
end;
|
||||
|
||||
procedure print_line(lengthL:integer; ch:string);
|
||||
var i:integer;
|
||||
begin
|
||||
write('+');
|
||||
for i:=1 to (lengthL-2) do
|
||||
begin
|
||||
if i mod 7 = 0 then
|
||||
write('+')
|
||||
else
|
||||
write(ch);
|
||||
end;
|
||||
writeln;
|
||||
end;
|
||||
|
||||
procedure print_map(var game:type_game);
|
||||
var i,j:integer;
|
||||
begin
|
||||
print_line(SIZETOPBOT,'-');
|
||||
for i:=1 to game.lin do
|
||||
begin
|
||||
write('|');
|
||||
for j:=1 to game.col do
|
||||
if game.map[i,j] >= 0 then
|
||||
begin
|
||||
print_number(game.map[i,j]);
|
||||
write('|');
|
||||
end;
|
||||
writeln;
|
||||
print_line(SIZETOPBOT,'-');
|
||||
end;
|
||||
end;
|
||||
|
||||
function CanMove(var v_lin:type_vector; i:integer):integer;
|
||||
(* Returns 1 if the next position is free *)
|
||||
(* Returns 2 if the next position has an equal number *)
|
||||
(* Returns 0 if the next position is not free *)
|
||||
begin
|
||||
if v_lin[i-1] = NOTHING then
|
||||
CanMove:=1
|
||||
else if v_lin[i] = v_lin[i-1] then
|
||||
CanMove:=2
|
||||
else
|
||||
CanMove:=0;
|
||||
end;
|
||||
|
||||
function MoveAndSum(var game:type_game; var v_lin:type_vector; size:integer):boolean;
|
||||
(* Move and Sum the elements of the vector *)
|
||||
(* The direction of the move is to the left *)
|
||||
(* Returns TRUE if a number was moved *)
|
||||
(* Returns FALSE if a number was not moved *)
|
||||
var
|
||||
i,e,ResultM:integer;
|
||||
v:type_vector;
|
||||
begin
|
||||
MoveAndSum:=FALSE;
|
||||
(* Initializing the vector *)
|
||||
(* This Vector is to know what number sum and what not sum *)
|
||||
for i:=1 to size do
|
||||
v[i]:=0;
|
||||
|
||||
for i:=2 to size do
|
||||
begin
|
||||
if v_lin[i] <> 0 then
|
||||
begin
|
||||
(* Move the number in v_lin[i] to the left as much as possible *)
|
||||
e:=i;
|
||||
ResultM:=CanMove(v_lin,e);
|
||||
while (ResultM <> 0)and(e>1) do
|
||||
begin
|
||||
case ResultM of
|
||||
1:begin
|
||||
v_lin[e-1]:=v_lin[e];
|
||||
v_lin[e]:=NOTHING;
|
||||
end;
|
||||
2:begin
|
||||
if v[e] = 0 then
|
||||
begin
|
||||
v_lin[e-1]:=v_lin[e-1]*2;
|
||||
game.score:=game.score+v_lin[e-1];
|
||||
v_lin[e]:=NOTHING;
|
||||
(* This number will not be sum again *)
|
||||
v[e-1]:=1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
e:=e-1;
|
||||
ResultM:=CanMove(v_lin,e);
|
||||
end;
|
||||
if e <> i then
|
||||
MoveAndSum:=TRUE;
|
||||
v[e-1]:=1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function move_left(var game:type_game):boolean;
|
||||
var
|
||||
i,j:integer;
|
||||
v:type_vector;
|
||||
begin
|
||||
move_left:=FALSE;
|
||||
for i:=1 to game.lin do
|
||||
begin
|
||||
for j:=1 to game.col do
|
||||
v[j]:=game.map[i,j];
|
||||
|
||||
if MoveAndSum(game,v,game.lin) then
|
||||
move_left:=TRUE;
|
||||
|
||||
for j:=1 to game.col do
|
||||
game.map[i,j]:=v[j];
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function move_right(var game:type_game):boolean;
|
||||
var
|
||||
i,j,k:integer;
|
||||
v:type_vector;
|
||||
begin
|
||||
move_right:=FALSE;
|
||||
for i:=1 to game.lin do
|
||||
begin
|
||||
(* The side which will be move had to be at the beginning of the vector *)
|
||||
(* For example, I want to move this line to the right: 0 2 0 3 6 *)
|
||||
(* The procedure "MoveAndSum" has to receive this vector: 6 3 0 2 0 *)
|
||||
k:=1;
|
||||
for j:=game.col downto 1 do
|
||||
begin
|
||||
v[k]:=game.map[i,j];
|
||||
k:=k+1;
|
||||
end;
|
||||
if MoveAndSum(game,v,game.lin) then
|
||||
move_right:=TRUE;
|
||||
(* Copy to the right place in the matrix *)
|
||||
k:=1;
|
||||
for j:=game.col downto 1 do
|
||||
begin
|
||||
game.map[i,k]:=v[j];
|
||||
k:=k+1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function move_down(var game:type_game):boolean;
|
||||
var
|
||||
i,j,k:integer;
|
||||
v:type_vector;
|
||||
begin
|
||||
move_down:=FALSE;
|
||||
for j:=1 to game.col do
|
||||
begin
|
||||
k:=1;
|
||||
for i:=game.lin downto 1 do
|
||||
begin
|
||||
v[k]:=game.map[i,j];
|
||||
k:=k+1;
|
||||
end;
|
||||
if MoveAndSum(game,v,game.lin) then
|
||||
move_down:=TRUE;
|
||||
k:=1;
|
||||
for i:=game.lin downto 1 do
|
||||
begin
|
||||
game.map[k,j]:=v[i];
|
||||
k:=k+1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function move_up(var game:type_game):boolean;
|
||||
var
|
||||
i,j:integer;
|
||||
v:type_vector;
|
||||
begin
|
||||
move_up:=FALSE;
|
||||
for j:=1 to game.col do
|
||||
begin
|
||||
for i:=1 to game.lin do
|
||||
v[i]:=game.map[i,j];
|
||||
if MoveAndSum(game,v,game.lin) then
|
||||
move_up:=TRUE;
|
||||
for i:=1 to game.lin do
|
||||
game.map[i,j]:=v[i];
|
||||
end;
|
||||
end;
|
||||
|
||||
function CheckWinLose(var game:type_game):integer;
|
||||
(* Returns 2 if the player win the game *)
|
||||
(* Returns 1 if the player lose the game *)
|
||||
(* Returns 0 if has a valid move*)
|
||||
var i,j:integer;
|
||||
begin
|
||||
with game do
|
||||
begin
|
||||
CheckWinLose:=1;
|
||||
i:=1;
|
||||
while (i<=game.lin)and(CheckWinLose<>2) do
|
||||
begin
|
||||
j:=1;
|
||||
while (j<=game.col)and(CheckWinLose<>2) do
|
||||
begin
|
||||
if map[i,j] = 2048 then
|
||||
CheckWinLose:=2
|
||||
else
|
||||
if map[i,j] = NOTHING then
|
||||
CheckWinLose:=0
|
||||
else
|
||||
if (map[i,j] = map[i,j+1])and(j<>col) then
|
||||
CheckWinLose:=0
|
||||
else
|
||||
if (map[i,j] = map[i,j-1])and(j<>1) then
|
||||
CheckWinLose:=0
|
||||
else
|
||||
if (map[i,j] = map[i+1,j])and(i<>lin) then
|
||||
CheckWinLose:=0
|
||||
else
|
||||
if (map[i,j] = map[i-1,j])and(i<>1) then
|
||||
CheckWinLose:=0;
|
||||
j:=j+1;
|
||||
end;
|
||||
i:=i+1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
movement:=false;
|
||||
end_game:=false;
|
||||
initializing_game(game);
|
||||
repeat
|
||||
ClrScr;
|
||||
if movement then
|
||||
Create_Number(game);
|
||||
movement:=false;
|
||||
|
||||
writeln('SCORE: ',game.score);
|
||||
print_map(game);
|
||||
writeln(' Use the arrow keys to move ');
|
||||
writeln(' Press ESC to quit the game ');
|
||||
|
||||
case CheckWinLose(game) of
|
||||
1:begin
|
||||
print_line(SIZETOPBOT,'-');
|
||||
writeln('| Game Over! |');
|
||||
print_line(SIZETOPBOT,'-');
|
||||
end_game:=TRUE;
|
||||
end;
|
||||
2:begin
|
||||
print_line(SIZETOPBOT,'-');
|
||||
writeln('| You Win! |');
|
||||
print_line(SIZETOPBOT,'-');
|
||||
end_game:=TRUE;
|
||||
end;
|
||||
end;
|
||||
|
||||
repeat
|
||||
until KeyPressed;
|
||||
case ReadKey of
|
||||
#0:begin
|
||||
case ReadKey of
|
||||
#72:movement:=move_up(game);
|
||||
#77:movement:=move_right(game);
|
||||
#75:movement:=move_left(game);
|
||||
#80:movement:=move_down(game);
|
||||
end;
|
||||
end;
|
||||
#27:end_game:=true;
|
||||
end;
|
||||
until end_game;
|
||||
end.
|
||||
87
Task/2048/Perl/2048.pl
Normal file
87
Task/2048/Perl/2048.pl
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict; # https://rosettacode.org/wiki/2048
|
||||
use warnings;
|
||||
use Tk;
|
||||
|
||||
my $N = shift // 4;
|
||||
$N < 2 and $N = 2;
|
||||
my @squares = 1 .. $N*$N;
|
||||
my %n2ch = (' ' => ' ');
|
||||
@n2ch{ map 2**$_, 1..26} = 'a'..'z';
|
||||
my %ch2n = reverse %n2ch;
|
||||
my $winner = '';
|
||||
my @arow = 0 .. $N - 1;
|
||||
my @acol = map $_ * $N, @arow;
|
||||
|
||||
my $mw = MainWindow->new;
|
||||
$mw->geometry( '+300+0' );
|
||||
$mw->title( 2048 );
|
||||
$mw->focus;
|
||||
$mw->bind('<KeyPress-Left>' => sub { arrow($N, @arow) } );
|
||||
$mw->bind('<KeyPress-Right>' => sub { arrow($N, reverse @arow) } );
|
||||
$mw->bind('<KeyPress-Up>' => sub { arrow(1, @acol) } );
|
||||
$mw->bind('<KeyPress-Down>' => sub { arrow(1, reverse @acol) } );
|
||||
my $grid = $mw->Frame()->pack;
|
||||
for my $i ( 0 .. $#squares )
|
||||
{
|
||||
$grid->Label(-textvariable => \$squares[$i],
|
||||
-width => 5, -height => 2, -font => 'courierbold 30',
|
||||
-relief => 'ridge', -borderwidth => 5,
|
||||
)->grid(-row => int $i / $N, -column => $i % $N );
|
||||
}
|
||||
my $buttons = $mw->Frame()->pack(-fill => 'x', -expand => 1);
|
||||
$buttons->Button(-text => 'Exit', -command => sub {$mw->destroy},
|
||||
-font => 'courierbold 14',
|
||||
)->pack(-side => 'right');
|
||||
$buttons->Button(-text => 'New Game', -command => \&newgame,
|
||||
-font => 'courierbold 14',
|
||||
)->pack(-side => 'left');
|
||||
$buttons->Label(-textvariable => \$winner,
|
||||
-font => 'courierbold 18', -fg => 'red2',
|
||||
)->pack;
|
||||
|
||||
newgame();
|
||||
MainLoop;
|
||||
-M $0 < 0 and exec $0;
|
||||
|
||||
sub losecheck
|
||||
{
|
||||
local $_ = join '', @n2ch{ @squares };
|
||||
/ / || ($_ ^ substr $_, $N) =~ tr/\0// and return;
|
||||
/(.)\1/ and return for /.{$N}/g;
|
||||
$winner = 'You Lost';
|
||||
}
|
||||
|
||||
sub arrow
|
||||
{
|
||||
$winner and return; # you won, no more play
|
||||
my ($inc, @ix) = @_;
|
||||
my $oldboard = "@squares";
|
||||
for ( 1 .. $N )
|
||||
{
|
||||
local $_ = join '', @n2ch{ @squares[@ix] }; # extract 4 squares
|
||||
tr/ //d; # force left
|
||||
s/(\w)\1/ chr 1 + ord $1 /ge; # group by twos
|
||||
@squares[@ix] = @ch2n{ split //, $_ . ' ' x $N }; # replace
|
||||
$_ += $inc for @ix; # next row or col
|
||||
}
|
||||
$oldboard eq "@squares" and return;
|
||||
add2();
|
||||
losecheck();
|
||||
grep $_ eq 2048, @squares and $winner = 'WINNER !!';
|
||||
}
|
||||
|
||||
sub add2
|
||||
{
|
||||
my @blanks = grep $squares[$_] eq ' ', 0 .. $#squares;
|
||||
@blanks and $squares[ $blanks[rand @blanks] ] =
|
||||
$_[0] // (rand() < 0.1 ? 4 : 2);
|
||||
}
|
||||
|
||||
sub newgame
|
||||
{
|
||||
$_ = ' ' for @squares;
|
||||
add2(2) for 1, 2;
|
||||
$winner = '';
|
||||
}
|
||||
268
Task/2048/Phix/2048.phix
Normal file
268
Task/2048/Phix/2048.phix
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #000080;font-style:italic;">-- demo\rosetta\2048.exw</span>
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
|
||||
|
||||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dialog</span>
|
||||
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">tile_colours</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">#CCC0B4</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- blank</span>
|
||||
<span style="color: #000000;">#EEE4DA</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 2</span>
|
||||
<span style="color: #000000;">#EDE0C8</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 4</span>
|
||||
<span style="color: #000000;">#F2B179</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 8</span>
|
||||
<span style="color: #000000;">#F59563</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 16</span>
|
||||
<span style="color: #000000;">#F67C5F</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 32</span>
|
||||
<span style="color: #000000;">#F65E3B</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 64</span>
|
||||
<span style="color: #000000;">#EDCF72</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 128</span>
|
||||
<span style="color: #000000;">#EDCC61</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 256</span>
|
||||
<span style="color: #000000;">#EDC850</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 512</span>
|
||||
<span style="color: #000000;">#EDC53F</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- 1024</span>
|
||||
<span style="color: #000000;">#EDC22E</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- 2048
|
||||
|
||||
-- the 4x4 board.
|
||||
-- note that values are [1..12] for [blank,2,4,8,..2048].
|
||||
-- (merging two eights is not 8+8->16 but 4+1->5, internally)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">board</span>
|
||||
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">newgame</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">prev</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nxt</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- (nb infinite loop if board is full)</span>
|
||||
<span style="color: #008080;">while</span> <span style="color: #000000;">count</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">),</span>
|
||||
<span style="color: #000000;">y</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- blank</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">+(</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">count</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (not blank)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">bxy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (blank)</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">and</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">13</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (not blank)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">=</span><span style="color: #000000;">prev</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">bxy</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- (blank)</span>
|
||||
<span style="color: #008080;">or</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">and</span> <span style="color: #000000;">prev</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">13</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">d</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">nxt</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">nxt</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bxy</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- a non-zero result means it changed something.</span>
|
||||
<span style="color: #000000;">valid</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_LEFT</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_UP</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">4</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_RIGHT</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">4</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">move_x</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_DOWN</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">prev</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">13</span>
|
||||
<span style="color: #000000;">nxt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #000000;">move_y</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">valid</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">game_won</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">valid_keys</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #004600;">K_LEFT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_DOWN</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_RIGHT</span><span style="color: #0000FF;">,</span><span style="color: #004600;">K_UP</span><span style="color: #0000FF;">}</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">no_valid_moves</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">saved_board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">board</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">saved_board</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- OK</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- game over...</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">,</span><span style="color: #000000;">oy</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- top right coords</span>
|
||||
<span style="color: #000000;">os</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- overall and tile size</span>
|
||||
<span style="color: #000000;">ts2</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- half tile, for number positioning</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">dw</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">dh</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dh</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">ox</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #000000;">oy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">dh</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dw</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">os</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dw</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">ts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">ts2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">10</span>
|
||||
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">newgame</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">board</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">),</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">newgame</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
|
||||
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#FAF8EF</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">#BBADA0</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">os</span><span style="color: #0000FF;">-</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
|
||||
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">tx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ox</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ty</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">oy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">15</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">bxy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">board</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">][</span><span style="color: #000000;">y</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tile_colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #7060A8;">cdCanvasRoundedBox</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts</span><span style="color: #0000FF;">-</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">bxy</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">3</span><span style="color: #0000FF;">?</span><span style="color: #000000;">#776E65</span><span style="color: #0000FF;">:</span><span style="color: #000000;">#F9F6F2</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">cdCanvasFont</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Calibri"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_BOLD</span><span style="color: #0000FF;">,</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">></span><span style="color: #000000;">10</span><span style="color: #0000FF;">?</span><span style="color: #000000;">32</span><span style="color: #0000FF;">:</span><span style="color: #000000;">40</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">cdCanvasText</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ty</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ts2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">25</span><span style="color: #0000FF;">-</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;"><</span><span style="color: #000000;">11</span><span style="color: #0000FF;">?</span><span style="color: #000000;">7</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">),</span> <span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bxy</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">ty</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #000000;">tx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">ts</span><span style="color: #0000FF;">+</span><span style="color: #000000;">5</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">cdCanvasSetTextAlignment</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_SOUTH</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">valid_keys</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">move</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">game_won</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"!!!YOU WON!!!\n\nAnother Go?"</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">add_rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">no_valid_moves</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">mbmsg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"You Lost.\n\nAnother Go?"</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Game Over"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">);</span>
|
||||
<span style="color: #000000;">newgame</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">IupAlarm</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Game Over"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mbmsg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Yes"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"No"</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">newgame</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CONTINUE</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
|
||||
|
||||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
|
||||
|
||||
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=520x540"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">))</span>
|
||||
|
||||
<span style="color: #000000;">dialog</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"MINSIZE=440x450"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"2048"</span><span style="color: #0000FF;">);</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"K_ANY"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">));</span>
|
||||
|
||||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dialog</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
|
||||
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
|
||||
<!--
|
||||
135
Task/2048/PicoLisp/2048.l
Normal file
135
Task/2048/PicoLisp/2048.l
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
(load "@lib/simul.l")
|
||||
|
||||
(symbols 'simul 'pico)
|
||||
|
||||
(seed (in "/dev/urandom" (rd 8)))
|
||||
|
||||
(setq *G (grid 4 4) *D NIL)
|
||||
|
||||
(de cell ()
|
||||
(use This
|
||||
(while
|
||||
(get
|
||||
(setq This
|
||||
(intern
|
||||
(pack
|
||||
(char (+ 96 (rand 1 4)))
|
||||
(rand 1 4) ) ) )
|
||||
'N ) )
|
||||
(=: N (if (> 90 (rand 1 100)) 2 4) ) )
|
||||
(setq *D (fish '((This) (: N)) *G)) )
|
||||
|
||||
(de redraw (G S D)
|
||||
# zeroize *G
|
||||
(mapc
|
||||
'((I)
|
||||
(mapc '((This) (=: N NIL)) I) )
|
||||
*G )
|
||||
# draw again
|
||||
(mapc
|
||||
'((X This)
|
||||
(while (and This X)
|
||||
(=: N (pop 'X))
|
||||
(setq This (D This)) ) )
|
||||
G
|
||||
S ) )
|
||||
|
||||
(de summ (Lst)
|
||||
(mapcar
|
||||
'((L)
|
||||
(make
|
||||
(while L
|
||||
(ifn (= (car L) (cadr L))
|
||||
(link (car L))
|
||||
(link (+ (car L) (cadr L)))
|
||||
(pop 'L) )
|
||||
(pop 'L) ) ) )
|
||||
Lst ) )
|
||||
|
||||
(de vertical ()
|
||||
(mapcar
|
||||
'((X) (extract '((This) (: N)) X))
|
||||
*G ) )
|
||||
|
||||
(de horizontal ()
|
||||
(mapcar
|
||||
'((This)
|
||||
(make
|
||||
(while This
|
||||
(when (: N) (link @))
|
||||
(setq This (east This)) ) ) )
|
||||
(car *G) ) )
|
||||
|
||||
(de finish? ()
|
||||
(nor
|
||||
(fish
|
||||
'((This)
|
||||
(when (atom This) (= NIL (: N))) )
|
||||
*G )
|
||||
(find
|
||||
'((L)
|
||||
(find
|
||||
'((This)
|
||||
(when (: N)
|
||||
(find
|
||||
'((D)
|
||||
(= (: N) (get (D This) 'N)) )
|
||||
(quote north south west east) ) ) )
|
||||
L ) )
|
||||
*G ) ) )
|
||||
|
||||
(de board (D)
|
||||
(space 3)
|
||||
(prin '+)
|
||||
(for I G
|
||||
(prin (if (D (car I)) " +" "---+")) )
|
||||
(prinl) )
|
||||
|
||||
(de display ()
|
||||
(let G (mapcar reverse *G)
|
||||
(board north)
|
||||
(while (caar G)
|
||||
(space 3)
|
||||
(prin '|)
|
||||
(for I G
|
||||
(with (car I)
|
||||
(prin
|
||||
(if (: N) (align 3 (: N)) " ")
|
||||
(if (east This) " " '|) ) ) )
|
||||
(prinl)
|
||||
(board south)
|
||||
(map pop G) )
|
||||
(do 2
|
||||
(prinl) ) ) )
|
||||
|
||||
(do 2
|
||||
(cell) )
|
||||
(display)
|
||||
(loop
|
||||
(case
|
||||
(pack
|
||||
(make
|
||||
(link (key))
|
||||
(while (key 100)
|
||||
(link @) ) ) )
|
||||
("^[[D" #left
|
||||
(redraw (summ (horizontal)) '(a1 a2 a3 a4) east) )
|
||||
("^[[C" #rigth
|
||||
(redraw
|
||||
(summ (mapcar reverse (horizontal)))
|
||||
'(d1 d2 d3 d4)
|
||||
west) )
|
||||
("^[[B" #down
|
||||
(redraw (summ (vertical)) '(a1 b1 c1 d1) north) )
|
||||
("^[[A" #up
|
||||
(redraw
|
||||
(summ (mapcar reverse (vertical)))
|
||||
'(a4 b4 c4 d4)
|
||||
south) ) )
|
||||
(when (diff *D (fish '((This) (: N)) *G))
|
||||
(cell) )
|
||||
(display)
|
||||
(T (finish?) (println 'Finish))
|
||||
(T (fish '((This) (= 512 (: N))) *G)
|
||||
(println 'Maximum) ) )
|
||||
(bye)
|
||||
266
Task/2048/Pony/2048.pony
Normal file
266
Task/2048/Pony/2048.pony
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
use "term"
|
||||
use "random"
|
||||
use "time"
|
||||
|
||||
interface EdgeRow
|
||||
fun val row() : Iterator[U32] ref
|
||||
fun val inc() : I32
|
||||
|
||||
primitive TopRow is EdgeRow
|
||||
fun row() : Iterator[U32] ref => let r : Array[U32] box = [0,1,2,3]
|
||||
r.values()
|
||||
fun inc() : I32 => 4
|
||||
|
||||
primitive LeftRow is EdgeRow
|
||||
fun row() : Iterator[U32] ref => let r : Array[U32] box = [0,4,8,12]
|
||||
r.values()
|
||||
fun inc() : I32 => 1
|
||||
|
||||
primitive RightRow is EdgeRow
|
||||
fun row() : Iterator[U32] ref => let r : Array[U32] box = [3,7,11,15]
|
||||
r.values()
|
||||
fun inc() : I32 => -1
|
||||
|
||||
primitive BottomRow is EdgeRow
|
||||
fun row() : Iterator[U32] ref => let r : Array[U32] box = [12,13,14,15]
|
||||
r.values()
|
||||
fun inc() : I32 => -4
|
||||
|
||||
primitive LEFT
|
||||
primitive RIGHT
|
||||
primitive UP
|
||||
primitive DOWN
|
||||
type Move is (LEFT|RIGHT|UP|DOWN)
|
||||
|
||||
class KeyboardHandler is ANSINotify
|
||||
let _game : Game tag
|
||||
new iso create(game : Game tag) => _game = game
|
||||
|
||||
fun ref apply(term: ANSITerm ref, input: U8 val) =>
|
||||
if input == 113 then
|
||||
_game.quit()
|
||||
term.dispose()
|
||||
end
|
||||
fun ref left(ctrl: Bool, alt: Bool, shift: Bool) => _game.move(LEFT)
|
||||
fun ref down(ctrl: Bool, alt: Bool, shift: Bool) => _game.move(DOWN)
|
||||
fun ref up(ctrl: Bool, alt: Bool, shift: Bool) => _game.move(UP)
|
||||
fun ref right(ctrl: Bool, alt: Bool, shift: Bool) => _game.move(RIGHT)
|
||||
|
||||
type ROW is (U32,U32,U32,U32)
|
||||
|
||||
primitive Merger
|
||||
fun tag apply(r : ROW) : ROW =>
|
||||
match r
|
||||
| (0,0,0,_) => (r._4,0,0,0)
|
||||
| (0,0,_,r._3) => (r._3<<1,0,0,0)
|
||||
| (0,0,_,_) => (r._3,r._4,0,0)
|
||||
| (0,_,r._2,_) => (r._2<<1,r._4,0,0)
|
||||
| (0,_,0,r._2) => (r._2<<1,0,0,0)
|
||||
| (0,_,0,_) => (r._2,r._4,0,0)
|
||||
| (0,_,_,r._3) => (r._2,r._3<<1,0,0)
|
||||
| (0,_,_,_) => (r._2,r._3,r._4,0)
|
||||
| (_, r._1, _, r._3) => (r._1<<1, r._3<<1, 0, 0)
|
||||
| (_, r._1, 0, _) => (r._1<<1, r._4, 0, 0)
|
||||
| (_, r._1, _, _) => (r._1<<1, r._3, r._4, 0)
|
||||
| (_, 0,r._1, _) => (r._1<<1,r._4,0,0)
|
||||
| (_, 0,0, r._1) => (r._1<<1,0,0,0)
|
||||
| (_, 0,0, _) => (r._1,r._4,0,0)
|
||||
| (_, 0,_, r._3) => (r._1, r._3<<1,0,0)
|
||||
| (_, 0,_, _) => (r._1, r._3,r._4,0)
|
||||
| (_,_,r._2,_) => (r._1, r._2<<1,r._4,0)
|
||||
| (_,_,0,r._2) => (r._1, r._2<<1,0,0)
|
||||
| (_,_,0,_) => (r._1, r._2,r._4,0)
|
||||
| (_,_,_,r._3) => (r._1, r._2,r._3<<1,0)
|
||||
else
|
||||
r
|
||||
end
|
||||
/**
|
||||
* Game actor
|
||||
*/
|
||||
actor Game
|
||||
embed _grid : Array[U32] = Array[U32].init(0, 16)
|
||||
let _rand : Random = MT(Time.millis())
|
||||
let _env : Env
|
||||
let _board : String ref = recover String(1024) end
|
||||
|
||||
new create(env: Env)=>
|
||||
_env = env
|
||||
_add_block()
|
||||
_add_block()
|
||||
_draw()
|
||||
|
||||
fun _merge(start : U32, inc : I32) : (ROW | None) =>
|
||||
var st = start.i32()
|
||||
let rval : ROW = (_get(st), _get(st + inc),
|
||||
_get(st + (inc * 2)), _get(st + (inc * 3)))
|
||||
let rout = Merger(rval)
|
||||
if rout is rval then None else rout end
|
||||
|
||||
fun ref _update(start : U32, inc : I32) : Bool =>
|
||||
match _merge(start, inc)
|
||||
| let rout : ROW =>
|
||||
var st = start.i32()
|
||||
_set(st, rout._1)
|
||||
_set(st + inc, rout._2)
|
||||
_set(st + (inc * 2), rout._3)
|
||||
_set(st + (inc * 3), rout._4)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
fun ref _shift_to(edge : EdgeRow val) : Bool =>
|
||||
var updated = false
|
||||
for r in edge.row() do
|
||||
if _update(r, edge.inc()) then
|
||||
updated = true
|
||||
end
|
||||
end
|
||||
updated
|
||||
|
||||
fun _fmt(i : U32) : String =>
|
||||
match i
|
||||
| 0 => " __ "
|
||||
| 2 => "\x1B[31m 2 \x1B[0m"
|
||||
| 4 => "\x1B[32m 4 \x1B[0m"
|
||||
| 8 => "\x1B[33m 8 \x1B[0m"
|
||||
| 16 => "\x1B[34m 16 \x1B[0m"
|
||||
| 32 => "\x1B[35m 32 \x1B[0m"
|
||||
| 64 => "\x1B[36m 64 \x1B[0m"
|
||||
| 128 => "\x1B[37m128 \x1B[0m"
|
||||
| 256 => "\x1B[41m\x1B[37m256 \x1B[0m"
|
||||
| 512 => "\x1B[42m\x1B[37m512 \x1B[0m"
|
||||
| 1024 => "\x1B[43m\x1B[37m1024\x1B[0m"
|
||||
| 2048 => "\x1B[47m\x1B[35m\x1B[1m\x1B[5m2048\x1B[0m"
|
||||
else
|
||||
i.string()
|
||||
end
|
||||
|
||||
fun ref _draw() =>
|
||||
let s : String ref = _board
|
||||
s.truncate(0)
|
||||
var i : U32 = 0
|
||||
repeat
|
||||
if (i % 4) == 0 then
|
||||
s.append("---------------------\n")
|
||||
end
|
||||
s.append(_fmt(_get(i)))
|
||||
s.append(" ")
|
||||
i = i + 1
|
||||
if (i % 4) == 0 then
|
||||
s.append("\n")
|
||||
end
|
||||
until i==16 end
|
||||
_env.out.print(s.string())
|
||||
_env.out.print("Arrow keys to move. Press (q)uit key to quit.")
|
||||
|
||||
fun ref _set(i:(I32|U32), v : U32) =>
|
||||
try
|
||||
_grid.update(i.usize(),v)
|
||||
else
|
||||
_env.out.print("cant update!")
|
||||
end
|
||||
|
||||
fun _count() : U64 =>
|
||||
var c : U64 = 0
|
||||
for v in _grid.values() do
|
||||
c = c + if v == 0 then 0 else 1 end
|
||||
end
|
||||
c
|
||||
|
||||
fun ref _add_block() =>
|
||||
let c = _count()
|
||||
if c == 16 then return end
|
||||
|
||||
var hit = _rand.int(16 - c)
|
||||
var i : U32 = 0
|
||||
while i < 16 do
|
||||
if (_get(i) == 0) then
|
||||
if hit == 0 then
|
||||
_set(i, if _rand.int(10) > 0 then 2 else 4 end)
|
||||
break
|
||||
end
|
||||
hit = hit - 1
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
fun _get(i : (I32|U32)) : U32 => try _grid(i.usize()) else 0 end
|
||||
|
||||
fun _win() : Bool =>
|
||||
for v in _grid.values() do
|
||||
if v == 2048 then return true end
|
||||
end
|
||||
false
|
||||
|
||||
fun _no_moves(edge : EdgeRow val) : Bool =>
|
||||
for r in edge.row() do
|
||||
match _merge(r, edge.inc())
|
||||
| let rout : ROW =>
|
||||
if (rout._1 == 0) or (rout._2 == 0) or
|
||||
(rout._3 == 0) or (rout._4 == 0) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
true
|
||||
|
||||
fun _lose() : Bool =>
|
||||
(_grid.size() >= 16) and
|
||||
_no_moves(LeftRow) and
|
||||
_no_moves(RightRow) and
|
||||
_no_moves(TopRow) and
|
||||
_no_moves(BottomRow)
|
||||
|
||||
be quit()=>
|
||||
_env.out.print("Exiting.. some terminals may require <ctrl-c>")
|
||||
_env.exitcode(0)
|
||||
_env.input.dispose()
|
||||
|
||||
be move(m: Move) =>
|
||||
let updated =
|
||||
match m
|
||||
| LEFT => _shift_to(LeftRow)
|
||||
| RIGHT => _shift_to(RightRow)
|
||||
| UP => _shift_to(TopRow)
|
||||
| DOWN => _shift_to(BottomRow)
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
if _win() then
|
||||
_draw()
|
||||
_env.out.print("You win :)")
|
||||
quit()
|
||||
else
|
||||
if updated then
|
||||
_add_block()
|
||||
_draw()
|
||||
end
|
||||
if _lose() then
|
||||
_env.out.print("You lose :(")
|
||||
quit()
|
||||
end
|
||||
end
|
||||
|
||||
actor Main
|
||||
new create(env: Env) =>
|
||||
// unit test
|
||||
ifdef "test" then
|
||||
TestMain(env)
|
||||
return
|
||||
end
|
||||
// else game
|
||||
let input : Stdin tag = env.input
|
||||
env.out.print("Welcome to ponylang-2048...")
|
||||
let game = Game(env)
|
||||
let term = ANSITerm(KeyboardHandler(game), input)
|
||||
|
||||
let notify : StdinNotify iso = object iso
|
||||
let term: ANSITerm = term
|
||||
let _in: Stdin tag = input
|
||||
fun ref apply(data: Array[U8] iso) => term(consume data)
|
||||
fun ref dispose() => _in.dispose()
|
||||
end
|
||||
|
||||
input(consume notify)
|
||||
158
Task/2048/Prolog/2048.pro
Normal file
158
Task/2048/Prolog/2048.pro
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/* -------------------------------------------------------------
|
||||
Entry point, just create a blank grid and enter a 'game loop'
|
||||
-------------------------------------------------------------*/
|
||||
play_2048 :-
|
||||
welcome_msg,
|
||||
length(Grid, 16), maplist(=(' '), Grid), % create a blank grid
|
||||
play(Grid, yes), !. % don't have to cut here but it makes the exit cleaner
|
||||
|
||||
|
||||
/* -----------------------------------------------
|
||||
Messages that will be printed at various points
|
||||
-----------------------------------------------*/
|
||||
welcome_msg :-
|
||||
format('~nWelcome to the Prolog version of 2048~n~n'),
|
||||
format('To play using w,s,a,d keys for movement, q to quit~n~n').
|
||||
contrats_msg :- format('Congratulations, you reached 2048!~n~n').
|
||||
loser_msg :- format('Uh Oh, you could not quite make it to 2048...~n~n').
|
||||
quit_msg :- format('Bye then!~n~n').
|
||||
|
||||
|
||||
/* -------------------
|
||||
End game conditions
|
||||
-------------------*/
|
||||
player_not_won_yet(Grid) :- maplist(dif(2048), Grid).
|
||||
player_wins(Grid) :- member(2048, Grid).
|
||||
player_loses(G) :- move(up, G, G), move(down, G, G), move(left, G, G), move(right, G, G).
|
||||
|
||||
|
||||
/* ---------
|
||||
Game loop
|
||||
---------*/
|
||||
% First check if the player has reached the win condition, if not find how many spaces are left
|
||||
play(Grid, _) :-
|
||||
player_wins(Grid),
|
||||
draw_grid(Grid),
|
||||
contrats_msg.
|
||||
play(Grid, CreateNewNum) :-
|
||||
player_not_won_yet(Grid),
|
||||
include(=(' '), Grid, Spaces), length(Spaces, NSpaces), % the number of spaces in the grid
|
||||
play(Grid, CreateNewNum, NSpaces).
|
||||
|
||||
% knowing the number of spaces, determine if there is a space, and if we need a new number, and generate.
|
||||
play(Grid, no, _) :- play(Grid).
|
||||
play(Grid, yes, 0) :- play(Grid).
|
||||
play(Grid, yes, NSpaces) :-
|
||||
dif(NSpaces, 0),
|
||||
random_space(NSpaces, Grid, GridWithRandom),
|
||||
play(GridWithRandom).
|
||||
|
||||
% with the new number on the grid we can tell if the player has lost the game yet
|
||||
% if not, draw the grid and get the next action by the player
|
||||
play(Grid) :-
|
||||
player_loses(Grid),
|
||||
draw_grid(Grid),
|
||||
loser_msg.
|
||||
play(Grid) :-
|
||||
\+ player_loses(Grid),
|
||||
draw_grid(Grid),
|
||||
next_move_by_player(Move),
|
||||
player_made_move(Grid, Move).
|
||||
|
||||
% determine the result of player move
|
||||
player_made_move(_, quit).
|
||||
player_made_move(Grid, Move) :-
|
||||
dif(Move, quit),
|
||||
move(Move, Grid, Grid), % The move creating the same grid indicates that no merge was done
|
||||
play(Grid, no). % don't create a new number
|
||||
player_made_move(Grid, Move) :-
|
||||
dif(Move, quit),
|
||||
move(Move, Grid, MovedGrid),
|
||||
dif(Grid, MovedGrid),
|
||||
play(MovedGrid, yes).
|
||||
|
||||
|
||||
/* ---------------------------------------
|
||||
Get the next move from the player input
|
||||
---------------------------------------*/
|
||||
next_move_by_player(Move) :-
|
||||
repeat,
|
||||
get_single_char(Char),
|
||||
key_move(Char, Move).
|
||||
|
||||
% valid keys are: up = 'w', down = 's', left = 'a' right = 'd', quit = 'q'
|
||||
key_move(119, up). key_move(115, down). key_move(97, left). key_move(100, right). key_move(113, quit).
|
||||
|
||||
|
||||
/* ------------------
|
||||
Draw the Game grid
|
||||
------------------*/
|
||||
draw_grid([A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D2,D3,D4]) :-
|
||||
format( '+-------------------+~n'),
|
||||
row([A1,A2,A3,A4]),
|
||||
row([B1,B2,B3,B4]),
|
||||
row([C1,C2,C3,C4]),
|
||||
maplist(draw, [D1,D2,D3,D4]),
|
||||
format('¦~n+-------------------+~n~n~n').
|
||||
|
||||
row([A,B,C,D]) :- maplist(draw, [A,B,C,D]), format('¦~n¦----+----+----+----¦~n').
|
||||
|
||||
draw(' ') :- format('¦ ').
|
||||
draw(X) :- member(X,[2,4,8]), format('¦ ~d ', X).
|
||||
draw(X) :- member(X,[16,32,64]), format('¦ ~d ', X).
|
||||
draw(X) :- member(X,[128,256,512]), format('¦ ~d', X).
|
||||
draw(X) :- member(X,[1024,2048]), format('¦~d', X).
|
||||
|
||||
|
||||
/* ----------------------------------------
|
||||
Populate a random space with a new value
|
||||
----------------------------------------*/
|
||||
random_space(0, G, G).
|
||||
random_space(1, Grid, GridWithRandom) :-
|
||||
four_or_two(V),
|
||||
select(' ', Grid, V, GridWithRandom).
|
||||
random_space(N, Grid, GridWithRandom) :-
|
||||
N > 1,
|
||||
four_or_two(V),
|
||||
random(1, N, P),
|
||||
replace_space(P, V, Grid, GridWithRandom).
|
||||
|
||||
replace_space(0, V, [' '|T], [V|T]).
|
||||
replace_space(P, V, [' '|T], [' '|R]) :- succ(NextP, P), replace_space(NextP, V, T, R).
|
||||
replace_space(P, V, [H|T], [H|R]) :- dif(' ', H), replace_space(P, V, T, R).
|
||||
|
||||
four_or_two(V) :- random(1, 10, IsFour), IsFour = 1 -> V = 4 ; V = 2.
|
||||
|
||||
|
||||
/* ------------------------------------------
|
||||
Process a game move based on the direction
|
||||
------------------------------------------*/
|
||||
move(Direction, UnMoved, Moved) :-
|
||||
map_move(Direction, UnMoved, UnMovedMapped),
|
||||
maplist(combine_row, UnMovedMapped, MovedMapped),
|
||||
map_move(Direction, Moved, MovedMapped).
|
||||
|
||||
% convert the array to a set of lists that can be moved in the same
|
||||
% direction. This can be reversed after the move is completed.
|
||||
map_move(up, [A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D2,D3,D4], [[D1,C1,B1,A1],[D2,C2,B2,A2],[D3,C3,B3,A3],[D4,C4,B4,A4]]).
|
||||
map_move(down, [A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D2,D3,D4], [[A1,B1,C1,D1],[A2,B2,C2,D2],[A3,B3,C3,D3],[A4,B4,C4,D4]]).
|
||||
map_move(left, [A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D2,D3,D4], [[A4,A3,A2,A1],[B4,B3,B2,B1],[C4,C3,C2,C1],[D4,D3,D2,D1]]).
|
||||
map_move(right, [A1,A2,A3,A4,B1,B2,B3,B4,C1,C2,C3,C4,D1,D2,D3,D4], [[A1,A2,A3,A4],[B1,B2,B3,B4],[C1,C2,C3,C4],[D1,D2,D3,D4]]).
|
||||
|
||||
% remove all the spaces, then put them at the front of the list
|
||||
combine_row(UnMoved, Moved) :-
|
||||
partition(=(' '), UnMoved, Blank, Set),
|
||||
append(Blank, Set, ReadyToMove),
|
||||
combine(ReadyToMove, Moved).
|
||||
|
||||
% combine based on the rules of the game.
|
||||
combine([A,B,C,D], [A,B,C,D]) :- dif(A,B), dif(B,C), dif(C,D).
|
||||
combine([A,A,B,B], [' ',' ',Ad,Bd]) :- dbl(A,Ad), dbl(B,Bd).
|
||||
combine([A,B,C,C], [' ',A,B,Cd]) :- dif(A,B), dbl(C,Cd).
|
||||
combine([A,B,B,C], [' ',A,Bd,C]) :- dif(B,C), dbl(B,Bd).
|
||||
combine([A,A,B,C], [' ',Ad,B,C]) :- dif(A,B), dif(B,C), dbl(A, Ad).
|
||||
combine([A,B,C,C], [' ',A,B,Cd]) :- dif(A,B), dif(B,C), dbl(C,Cd).
|
||||
|
||||
% this could be done using maths, but it is more prology this way.
|
||||
dbl(' ', ' ').
|
||||
dbl(2,4). dbl(4,8). dbl(8,16). dbl(16,32). dbl(32,64). dbl(64,128). dbl(128,256). dbl(256,512). dbl(512,1028). dbl(1028,2048).
|
||||
201
Task/2048/Python/2048-1.py
Normal file
201
Task/2048/Python/2048-1.py
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import curses
|
||||
from random import randrange, choice # generate and place new tile
|
||||
from collections import defaultdict
|
||||
|
||||
letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']
|
||||
actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
|
||||
actions_dict = dict(zip(letter_codes, actions * 2))
|
||||
|
||||
def get_user_action(keyboard):
|
||||
char = "N"
|
||||
while char not in actions_dict:
|
||||
char = keyboard.getch()
|
||||
return actions_dict[char]
|
||||
|
||||
def transpose(field):
|
||||
return [list(row) for row in zip(*field)]
|
||||
|
||||
def invert(field):
|
||||
return [row[::-1] for row in field]
|
||||
|
||||
class GameField(object):
|
||||
def __init__(self, height=4, width=4, win=2048):
|
||||
self.height = height
|
||||
self.width = width
|
||||
self.win_value = win
|
||||
self.score = 0
|
||||
self.highscore = 0
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
if self.score > self.highscore:
|
||||
self.highscore = self.score
|
||||
self.score = 0
|
||||
self.field = [[0 for i in range(self.width)] for j in range(self.height)]
|
||||
self.spawn()
|
||||
self.spawn()
|
||||
|
||||
def move(self, direction):
|
||||
def move_row_left(row):
|
||||
def tighten(row): # squeese non-zero elements together
|
||||
new_row = [i for i in row if i != 0]
|
||||
new_row += [0 for i in range(len(row) - len(new_row))]
|
||||
return new_row
|
||||
|
||||
def merge(row):
|
||||
pair = False
|
||||
new_row = []
|
||||
for i in range(len(row)):
|
||||
if pair:
|
||||
new_row.append(2 * row[i])
|
||||
self.score += 2 * row[i]
|
||||
pair = False
|
||||
else:
|
||||
if i + 1 < len(row) and row[i] == row[i + 1]:
|
||||
pair = True
|
||||
new_row.append(0)
|
||||
else:
|
||||
new_row.append(row[i])
|
||||
assert len(new_row) == len(row)
|
||||
return new_row
|
||||
return tighten(merge(tighten(row)))
|
||||
|
||||
moves = {}
|
||||
moves['Left'] = lambda field: \
|
||||
[move_row_left(row) for row in field]
|
||||
moves['Right'] = lambda field: \
|
||||
invert(moves['Left'](invert(field)))
|
||||
moves['Up'] = lambda field: \
|
||||
transpose(moves['Left'](transpose(field)))
|
||||
moves['Down'] = lambda field: \
|
||||
transpose(moves['Right'](transpose(field)))
|
||||
|
||||
if direction in moves:
|
||||
if self.move_is_possible(direction):
|
||||
self.field = moves[direction](self.field)
|
||||
self.spawn()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_win(self):
|
||||
return any(any(i >= self.win_value for i in row) for row in self.field)
|
||||
|
||||
def is_gameover(self):
|
||||
return not any(self.move_is_possible(move) for move in actions)
|
||||
|
||||
def draw(self, screen):
|
||||
help_string1 = '(W)Up (S)Down (A)Left (D)Right'
|
||||
help_string2 = ' (R)Restart (Q)Exit'
|
||||
gameover_string = ' GAME OVER'
|
||||
win_string = ' YOU WIN!'
|
||||
def cast(string):
|
||||
screen.addstr(string + '\n')
|
||||
|
||||
def draw_hor_separator():
|
||||
top = '┌' + ('┬──────' * self.width + '┐')[1:]
|
||||
mid = '├' + ('┼──────' * self.width + '┤')[1:]
|
||||
bot = '└' + ('┴──────' * self.width + '┘')[1:]
|
||||
separator = defaultdict(lambda: mid)
|
||||
separator[0], separator[self.height] = top, bot
|
||||
if not hasattr(draw_hor_separator, "counter"):
|
||||
draw_hor_separator.counter = 0
|
||||
cast(separator[draw_hor_separator.counter])
|
||||
draw_hor_separator.counter += 1
|
||||
|
||||
def draw_row(row):
|
||||
cast(''.join('│{: ^5} '.format(num) if num > 0 else '| ' for num in row) + '│')
|
||||
|
||||
screen.clear()
|
||||
cast('SCORE: ' + str(self.score))
|
||||
if 0 != self.highscore:
|
||||
cast('HIGHSCORE: ' + str(self.highscore))
|
||||
for row in self.field:
|
||||
draw_hor_separator()
|
||||
draw_row(row)
|
||||
draw_hor_separator()
|
||||
if self.is_win():
|
||||
cast(win_string)
|
||||
else:
|
||||
if self.is_gameover():
|
||||
cast(gameover_string)
|
||||
else:
|
||||
cast(help_string1)
|
||||
cast(help_string2)
|
||||
|
||||
def spawn(self):
|
||||
new_element = 4 if randrange(100) > 89 else 2
|
||||
(i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])
|
||||
self.field[i][j] = new_element
|
||||
|
||||
def move_is_possible(self, direction):
|
||||
def row_is_left_movable(row):
|
||||
def change(i): # true if there'll be change in i-th tile
|
||||
if row[i] == 0 and row[i + 1] != 0: # Move
|
||||
return True
|
||||
if row[i] != 0 and row[i + 1] == row[i]: # Merge
|
||||
return True
|
||||
return False
|
||||
return any(change(i) for i in range(len(row) - 1))
|
||||
|
||||
check = {}
|
||||
check['Left'] = lambda field: \
|
||||
any(row_is_left_movable(row) for row in field)
|
||||
|
||||
check['Right'] = lambda field: \
|
||||
check['Left'](invert(field))
|
||||
|
||||
check['Up'] = lambda field: \
|
||||
check['Left'](transpose(field))
|
||||
|
||||
check['Down'] = lambda field: \
|
||||
check['Right'](transpose(field))
|
||||
|
||||
if direction in check:
|
||||
return check[direction](self.field)
|
||||
else:
|
||||
return False
|
||||
|
||||
def main(stdscr):
|
||||
curses.use_default_colors()
|
||||
game_field = GameField(win=32)
|
||||
state_actions = {} # Init, Game, Win, Gameover, Exit
|
||||
def init():
|
||||
game_field.reset()
|
||||
return 'Game'
|
||||
|
||||
state_actions['Init'] = init
|
||||
|
||||
def not_game(state):
|
||||
game_field.draw(stdscr)
|
||||
action = get_user_action(stdscr)
|
||||
responses = defaultdict(lambda: state)
|
||||
responses['Restart'], responses['Exit'] = 'Init', 'Exit'
|
||||
return responses[action]
|
||||
|
||||
state_actions['Win'] = lambda: not_game('Win')
|
||||
state_actions['Gameover'] = lambda: not_game('Gameover')
|
||||
|
||||
def game():
|
||||
game_field.draw(stdscr)
|
||||
action = get_user_action(stdscr)
|
||||
if action == 'Restart':
|
||||
return 'Init'
|
||||
if action == 'Exit':
|
||||
return 'Exit'
|
||||
if game_field.move(action): # move successful
|
||||
if game_field.is_win():
|
||||
return 'Win'
|
||||
if game_field.is_gameover():
|
||||
return 'Gameover'
|
||||
return 'Game'
|
||||
|
||||
state_actions['Game'] = game
|
||||
|
||||
state = 'Init'
|
||||
while state != 'Exit':
|
||||
state = state_actions[state]()
|
||||
|
||||
curses.wrapper(main)
|
||||
294
Task/2048/Python/2048-2.py
Normal file
294
Task/2048/Python/2048-2.py
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
''' Python 3.6.5 code using Tkinter graphical user interface.
|
||||
Option to set goal to powers of 2 from 128 to 2048. '''
|
||||
from tkinter import *
|
||||
from tkinter import messagebox
|
||||
from tkinter import ttk
|
||||
import random
|
||||
|
||||
# ************************************************
|
||||
|
||||
class Board:
|
||||
|
||||
def __init__(self):
|
||||
self.bd = ['']* 16
|
||||
self.goal = 2048
|
||||
self.choices = '2222222224'
|
||||
|
||||
# place 2 random squares on empty board:
|
||||
def place_two(self):
|
||||
idx = range(15)
|
||||
a, b = random.sample(idx, 2)
|
||||
self.bd[a] = random.choice(self.choices)
|
||||
self.bd[b] = random.choice(self.choices)
|
||||
|
||||
# return text on square at index=idx of board:
|
||||
def get_text(self, idx):
|
||||
return self.bd[idx]
|
||||
|
||||
# move squares on board based on arrow key entered:
|
||||
def move_squares(self, key):
|
||||
if key in ('LR'):
|
||||
# generate 4x4 2D array for row processing:
|
||||
rows = [[self.bd[0], self.bd[1], self.bd[2], self.bd[3]],
|
||||
[self.bd[4], self.bd[5], self.bd[6], self.bd[7]],
|
||||
[self.bd[8], self.bd[9], self.bd[10], self.bd[11]],
|
||||
[self.bd[12], self.bd[13], self.bd[14], self.bd[15]]]
|
||||
else:
|
||||
# generate transposed 4x4 2D array instead:
|
||||
rows = [[self.bd[0], self.bd[4], self.bd[8], self.bd[12]],
|
||||
[self.bd[1], self.bd[5], self.bd[9], self.bd[13]],
|
||||
[self.bd[2], self.bd[6], self.bd[10], self.bd[14]],
|
||||
[self.bd[3], self.bd[7], self.bd[11], self.bd[15]]]
|
||||
|
||||
# build a new 4x4 array of "moved" rows:
|
||||
nrows = []
|
||||
for row in rows:
|
||||
if key in 'RD':
|
||||
# reverse these rows and slide to left:
|
||||
row = row[::-1]
|
||||
nrow = self.slide_squares(row)
|
||||
if key in 'RD':
|
||||
# restore reversed rows:
|
||||
nrow = nrow[::-1]
|
||||
nrows.append(nrow)
|
||||
if key in ('UD'):
|
||||
# transpose arrays that were transposed:
|
||||
nrows = list(map(list, zip(*nrows)))
|
||||
|
||||
# flatten 4x4 2D array:
|
||||
newbd = []
|
||||
for row in nrows:
|
||||
for r in row:
|
||||
newbd.append(r)
|
||||
|
||||
# place a '2' or '4' in random open square of newbd:
|
||||
if newbd != self.bd and '' in newbd:
|
||||
loi = []
|
||||
for i in range(16):
|
||||
if newbd[i] == '':
|
||||
loi.append(i)
|
||||
i = random.choice(loi)
|
||||
newbd[i] = random.choice(self.choices)
|
||||
|
||||
self.bd = newbd
|
||||
return
|
||||
|
||||
# slide squares in row to the left:
|
||||
def slide_squares(self, row):
|
||||
new = [''] * 4
|
||||
icmb = -1
|
||||
inew = 0
|
||||
for x in row:
|
||||
if x:
|
||||
if (inew > 0 and
|
||||
x == new[inew-1] and
|
||||
icmb != inew-1):
|
||||
new[inew-1] = str(2*int(x))
|
||||
icmb = inew-1
|
||||
else:
|
||||
new[inew] = x
|
||||
inew += 1
|
||||
return new
|
||||
|
||||
# check if game won, lost, or continuing:
|
||||
def is_end(self):
|
||||
if self.goal in self.bd:
|
||||
return 'W'
|
||||
if '' in self.bd:
|
||||
return 'C'
|
||||
for i in [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14]:
|
||||
if self.bd[i] == self.bd[i+1]:
|
||||
return 'C'
|
||||
for i in range(12):
|
||||
if self.bd[i] == self.bd[i+4]:
|
||||
return 'C'
|
||||
return 'L'
|
||||
|
||||
# ************************************************
|
||||
|
||||
class Game:
|
||||
def __init__(self, gw):
|
||||
self.window = gw
|
||||
|
||||
self.rosybrown1 = '#ffc1c1'
|
||||
self.lemonchiffon = '#fffacd'
|
||||
self.skyblue1 = '#87ceff'
|
||||
self.springgreen = '#00ff7f'
|
||||
self.tomato1 = '#ff6347'
|
||||
self.hotpink = '#ff69b4'
|
||||
self.brilliantlavender = '#edcaf6'
|
||||
self.cobaltgreen = '#3d9140'
|
||||
self.dodgerblue = '#1e90ff'
|
||||
self.darkgoldenrod1 = '#ffb90f'
|
||||
self.yellow = '#ffff00'
|
||||
self.imperialred = '#ed2939'
|
||||
self.navyblue = '#000080'
|
||||
self.lightgreen = '#90ee90'
|
||||
self.lightsteelblue = '#b0c4de'
|
||||
self.white = '#ffffff'
|
||||
self.palegreen4 = '#548b54'
|
||||
self.darkgreen = '#013220'
|
||||
self.black = '#000000'
|
||||
|
||||
self.doc = {'':self.rosybrown1,
|
||||
'2':self.lemonchiffon,
|
||||
'4':self.skyblue1,
|
||||
'8':self.springgreen,
|
||||
'16':self.tomato1,
|
||||
'32':self.hotpink,
|
||||
'64':self.brilliantlavender,
|
||||
'128':self.cobaltgreen,
|
||||
'256':self.dodgerblue,
|
||||
'512':self.darkgoldenrod1,
|
||||
'1024':self.yellow,
|
||||
'2048':self.imperialred}
|
||||
|
||||
# game data:
|
||||
self.bd = None
|
||||
self.playable = False
|
||||
|
||||
# top frame:
|
||||
self.top_fr = Frame(gw,
|
||||
width=600,
|
||||
height=100,
|
||||
bg=self.lightgreen)
|
||||
self.top_fr.pack(fill=X)
|
||||
|
||||
self.hdg = Label(self.top_fr,
|
||||
text=' 2048 ',
|
||||
font='arial 22 bold',
|
||||
fg=self.navyblue,
|
||||
bg=self.white)
|
||||
self.hdg.place(relx=0.5, rely=0.4,
|
||||
anchor=CENTER)
|
||||
|
||||
self.dir = Label(self.top_fr,
|
||||
text="(Select a 'Goal' & Click 'New Game')",
|
||||
font='arial 12 ',
|
||||
fg=self.navyblue,
|
||||
bg=self.lightgreen)
|
||||
self.dir.place(relx=0.5, rely=0.8,
|
||||
anchor=CENTER)
|
||||
|
||||
self.play_btn = Button(self.top_fr,
|
||||
text='New \nGame',
|
||||
bd=5,
|
||||
bg=self.palegreen4,
|
||||
fg=self.white,
|
||||
font='times 12 bold',
|
||||
command=self.new_game)
|
||||
self.play_btn.place(relx=0.92, rely=0.5,
|
||||
anchor=E)
|
||||
|
||||
self.lbl_cb = Label(self.top_fr,
|
||||
text=' Goal',
|
||||
font='arial 12 bold ',
|
||||
fg=self.darkgreen,
|
||||
bg=self.lightgreen)
|
||||
self.lbl_cb.place(relx=0.08, rely=0.35,
|
||||
anchor=W)
|
||||
|
||||
goals = ['2048', '1024', '512', '256', '128']
|
||||
self.cur_goal = StringVar()
|
||||
self.goal_cb = ttk.Combobox(self.top_fr,
|
||||
foreground=self.darkgreen,
|
||||
values=goals,
|
||||
font='times 12 bold',
|
||||
justify='left',
|
||||
state='readonly',
|
||||
textvariable=self.cur_goal,
|
||||
width=7,
|
||||
height=30)
|
||||
self.goal_cb.place(relx=0.08, rely=0.6,
|
||||
anchor=W)
|
||||
self.goal_cb.current(0)
|
||||
|
||||
# bottom frame:
|
||||
self.btm_fr = Frame(gw,
|
||||
width=600,
|
||||
height=500,
|
||||
bg=self.lightsteelblue)
|
||||
self.btm_fr.pack(fill=X)
|
||||
|
||||
# board frame:
|
||||
self.bd_fr = Frame(self.btm_fr,
|
||||
width=400+2,
|
||||
height=400+2,
|
||||
relief='solid',
|
||||
bd=1,
|
||||
bg=self.lemonchiffon)
|
||||
self.bd_fr.place(relx=0.5, rely=0.5,
|
||||
anchor=CENTER)
|
||||
|
||||
self.bd = Board()
|
||||
self.play_game()
|
||||
|
||||
# ************************************************
|
||||
|
||||
# action to take if 'new game' button is clicked
|
||||
# or if 'play again' is chosen after win or loss:
|
||||
def new_game(self):
|
||||
self.playable = True
|
||||
self.bd = Board()
|
||||
self.bd.place_two()
|
||||
self.bd.goal = self.goal_cb.get()
|
||||
self.goal_cb.config(state='disabled')
|
||||
self.dir.config(text='(Use arrow keys to play game)')
|
||||
self.play_game()
|
||||
|
||||
# show current contents of board:
|
||||
def play_game(self):
|
||||
objh = 100 # widget height
|
||||
objw = 100 # widget width
|
||||
objx = 0 # x-position of widget in frame
|
||||
objy = 0 # y-position of widget in frame
|
||||
|
||||
i = 0
|
||||
for r in range(4):
|
||||
for c in range(4):
|
||||
txt = self.bd.get_text(i)
|
||||
bg_color = self.doc[txt]
|
||||
game_sq = Label(self.bd_fr,
|
||||
text=txt,
|
||||
relief='solid',
|
||||
bd=1,
|
||||
fg=self.black,
|
||||
bg=bg_color,
|
||||
font='times 16 bold')
|
||||
game_sq.place(x=objx, y=objy,
|
||||
height=objh, width=objw)
|
||||
i += 1
|
||||
objx = objx + objw
|
||||
objx = 0
|
||||
objy = objy + objh
|
||||
|
||||
# control play when an arrow key is pressed:
|
||||
def key(self, event):
|
||||
if event.keysym in ('Left', 'Right', 'Up', 'Down'):
|
||||
if self.playable:
|
||||
self.bd.move_squares(event.keysym[0])
|
||||
self.play_game()
|
||||
x = self.bd.is_end()
|
||||
if x == 'C':
|
||||
return
|
||||
elif x == 'W':
|
||||
msg = 'You won!!! Play again?'
|
||||
elif x == 'L':
|
||||
msg = 'You lost!!! Play again?'
|
||||
ans = messagebox.askquestion(msg)
|
||||
if ans == 'no':
|
||||
self.window.destroy()
|
||||
else:
|
||||
self.new_game()
|
||||
|
||||
# ************************************************
|
||||
|
||||
root = Tk()
|
||||
root.title('2048')
|
||||
root.geometry('600x600+100+50')
|
||||
root.resizable(False, False)
|
||||
g = Game(root)
|
||||
root.bind_all('<Key>', g.key)
|
||||
root.mainloop()
|
||||
287
Task/2048/QB64/2048.qb64
Normal file
287
Task/2048/QB64/2048.qb64
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
_DEFINE A-Z AS _INTEGER64
|
||||
DIM SHARED Grid(0 TO 5, 0 TO 5) AS INTEGER
|
||||
CONST Left = 19200
|
||||
CONST Right = 19712
|
||||
CONST Down = 20480
|
||||
CONST Up = 18432
|
||||
CONST ESC = 27
|
||||
CONST LCtrl = 100306
|
||||
CONST RCtrl = 100305
|
||||
|
||||
Init
|
||||
MakeNewGame
|
||||
DO
|
||||
_LIMIT 30
|
||||
ShowGrid
|
||||
CheckInput flag
|
||||
IF flag THEN GetNextNumber
|
||||
_DISPLAY
|
||||
LOOP
|
||||
|
||||
SUB CheckInput (flag)
|
||||
flag = 0
|
||||
k = _KEYHIT
|
||||
SELECT CASE k
|
||||
CASE ESC: SYSTEM
|
||||
CASE 83, 115 'S
|
||||
IF _KEYDOWN(LCtrl) OR _KEYDOWN(RCtrl) THEN MakeNewGame
|
||||
CASE Left
|
||||
MoveLeft
|
||||
flag = -1 'we hit a valid move key. Even if we don't move, get a new number
|
||||
CASE Up
|
||||
MoveUp
|
||||
flag = -1
|
||||
CASE Down
|
||||
MoveDown
|
||||
flag = -1
|
||||
CASE Right
|
||||
MoveRight
|
||||
flag = -1
|
||||
END SELECT
|
||||
END SUB
|
||||
|
||||
SUB MoveDown
|
||||
'first move everything left to cover the blank spaces
|
||||
DO
|
||||
moved = 0
|
||||
FOR y = 4 TO 1 STEP -1
|
||||
FOR x = 1 TO 4
|
||||
IF Grid(x, y) = 0 THEN 'every point above this moves down
|
||||
FOR j = y TO 1 STEP -1
|
||||
Grid(x, j) = Grid(x, j - 1)
|
||||
IF Grid(x, j) <> 0 THEN moved = -1
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
IF moved THEN y = y + 1 'recheck the same column
|
||||
LOOP UNTIL NOT moved
|
||||
FOR y = 4 TO 1 STEP -1
|
||||
FOR x = 1 TO 4
|
||||
IF Grid(x, y) <> 0 AND Grid(x, y) = Grid(x, y - 1) THEN 'add them together and every point above this moves
|
||||
Grid(x, y) = Grid(x, y) * 2
|
||||
FOR j = y - 1 TO 1
|
||||
Grid(x, j) = Grid(x, j - 1)
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB MoveLeft
|
||||
'first move everything to cover the blank spaces
|
||||
DO
|
||||
moved = 0
|
||||
FOR x = 1 TO 4
|
||||
FOR y = 1 TO 4
|
||||
IF Grid(x, y) = 0 THEN 'every point right of this moves left
|
||||
FOR j = x TO 4
|
||||
Grid(j, y) = Grid(j + 1, y)
|
||||
IF Grid(j, y) <> 0 THEN moved = -1
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
IF moved THEN x = x - 1 'recheck the same row
|
||||
LOOP UNTIL NOT moved
|
||||
FOR x = 1 TO 4
|
||||
FOR y = 1 TO 4
|
||||
IF Grid(x, y) <> 0 AND Grid(x, y) = Grid(x + 1, y) THEN 'add them together and every point right of this moves left
|
||||
Grid(x, y) = Grid(x, y) * 2
|
||||
FOR j = x + 1 TO 4
|
||||
Grid(j, y) = Grid(j + 1, y)
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB MoveUp
|
||||
'first move everything to cover the blank spaces
|
||||
DO
|
||||
moved = 0
|
||||
FOR y = 1 TO 4
|
||||
FOR x = 1 TO 4
|
||||
IF Grid(x, y) = 0 THEN 'every point below of this moves up
|
||||
FOR j = y TO 4
|
||||
Grid(x, j) = Grid(x, j + 1)
|
||||
IF Grid(x, j) <> 0 THEN moved = -1
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
IF moved THEN y = y - 1 'recheck the same column
|
||||
LOOP UNTIL NOT moved
|
||||
FOR y = 1 TO 4
|
||||
FOR x = 1 TO 4
|
||||
IF Grid(x, y) <> 0 AND Grid(x, y) = Grid(x, y + 1) THEN 'add them together and every point below this moves
|
||||
Grid(x, y) = Grid(x, y) * 2
|
||||
FOR j = y + 1 TO 4
|
||||
Grid(x, j) = Grid(x, j + 1)
|
||||
NEXT
|
||||
Grid(x, 4) = 0
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB MoveRight
|
||||
'first move everything to cover the blank spaces
|
||||
DO
|
||||
moved = 0
|
||||
FOR x = 4 TO 1 STEP -1
|
||||
FOR y = 1 TO 4
|
||||
IF Grid(x, y) = 0 THEN 'every point right of this moves left
|
||||
FOR j = x TO 1 STEP -1
|
||||
Grid(j, y) = Grid(j - 1, y)
|
||||
IF Grid(j, y) <> 0 THEN moved = -1
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
IF moved THEN x = x - 1 'recheck the same row
|
||||
LOOP UNTIL NOT moved
|
||||
|
||||
FOR x = 4 TO 1 STEP -1
|
||||
FOR y = 1 TO 4
|
||||
IF Grid(x, y) <> 0 AND Grid(x, y) = Grid(x - 1, y) THEN 'add them together and every point right of this moves left
|
||||
Grid(x, y) = Grid(x, y) * 2
|
||||
FOR j = x - 1 TO 1 STEP -1
|
||||
Grid(j, y) = Grid(j - 1, y)
|
||||
NEXT
|
||||
END IF
|
||||
NEXT
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB ShowGrid
|
||||
'SUB MakeBox (Mode AS INTEGER, x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER,
|
||||
'Caption AS STRING, FontColor AS _UNSIGNED LONG, FontBackground AS _UNSIGNED LONG,
|
||||
'BoxColor AS _UNSIGNED LONG, BoxHighLight AS _UNSIGNED LONG, XOffset AS INTEGER, YOffset AS INTEGER)
|
||||
w = 120
|
||||
h = 120
|
||||
FOR x = 1 TO 4
|
||||
FOR y = 1 TO 4
|
||||
t$ = LTRIM$(STR$(Grid(x, y)))
|
||||
IF t$ = "0" THEN t$ = ""
|
||||
MakeBox 4, (x - 1) * w, (y - 1) * h, w, h, t$, -1, 0, 0, -1, 0, 0
|
||||
NEXT
|
||||
NEXT
|
||||
END SUB
|
||||
|
||||
SUB Init
|
||||
ws = _NEWIMAGE(480, 480, 32)
|
||||
SCREEN ws
|
||||
_DELAY 1
|
||||
_TITLE "Double Up"
|
||||
_SCREENMOVE _MIDDLE
|
||||
RANDOMIZE TIMER
|
||||
f& = _LOADFONT("C:\Windows\Fonts\courbd.ttf", 32, "MONOSPACE")
|
||||
_FONT f&
|
||||
|
||||
END SUB
|
||||
|
||||
SUB MakeNewGame
|
||||
FOR x = 1 TO 4
|
||||
FOR y = 1 TO 4
|
||||
Grid(x, y) = 0
|
||||
NEXT
|
||||
NEXT
|
||||
GetNextNumber
|
||||
GetNextNumber
|
||||
END SUB
|
||||
|
||||
SUB GetNextNumber
|
||||
FOR x = 1 TO 4
|
||||
FOR y = 1 TO 4
|
||||
IF Grid(x, y) = 0 THEN valid = -1
|
||||
NEXT
|
||||
NEXT
|
||||
IF valid THEN 'If all the grids are full, we can't add any more numbers
|
||||
'This doesn't mean the game is over, as the player may be able to
|
||||
DO
|
||||
x = _CEIL(RND * 4)
|
||||
y = _CEIL(RND * 4)
|
||||
LOOP UNTIL Grid(x, y) = 0
|
||||
Grid(x, y) = 2
|
||||
END IF
|
||||
END SUB
|
||||
|
||||
SUB MakeBox (Mode AS INTEGER, x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER, Caption AS STRING, FontColor AS _UNSIGNED LONG, FontBackground AS _UNSIGNED LONG, BoxColor AS _UNSIGNED LONG, BoxHighLight AS _UNSIGNED LONG, XOffset AS INTEGER, YOffset AS INTEGER)
|
||||
|
||||
'This is an upgrade version of my original Button routine.
|
||||
'It's more versitile (but complex) than the original.
|
||||
'Mode 0 (or any unsupported number) will tell the box to size itself from X1,Y1 to X2,Y2
|
||||
'Mode 1 will tell the box to autosize itself according to whatever text is placed within it.
|
||||
'Mode 2 will tell the box to use X2 and Y2 as relative coordinates and not absolute coordinates.
|
||||
'Mode 3 will tell the box to autocenter text with X2, Y2 being absolute coordinates.
|
||||
'Mode 4 will tell the box to autocenter text with X2, Y2 being relative coordinates.
|
||||
'Mode otherwise is unused, but available for expanded functionality.
|
||||
'X1 carries the X location of where we want to place our box on the screen.
|
||||
'Y2 carries the Y location of where we want to place our box on the screen.
|
||||
'X2 is the X boundry of our box on the screen, depending on our mode.
|
||||
'Y2 is the Y boundry of our box on the screen, depending on our mode.
|
||||
|
||||
'Caption is the text that we want our box to contain.
|
||||
|
||||
'FontColor is our font color for our caption
|
||||
'FontBackground is the font background color for our caption
|
||||
'NOTE: IF FONTCOLOR OR FONTBACKGROUND IS SET TO ZERO, THEY WILL **NOT** AFFECT THE COLOR BEHIND THEM.
|
||||
'This can be used to mimic the function of _KEEPBACKGROUND, _FILLBACKGROUND, or _ONLYBACKGROUND
|
||||
|
||||
'BoxColor is our box color
|
||||
'BoxHighlight is our box highligh colors
|
||||
'NOTE: SAME WITH BOXCOLOR AND BOXHIGHLIGHT. IF SET TO ZERO, THEY WILL HAVE **NO** COLOR AT ALL TO THEM, AND WILL NOT AFFECT THE BACKGROUND OF ANYTHING BEHIND THEM.
|
||||
|
||||
'XOffset is used to offset our text # pixels from the X1 top.
|
||||
'YOffset is used to offset our text # pixels from the Y1 top.
|
||||
'These can be used to place our text wherever we want on our box.
|
||||
'But remember, if Mode = 3 or 4, the box will autocenter the text and ignore these parameters completely.
|
||||
|
||||
DIM BoxBlack AS _UNSIGNED LONG
|
||||
|
||||
dc& = _DEFAULTCOLOR: bg& = _BACKGROUNDCOLOR
|
||||
IF Black <> 0 THEN
|
||||
'We have black either as a CONST or a SHARED color
|
||||
BoxBlack = Black
|
||||
ELSE
|
||||
'We need to define what Black is for our box.
|
||||
BoxBlack = _RGB32(0, 0, 0)
|
||||
END IF
|
||||
|
||||
IF _FONTWIDTH <> 0 THEN cw = _FONTWIDTH * LEN(Caption) ELSE cw = _PRINTWIDTH(Caption)
|
||||
ch = _FONTHEIGHT
|
||||
|
||||
tx1 = x1: tx2 = x2: ty1 = y1: ty2 = y2
|
||||
SELECT CASE Mode
|
||||
CASE 0
|
||||
'We use the X2, Y2 coordinates provided as absolute coordinates
|
||||
CASE 1
|
||||
tx2 = tx1 + cw + 8
|
||||
ty2 = ty1 + ch + 8
|
||||
XOffset = 5: YOffset = 5
|
||||
CASE 2
|
||||
tx2 = tx1 + x2
|
||||
ty2 = ty1 + y2
|
||||
CASE 3
|
||||
XOffset = (tx2 - tx1 - cw) \ 2
|
||||
YOffset = (ty2 - ty1 - ch) \ 2
|
||||
CASE 4
|
||||
tx2 = tx1 + x2
|
||||
ty2 = ty1 + y2
|
||||
XOffset = (tx2 - tx1) \ 2 - cw \ 2
|
||||
YOffset = (ty2 - ty1 - ch) \ 2
|
||||
END SELECT
|
||||
LINE (tx1, ty1)-(tx2, ty2), BoxBlack, BF
|
||||
LINE (tx1 + 1, ty1 + 1)-(tx2 - 1, ty2 - 1), BoxHighLight, B
|
||||
LINE (tx1 + 2, ty1 + 2)-(tx2 - 2, ty2 - 2), BoxHighLight, B
|
||||
LINE (tx1 + 3, ty1 + 3)-(tx2 - 3, ty2 - 3), BoxBlack, B
|
||||
LINE (tx1, ty1)-(tx1 + 3, ty1 + 3), BoxBlack
|
||||
LINE (tx2, ty1)-(tx2 - 3, ty1 + 3), BoxBlack
|
||||
LINE (tx1, ty2)-(tx1 + 3, ty2 - 3), BoxBlack
|
||||
LINE (tx2, ty2)-(tx2 - 3, ty2 - 3), BoxBlack
|
||||
LINE (tx1 + 3, y1 + 3)-(tx2 - 3, ty2 - 3), BoxColor, BF
|
||||
COLOR FontColor, FontBackground
|
||||
_PRINTSTRING (tx1 + XOffset, ty1 + YOffset), Caption$
|
||||
COLOR dc&, bg&
|
||||
END SUB
|
||||
354
Task/2048/QBasic/2048.basic
Normal file
354
Task/2048/QBasic/2048.basic
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
SCREEN 13
|
||||
PALETTE 1, pColor(35, 33, 31)
|
||||
PALETTE 2, pColor(46, 46, 51)
|
||||
PALETTE 3, pColor(59, 56, 50)
|
||||
PALETTE 4, pColor(61, 44, 30)
|
||||
PALETTE 5, pColor(61, 37, 25)
|
||||
PALETTE 6, pColor(62, 31, 24)
|
||||
PALETTE 7, pColor(62, 24, 15)
|
||||
PALETTE 8, pColor(59, 52, 29)
|
||||
PALETTE 9, pColor(59, 51, 24)
|
||||
PALETTE 10, pColor(59, 50, 20)
|
||||
PALETTE 11, pColor(59, 49, 16)
|
||||
PALETTE 12, pColor(59, 49, 12)
|
||||
PALETTE 13, pColor(15, 15, 13)
|
||||
PALETTE 14, pColor(23, 22, 20)
|
||||
|
||||
DIM SHARED gDebug
|
||||
DIM SHARED gOriginX
|
||||
DIM SHARED gOriginY
|
||||
DIM SHARED gTextOriginX
|
||||
DIM SHARED gTextOriginY
|
||||
DIM SHARED gSquareSide
|
||||
DIM SHARED gGridSize
|
||||
|
||||
gGridSize = 4 ' grid size (4 -> 4x4)
|
||||
|
||||
DIM SHARED gGrid(gGridSize, gGridSize)
|
||||
DIM SHARED gScore
|
||||
|
||||
' Don't touch these numbers, seriously
|
||||
|
||||
gOriginX = 75 'pixel X of top left of grid
|
||||
gOriginY = 12 'pixel Y of top right of grid
|
||||
gTextOriginX = 11
|
||||
gTextOriginY = 3
|
||||
gSquareSide = 38 'width/height of block in pixels
|
||||
|
||||
|
||||
'set up all the things!
|
||||
gDebug = 0
|
||||
|
||||
RANDOMIZE TIMER
|
||||
CLS
|
||||
|
||||
start:
|
||||
initGrid
|
||||
initGraphicGrid
|
||||
renderGrid
|
||||
updateScore
|
||||
|
||||
gScore = 0
|
||||
|
||||
LOCATE 23, 1
|
||||
PRINT "Move with arrow keys. (R)estart, (Q)uit"
|
||||
|
||||
' keyboard input loop
|
||||
DO
|
||||
DO
|
||||
k$ = INKEY$
|
||||
LOOP UNTIL k$ <> ""
|
||||
|
||||
SELECT CASE k$
|
||||
CASE CHR$(0) + CHR$(72) 'up
|
||||
processMove ("u")
|
||||
CASE CHR$(0) + CHR$(80) 'down
|
||||
processMove ("d")
|
||||
CASE CHR$(0) + CHR$(77) 'right
|
||||
processMove ("r")
|
||||
CASE CHR$(0) + CHR$(75) 'left
|
||||
processMove ("l")
|
||||
CASE CHR$(27) 'escape
|
||||
GOTO programEnd
|
||||
CASE "q"
|
||||
GOTO programEnd
|
||||
CASE "Q"
|
||||
GOTO programEnd
|
||||
CASE "r"
|
||||
GOTO start
|
||||
CASE "R"
|
||||
GOTO start
|
||||
END SELECT
|
||||
LOOP
|
||||
|
||||
programEnd:
|
||||
|
||||
SUB addblock
|
||||
DIM emptyCells(gGridSize * gGridSize, 2)
|
||||
emptyCellCount = 0
|
||||
|
||||
FOR x = 0 TO gGridSize - 1
|
||||
FOR y = 0 TO gGridSize - 1
|
||||
IF gGrid(x, y) = 0 THEN
|
||||
emptyCells(emptyCellCount, 0) = x
|
||||
emptyCells(emptyCellCount, 1) = y
|
||||
emptyCellCount = emptyCellCount + 1
|
||||
END IF
|
||||
NEXT y
|
||||
NEXT x
|
||||
|
||||
IF emptyCellCount > 0 THEN
|
||||
index = INT(RND * emptyCellCount)
|
||||
num = CINT(RND + 1) * 2
|
||||
gGrid(emptyCells(index, 0), emptyCells(index, 1)) = num
|
||||
END IF
|
||||
|
||||
END SUB
|
||||
|
||||
SUB drawNumber (num, xPos, yPos)
|
||||
SELECT CASE num
|
||||
CASE 0: c = 16
|
||||
CASE 2: c = 2
|
||||
CASE 4: c = 3
|
||||
CASE 8: c = 4
|
||||
CASE 16: c = 5
|
||||
CASE 32: c = 6
|
||||
CASE 64: c = 7
|
||||
CASE 128: c = 8
|
||||
CASE 256: c = 9
|
||||
CASE 512: c = 10
|
||||
CASE 1024: c = 11
|
||||
CASE 2048: c = 12
|
||||
CASE 4096: c = 13
|
||||
CASE 8192: c = 13
|
||||
CASE ELSE: c = 13
|
||||
END SELECT
|
||||
|
||||
x = xPos * (gSquareSide + 2) + gOriginX + 1
|
||||
y = yPos * (gSquareSide + 2) + gOriginY + 1
|
||||
LINE (x + 1, y + 1)-(x + gSquareSide - 1, y + gSquareSide - 1), c, BF
|
||||
|
||||
IF num > 0 THEN
|
||||
LOCATE gTextOriginY + 1 + (yPos * 5), gTextOriginX + (xPos * 5)
|
||||
PRINT " "
|
||||
LOCATE gTextOriginY + 2 + (yPos * 5), gTextOriginX + (xPos * 5)
|
||||
PRINT pad$(num)
|
||||
LOCATE gTextOriginY + 3 + (yPos * 5), gTextOriginX + (xPos * 5)
|
||||
'PRINT " "
|
||||
END IF
|
||||
|
||||
END SUB
|
||||
|
||||
FUNCTION getAdjacentCell (x, y, d AS STRING)
|
||||
|
||||
IF (d = "l" AND x = 0) OR (d = "r" AND x = gGridSize - 1) OR (d = "u" AND y = 0) OR (d = "d" AND y = gGridSize - 1) THEN
|
||||
getAdjacentCell = -1
|
||||
ELSE
|
||||
SELECT CASE d
|
||||
CASE "l": getAdjacentCell = gGrid(x - 1, y)
|
||||
CASE "r": getAdjacentCell = gGrid(x + 1, y)
|
||||
|
||||
CASE "u": getAdjacentCell = gGrid(x, y - 1)
|
||||
CASE "d": getAdjacentCell = gGrid(x, y + 1)
|
||||
END SELECT
|
||||
END IF
|
||||
|
||||
END FUNCTION
|
||||
|
||||
'Draws the outside grid (doesn't render tiles)
|
||||
SUB initGraphicGrid
|
||||
|
||||
gridSide = (gSquareSide + 2) * gGridSize
|
||||
|
||||
LINE (gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 14, BF 'outer square, 3 thick
|
||||
LINE (gOriginX, gOriginY)-(gOriginX + gridSide, gOriginY + gridSide), 1, B 'outer square, 3 thick
|
||||
LINE (gOriginX - 1, gOriginY - 1)-(gOriginX + gridSide + 1, gOriginY + gridSide + 1), 1, B
|
||||
LINE (gOriginX - 2, gOriginY - 2)-(gOriginX + gridSide + 2, gOriginY + gridSide + 2), 1, B
|
||||
|
||||
FOR x = gOriginX + gSquareSide + 2 TO gOriginX + (gSquareSide + 2) * gGridSize STEP gSquareSide + 2 ' horizontal lines
|
||||
LINE (x, gOriginY)-(x, gOriginY + gridSide), 1
|
||||
NEXT x
|
||||
|
||||
FOR y = gOriginY + gSquareSide + 2 TO gOriginY + (gSquareSide + 2) * gGridSize STEP gSquareSide + 2 ' vertical lines
|
||||
LINE (gOriginX, y)-(gOriginX + gridSide, y), 1
|
||||
NEXT y
|
||||
|
||||
END SUB
|
||||
|
||||
'Init the (data) grid with 0s
|
||||
SUB initGrid
|
||||
FOR x = 0 TO 3
|
||||
FOR y = 0 TO 3
|
||||
gGrid(x, y) = 0
|
||||
NEXT y
|
||||
NEXT x
|
||||
|
||||
addblock
|
||||
addblock
|
||||
|
||||
END SUB
|
||||
|
||||
SUB moveBlock (sourceX, sourceY, targetX, targetY, merge)
|
||||
|
||||
IF sourceX < 0 OR sourceX >= gGridSize OR sourceY < 0 OR sourceY >= gGridSize AND gDebug = 1 THEN
|
||||
LOCATE 0, 0
|
||||
PRINT "moveBlock: source coords out of bounds"
|
||||
END IF
|
||||
|
||||
IF targetX < 0 OR targetX >= gGridSize OR targetY < 0 OR targetY >= gGridSize AND gDebug = 1 THEN
|
||||
LOCATE 0, 0
|
||||
PRINT "moveBlock: source coords out of bounds"
|
||||
END IF
|
||||
|
||||
sourceSquareValue = gGrid(sourceX, sourceY)
|
||||
targetSquareValue = gGrid(targetX, targetY)
|
||||
|
||||
IF merge = 1 THEN
|
||||
|
||||
IF sourceSquareValue = targetSquareValue THEN
|
||||
gGrid(sourceX, sourceY) = 0
|
||||
gGrid(targetX, targetY) = targetSquareValue * 2
|
||||
gScore = gScore + targetSquareValue * 2 ' Points!
|
||||
ELSEIF gDebug = 1 THEN
|
||||
LOCATE 0, 0
|
||||
PRINT "moveBlock: Attempted to merge unequal sqs"
|
||||
END IF
|
||||
|
||||
ELSE
|
||||
|
||||
IF targetSquareValue = 0 THEN
|
||||
gGrid(sourceX, sourceY) = 0
|
||||
gGrid(targetX, targetY) = sourceSquareValue
|
||||
ELSEIF gDebug = 1 THEN
|
||||
LOCATE 0, 0
|
||||
PRINT "moveBlock: Attempted to move to non-empty block"
|
||||
END IF
|
||||
|
||||
END IF
|
||||
|
||||
END SUB
|
||||
|
||||
FUNCTION pad$ (num)
|
||||
strNum$ = LTRIM$(STR$(num))
|
||||
|
||||
SELECT CASE LEN(strNum$)
|
||||
CASE 1: pad = " " + strNum$ + " "
|
||||
CASE 2: pad = " " + strNum$ + " "
|
||||
CASE 3: pad = " " + strNum$
|
||||
CASE 4: pad = strNum$
|
||||
END SELECT
|
||||
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION pColor (r, g, b)
|
||||
pColor = (r + g * 256 + b * 65536)
|
||||
END FUNCTION
|
||||
|
||||
SUB processMove (dir AS STRING)
|
||||
' dir can be 'l', 'r', 'u', or 'd'
|
||||
|
||||
hasMoved = 0
|
||||
|
||||
IF dir = "l" THEN
|
||||
|
||||
FOR y = 0 TO gGridSize - 1
|
||||
wasMerge = 0
|
||||
FOR x = 0 TO gGridSize - 1
|
||||
GOSUB processBlock
|
||||
NEXT x
|
||||
NEXT y
|
||||
|
||||
ELSEIF dir = "r" THEN
|
||||
|
||||
FOR y = 0 TO gGridSize - 1
|
||||
wasMerge = 0
|
||||
FOR x = gGridSize - 1 TO 0 STEP -1
|
||||
GOSUB processBlock
|
||||
NEXT x
|
||||
NEXT y
|
||||
|
||||
ELSEIF dir = "u" THEN
|
||||
FOR x = 0 TO gGridSize - 1
|
||||
wasMerge = 0
|
||||
FOR y = 0 TO gGridSize - 1
|
||||
GOSUB processBlock
|
||||
NEXT y
|
||||
NEXT x
|
||||
|
||||
ELSEIF dir = "d" THEN
|
||||
FOR x = 0 TO gGridSize - 1
|
||||
wasMerge = 0
|
||||
FOR y = gGridSize - 1 TO 0 STEP -1
|
||||
GOSUB processBlock
|
||||
NEXT y
|
||||
NEXT x
|
||||
|
||||
END IF
|
||||
|
||||
GOTO processMoveEnd
|
||||
|
||||
moveToObstacle:
|
||||
curX = x
|
||||
curY = y
|
||||
|
||||
DO WHILE getAdjacentCell(curX, curY, dir) = 0
|
||||
SELECT CASE dir
|
||||
CASE "l": curX = curX - 1
|
||||
CASE "r": curX = curX + 1
|
||||
CASE "u": curY = curY - 1
|
||||
CASE "d": curY = curY + 1
|
||||
END SELECT
|
||||
LOOP
|
||||
RETURN
|
||||
|
||||
processBlock:
|
||||
|
||||
merge = 0
|
||||
IF gGrid(x, y) <> 0 THEN ' have block
|
||||
|
||||
GOSUB moveToObstacle ' figure out where it can be moved to
|
||||
IF getAdjacentCell(curX, curY, dir) = gGrid(x, y) AND wasMerge = 0 THEN ' obstacle can be merged with
|
||||
merge = 1
|
||||
wasMerge = 1
|
||||
ELSE
|
||||
wasMerge = 0
|
||||
END IF
|
||||
|
||||
IF curX <> x OR curY <> y OR merge = 1 THEN
|
||||
mergeDirX = 0
|
||||
mergeDirY = 0
|
||||
IF merge = 1 THEN
|
||||
SELECT CASE dir
|
||||
CASE "l": mergeDirX = -1
|
||||
CASE "r": mergeDirX = 1
|
||||
CASE "u": mergeDirY = -1
|
||||
CASE "d": mergeDirY = 1
|
||||
END SELECT
|
||||
END IF
|
||||
|
||||
CALL moveBlock(x, y, curX + mergeDirX, curY + mergeDirY, merge) ' move to before obstacle or merge
|
||||
hasMoved = 1
|
||||
END IF
|
||||
END IF
|
||||
RETURN
|
||||
|
||||
processMoveEnd:
|
||||
|
||||
IF hasMoved = 1 THEN addblock
|
||||
renderGrid
|
||||
updateScore
|
||||
|
||||
END SUB
|
||||
|
||||
SUB renderGrid
|
||||
FOR x = 0 TO gGridSize - 1
|
||||
FOR y = 0 TO gGridSize - 1
|
||||
CALL drawNumber(gGrid(x, y), x, y)
|
||||
NEXT y
|
||||
NEXT x
|
||||
END SUB
|
||||
|
||||
SUB updateScore
|
||||
LOCATE 1, 10
|
||||
PRINT "Score:" + STR$(gScore)
|
||||
END SUB
|
||||
162
Task/2048/R/2048.r
Normal file
162
Task/2048/R/2048.r
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
GD <- function(vec) {
|
||||
c(vec[vec != 0], vec[vec == 0])
|
||||
}
|
||||
DG <- function(vec) {
|
||||
c(vec[vec == 0], vec[vec != 0])
|
||||
}
|
||||
|
||||
DG_ <- function(vec, v = TRUE) {
|
||||
if (v)
|
||||
print(vec)
|
||||
rev(GD_(rev(vec), v = FALSE))
|
||||
}
|
||||
|
||||
GD_ <- function(vec, v = TRUE) {
|
||||
if (v) {
|
||||
print(vec)
|
||||
}
|
||||
vec2 <- GD(vec)
|
||||
# on cherche les 2 cote a cote
|
||||
pos <- which(vec2 == c(vec2[-1], 9999))
|
||||
# put pas y avoir consécutif dans pos
|
||||
pos[-1][which(abs(pos - c(pos[-1], 999)) == 1)]
|
||||
av <- which(c(0, c(pos[-1], 9) - pos) == 1)
|
||||
if (length(av) > 0) {
|
||||
pos <- pos[-av]
|
||||
}
|
||||
vec2[pos] <- vec2[pos] + vec2[pos + 1]
|
||||
vec2[pos + 1] <- 0
|
||||
GD(vec2)
|
||||
|
||||
}
|
||||
|
||||
H_ <- function(base) {
|
||||
apply(base, MARGIN = 2, FUN = GD_, v = FALSE)
|
||||
}
|
||||
B_ <- function(base) {
|
||||
apply(base, MARGIN = 2, FUN = DG_, v = FALSE)
|
||||
}
|
||||
G_ <- function(base) {
|
||||
t(apply(base, MARGIN = 1, FUN = GD_, v = FALSE))
|
||||
}
|
||||
D_ <- function(base) {
|
||||
t(apply(base, MARGIN = 1, FUN = DG_, v = FALSE))
|
||||
}
|
||||
|
||||
H <- function(base) {
|
||||
apply(base, MARGIN = 2, FUN = GD, v = FALSE)
|
||||
}
|
||||
B <- function(base) {
|
||||
apply(base, MARGIN = 2, FUN = DG, v = FALSE)
|
||||
}
|
||||
G <- function(base) {
|
||||
t(apply(base, MARGIN = 1, FUN = GD, v = FALSE))
|
||||
}
|
||||
D <- function(base) {
|
||||
t(apply(base, MARGIN = 1, FUN = DG, v = FALSE))
|
||||
}
|
||||
|
||||
add2or4 <- function(base, p = 0.9) {
|
||||
lw <- which(base == 0)
|
||||
if (length(lw) > 1) {
|
||||
tirage <- sample(lw, 1)
|
||||
} else {
|
||||
tirage <- lw
|
||||
}
|
||||
base[tirage] <- sample(c(2, 4), 1, prob = c(p, 1 - p))
|
||||
base
|
||||
}
|
||||
print.dqh <- function(base) {
|
||||
cat("\n\n")
|
||||
for (i in 1:nrow(base)) {
|
||||
cat(paste(" ", base[i, ], " "))
|
||||
cat("\n")
|
||||
}
|
||||
cat("\n")
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
#' @encoding UTF-8
|
||||
#' @title run_2048
|
||||
#' @description The 2048 game
|
||||
#' @param nrow nomber of row
|
||||
#' @param ncol numver of col
|
||||
#' @param p probability to obtain a 2 (1-p) is the probability to obtain a 4
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' run_2048()
|
||||
#' }
|
||||
#' @export
|
||||
|
||||
|
||||
run_2048 <- function(nrow, ncol, p = 0.9) {
|
||||
|
||||
|
||||
|
||||
help <- function() {
|
||||
cat(" *** KEY BINDING *** \n\n")
|
||||
cat("press ECHAP to quit\n\n")
|
||||
cat("choose moove E (up) ; D (down) ; S (left); F (right) \n")
|
||||
cat("choose moove 8 (up) ; 2 (down) ; 4 (left); 6 (right) \n")
|
||||
cat("choose moove I (up) ; K (down) ; J (left); L (right) \n\n\n")
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (missing(nrow) & missing(ncol)) {
|
||||
nrow <- ncol <- 4
|
||||
}
|
||||
if (missing(nrow)) {
|
||||
nrow <- ncol
|
||||
}
|
||||
if (missing(ncol)) {
|
||||
ncol <- nrow
|
||||
}
|
||||
|
||||
base <- matrix(0, nrow = nrow, ncol = ncol)
|
||||
|
||||
while (length(which(base == 2048)) == 0) {
|
||||
base <- add2or4(base, p = p)
|
||||
# print(base)
|
||||
|
||||
class(base) <- "dqh"
|
||||
print(base)
|
||||
flag <- sum((base == rbind(base[-1, ], 0)) + (base == rbind(0,
|
||||
base[-nrow(base), ])) + (base == cbind(base[, -1], 0)) + (base ==
|
||||
cbind(0, base[, -nrow(base)])))
|
||||
if (flag == 0) {
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
y <- character(0)
|
||||
while (length(y) == 0) {
|
||||
cat("\n", "choose moove E (up) ; D (down) ; s (left); f (right) OR H for help",
|
||||
"\n") # prompt
|
||||
y <- scan(n = 1, what = "character")
|
||||
}
|
||||
|
||||
|
||||
baseSAVE <- base
|
||||
base <- switch(EXPR = y, E = H_(base), D = B_(base), S = G_(base),
|
||||
F = D_(base), e = H_(base), d = B_(base), s = G_(base), f = D_(base),
|
||||
`8` = H_(base), `2` = B_(base), `4` = G_(base), `6` = D_(base),
|
||||
H = help(), h = help(), i = H_(base), k = B_(base), j = G_(base),
|
||||
l = D_(base), I = H_(base), K = B_(base), J = G_(base), L = D_(base))
|
||||
if (is.null(base)) {
|
||||
cat(" wrong KEY \n")
|
||||
base <- baseSAVE
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (sum(base >= 2048) > 1) {
|
||||
cat("YOU WIN ! \n")
|
||||
} else {
|
||||
cat("YOU LOOSE \n")
|
||||
}
|
||||
}
|
||||
90
Task/2048/REXX/2048.rexx
Normal file
90
Task/2048/REXX/2048.rexx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/*REXX program lets a user play the 2048 game on an NxN grid (default is 4x4 grid).*/
|
||||
parse arg N win seed . /*obtain optional arguments from the CL*/
|
||||
if N=='' | N=="," then N= 4 /*Not specified? Then use the default.*/
|
||||
if win=='' | win=="," then win= 2**11 /* " " " " " " */
|
||||
if datatype(seed, 'W') then call random ,,seed /*Specified? Then use seed for RANDOM.*/
|
||||
L= length(win) + 2 /*L: used for displaying the grid #'s.*/
|
||||
eye=copies("─", 8); pad=left('', length(eye)+2) /*eye catchers; and perusable perusing.*/
|
||||
b= ' ' /*comfortable readable name for a blank*/
|
||||
@cls= 'CLS' /*hardcoded command to clear the screen*/
|
||||
prompt= eye "Please enter a direction (Up, Down, Right, Left) ───or─── Quit:"
|
||||
move= 1; moves= 0; score= 0; ok= 1 /*simulation that a move was performed.*/
|
||||
@.= b /*define all grid elements to a blank. */
|
||||
do until any(win); if ok then call put; ok= 1; say; call showGrid
|
||||
say; say prompt; parse pull a x . 1 d 2 1 way xx /*show prompt; obtain answer.*/
|
||||
if datatype(a, 'U') then @cls /*if uppercase, then clear the screen. */
|
||||
if a=='' then do; ok= 0 /*the user entered blank(s) or nothing.*/
|
||||
say copies(eye, 5) 'moves:' moves eye "score:" score
|
||||
iterate /* [↑] display # of moves & the score.*/
|
||||
end
|
||||
upper d a x /*uppercase contents of three variables*/
|
||||
if x\=='' then call err "too many arguments entered: " xx
|
||||
if abbrev('QUIT',a,1) then do; say; say eye "quitting the game".; exit 1; end
|
||||
good=abbrev('UP',a,1) | abbrev("DOWN",a,1) | abbrev('RIGHT',a,1) | abbrev("LEFT",a,1)
|
||||
if \good then call err "invalid direction: " way
|
||||
if \ok then iterate; moves= moves + 1; call mov
|
||||
end /*until*/
|
||||
say
|
||||
say translate(eye "Congrats!! You've won the" win 'game!' eye,"═",'─') "score:" score
|
||||
exit 0 /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
@: procedure expose @.; parse arg row,col; return @.row.col
|
||||
any: arg ?; do r=1 for N; do c=1 for N; if @.r.c==? then return 1; end; end; return 0
|
||||
err: say; say eye '***error*** ' arg(1); say; ok=0; return
|
||||
o_c: $=; do k=1 for N; $=$ word(@.k.c .,1); end; !=space(translate($,,.))==''; return $
|
||||
o_r: $=; do k=1 for N; $=$ word(@.r.k .,1); end; !=space(translate($,,.))==''; return $
|
||||
put: if \any(b) then call err ,"game over, no more moves."; if move then call two; return
|
||||
row: if r==0 | r>N then return copies('═', L); return center(@.r.c, L)
|
||||
ten: if random(9)==4 then return 4; return 2 /*10% of the time, use 4 instead of 2.*/
|
||||
two: do until @.p.q==b; p= random(1,N); q= random(1,N); end; @.p.q= ten(); return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
showGrid: do r=0 for N+2; _= '║'; __= "╠"
|
||||
do c=1 for N; _= _ || row()'║'; __= __ || copies("═", L)'╬'
|
||||
end /*c*/
|
||||
if r==0 then _= '╔'translate( substr(_, 2, length(_) - 2), "╦", '║')"╗"
|
||||
if r >N then _= '╚'translate( substr(_, 2, length(_) - 2), "╩", '║')"╝"
|
||||
say pad _
|
||||
if r<N & r>0 then say pad substr(__, 1, length(__) - 1)"╣"
|
||||
end /*r*/; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
mov: move= 0; if d=='R' then call moveLR N, 1, -1 /*move (slide) numbers ► */
|
||||
if d=='L' then call moveLR 1, N, +1 /* " " " ◄ */
|
||||
if d=='U' then call moveUD 1, N, +1 /* " " " ↑ */
|
||||
if d=='D' then call moveUD N, 1, -1 /* " " " ↓ */
|
||||
if \move then call err 'moving ' way " doesn't change anything."; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
moveLR: parse arg start, sTo, # /*slide ◄ or ► */
|
||||
do r=1 for N; old= o_r(); if ! then iterate /*is this row blank? */
|
||||
do N-1; call packLR /*pack ◄ or ► */
|
||||
end /*N-1*/ /* [↓] get new tiles.*/
|
||||
new= o_r(); move= move | (old\==new) /*indicate tiles moved*/
|
||||
do c=start for N-1 by # while @.r.c\==b /*slide ◄ or ► */
|
||||
if @.r.c\==@(r,c+#) then iterate /*not a duplicate ? */
|
||||
@.r.c= @.r.c * 2; score= score + @.r.c /*double; bump score */
|
||||
c= c + # ; @.r.c= b; move= 1 /*bump C; blank dup 2.*/
|
||||
end /*c*/ /* [↑] indicate move.*/
|
||||
call packLR /*pack ◄ or ► */
|
||||
end /*r*/; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
moveUD: parse arg start, Sto, # /*slide ↑ or ↓ */
|
||||
do c=1 for N; old= o_c(); if ! then iterate /*is this col blank? */
|
||||
do N-1; call packUD /*pack up or down. */
|
||||
end /*N-1*/ /* [↓] get new tiles.*/
|
||||
new= o_c(); move= move | (old\==new) /*indicate tiles moved*/
|
||||
do r=start for N-1 by # while @.r.c\==b /*slide ↑ or ↓ */
|
||||
if @.r.c\==@(r+#,c) then iterate /*not a duplicate ? */
|
||||
@.r.c= @.r.c * 2; score= score + @.r.c /*double; bump score */
|
||||
r= r + # ; @.r.c= b; move= 1 /*bump R; blank dup 2.*/
|
||||
end /*r*/ /* [↑] indicate move.*/
|
||||
call packUD /*pack ↑ or ↓ */
|
||||
end /*c*/; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
packLR: do c=start for N-1 by #; if @.r.c\==b then iterate /*Not a blank? Skip. */
|
||||
do s=c to sTo by #; @.r.s= @(r, s + #) /*slide ◄ or ► */
|
||||
end /*s*/; @.r.sTo= b /*handle the last one.*/
|
||||
end /*c*/; return
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
packUD: do r=start for N-1 by #; if @.r.c\==b then iterate /*Not a blank? Skip. */
|
||||
do s=r to sTo by #; @.s.c= @(s + #, c) /*slide ↑ or ↓ */
|
||||
end /*s*/; @.sTo.c= b /*handle the last one.*/
|
||||
end /*r*/; return
|
||||
804
Task/2048/Racket/2048.rkt
Normal file
804
Task/2048/Racket/2048.rkt
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
;; LICENSE: See License file LICENSE (MIT license)
|
||||
;;
|
||||
;; Repository: https://github.com/danprager/2048
|
||||
;;
|
||||
;; Copyright 2014: Daniel Prager
|
||||
;; daniel.a.prager@gmail.com
|
||||
;;
|
||||
;; This is a largely clean-room, functional implementation in Racket
|
||||
;; of the game 2048 by Gabriele Cirulli, based on 1024 by Veewo Studio,
|
||||
;; and conceptually similar to Threes by Asher Vollmer.
|
||||
;;
|
||||
;;
|
||||
;; HOW TO PLAY:
|
||||
;; * Use your arrow keys to slide the tiles.
|
||||
;; * When two tiles with the same number touch, they merge into one!
|
||||
;; * Press <space> to rotate the board.
|
||||
;;
|
||||
|
||||
#lang racket
|
||||
|
||||
(require rackunit
|
||||
2htdp/image
|
||||
(rename-in 2htdp/universe
|
||||
[left left-arrow]
|
||||
[right right-arrow]
|
||||
[up up-arrow]
|
||||
[down down-arrow]))
|
||||
|
||||
|
||||
(define *side* 4) ; Side-length of the grid
|
||||
(define *time-limit* #f) ; Use #f for no time limit, or number of seconds
|
||||
|
||||
(define *amber-alert* 60) ; Time indicator goes orange when less than this number of seconds remaining
|
||||
(define *red-alert* 10) ; Time indicator goes red when less than this number of seconds remaining
|
||||
|
||||
(define *tile-that-wins* 2048) ; You win when you get a tile = this number
|
||||
(define *magnification* 2) ; Scales the game board
|
||||
|
||||
(define (set-side! n)
|
||||
(set! *side* n))
|
||||
|
||||
;;
|
||||
;; Numbers can be displayed with substiture text. Just edit this table...
|
||||
;;
|
||||
(define *text*
|
||||
'((0 "")
|
||||
(2 "2")))
|
||||
|
||||
;; Color scheme
|
||||
;;
|
||||
;; From https://github.com/gabrielecirulli/2048/blob/master/style/main.css
|
||||
;;
|
||||
(define *grid-color* (color #xbb #xad #xa0))
|
||||
|
||||
(define *default-tile-bg-color* (color #x3c #x3a #x32))
|
||||
(define *default-tile-fg-color* 'white)
|
||||
|
||||
(define *tile-bg-colors*
|
||||
(map (lambda (x)
|
||||
(match-define (list n r g b) x)
|
||||
(list n (color r g b)))
|
||||
'((0 #xcc #xc0 #xb3)
|
||||
(2 #xee #xe4 #xda)
|
||||
(4 #xed #xe0 #xc8)
|
||||
(8 #xf2 #xb1 #x79)
|
||||
(16 #xf5 #x95 #x63)
|
||||
(32 #xf6 #x7c #x5f)
|
||||
(64 #xf6 #x5e #x3b)
|
||||
(128 #xed #xcf #x72)
|
||||
(256 #xed #xcc #x61)
|
||||
(512 #xed #xc8 #x50)
|
||||
(1024 #xed #xc5 #x3f)
|
||||
(2048 #xed #xc2 #x2e))))
|
||||
|
||||
(define *tile-fg-colors*
|
||||
'((0 dimgray)
|
||||
(2 dimgray)
|
||||
(4 dimgray)
|
||||
(8 white)
|
||||
(16 white)
|
||||
(32 white)
|
||||
(64 white)
|
||||
(128 white)
|
||||
(256 white)
|
||||
(512 white)
|
||||
(1024 white)
|
||||
(2048 white)))
|
||||
|
||||
;;--------------------------------------------------------------------
|
||||
;; Rows may be represented as lists, with 0s representing empty spots.
|
||||
;;
|
||||
|
||||
(define (nonzero? x) (not (zero? x)))
|
||||
|
||||
;; Append padding to lst to make it n items long
|
||||
;;
|
||||
(define (pad-right lst padding n)
|
||||
(append lst (make-list (- n (length lst)) padding)))
|
||||
|
||||
;; Slide items towards the head of the list, doubling adjacent pairs
|
||||
;; when no item is a 0.
|
||||
;;
|
||||
;; E.g. (combine '(2 2 2 4 4)) -> '(4 2 8)
|
||||
;;
|
||||
(define (combine lst)
|
||||
(cond [(<= (length lst) 1) lst]
|
||||
[(= (first lst) (second lst))
|
||||
(cons (* 2 (first lst)) (combine (drop lst 2)))]
|
||||
[else (cons (first lst) (combine (rest lst)))]))
|
||||
|
||||
;; Total of new elements introduced by combining.
|
||||
;;
|
||||
;; E.g. (combine-total '(2 2 2 4 4)) -> 4 + 8 = 12
|
||||
;;
|
||||
(define (combine-total lst)
|
||||
(cond [(<= (length lst) 1) 0]
|
||||
[(= (first lst) (second lst))
|
||||
(+ (* 2 (first lst)) (combine-total (drop lst 2)))]
|
||||
[else (combine-total (rest lst))]))
|
||||
|
||||
;; Slide towards the head of the list, doubling pairs, 0 are
|
||||
;; allowed (and slid through), and length is preserved by
|
||||
;; padding with 0s.
|
||||
;;
|
||||
;; E.g. (slide-left '(2 2 2 0 4 4)) -> '(4 2 8 0 0 0)
|
||||
;;
|
||||
(define (slide-left row)
|
||||
(pad-right (combine (filter nonzero? row)) 0 (length row)))
|
||||
|
||||
;; Slide towards the tail of the list:
|
||||
;;
|
||||
;; E.g. (slide-right '(2 2 0 0 4 4)) -> '(0 0 0 0 0 4 8)
|
||||
;;
|
||||
(define (slide-right row) (reverse (slide-left (reverse row))))
|
||||
|
||||
|
||||
;;--------------------------------------------------------------------
|
||||
;; We use a sparse representation for transitions in a row.
|
||||
;;
|
||||
;; Moves take the form '(value initial-position final-position)
|
||||
;;
|
||||
(define (moves-row-left row [last #f] [i 0] [j -1])
|
||||
(if (null? row)
|
||||
null
|
||||
(let ([head (first row)])
|
||||
(cond [(zero? head) (moves-row-left (rest row) last (add1 i) j)]
|
||||
[(equal? last head)
|
||||
(cons (list head i j)
|
||||
(moves-row-left (rest row) #f (add1 i) j))]
|
||||
[else (cons (list head i (add1 j))
|
||||
(moves-row-left (rest row) head (add1 i) (add1 j)))]))))
|
||||
|
||||
;; Convert a row into the sparse representaiton without any sliding.
|
||||
;;
|
||||
;; E.g. (moves-row-none '(0 2 0 4)) -> '((2 1 1) (4 3 3))
|
||||
;;
|
||||
(define (moves-row-none row)
|
||||
(for/list ([value row]
|
||||
[i (in-naturals)]
|
||||
#:when (nonzero? value))
|
||||
(list value i i)))
|
||||
|
||||
;; Reverse all moves so that:
|
||||
;;
|
||||
;; '(value initial final) -> '(value (- n initial 1) (- n final 1)
|
||||
;;
|
||||
(define (reverse-moves moves n)
|
||||
(define (flip i) (- n i 1))
|
||||
(map (λ (m)
|
||||
(match-define (list a b c) m)
|
||||
(list a (flip b) (flip c)))
|
||||
moves))
|
||||
|
||||
(define (transpose-moves moves)
|
||||
(for/list ([m moves])
|
||||
(match-define (list v (list a b) (list c d)) m)
|
||||
(list v (list b a) (list d c))))
|
||||
|
||||
(define (moves-row-right row [n *side*])
|
||||
(reverse-moves (moves-row-left (reverse row)) n))
|
||||
|
||||
;;--------------------------------------------------------------------
|
||||
;; Lift the sparse representation for transitions
|
||||
;; up to two dimensions...
|
||||
;;
|
||||
;; '(value initial final) -> '(value (x initial) (x final))
|
||||
;;
|
||||
(define (add-row-coord i rows)
|
||||
(for/list ([r rows])
|
||||
(match-define (list a b c) r)
|
||||
(list a (list i b) (list i c))))
|
||||
|
||||
(define (transpose lsts)
|
||||
(apply map list lsts))
|
||||
|
||||
;; Slide the entire grid in the specified direction
|
||||
;;
|
||||
(define (left grid)
|
||||
(map slide-left grid))
|
||||
|
||||
(define (right grid)
|
||||
(map slide-right grid))
|
||||
|
||||
(define (up grid)
|
||||
((compose transpose left transpose) grid))
|
||||
|
||||
(define (down grid)
|
||||
((compose transpose right transpose) grid))
|
||||
|
||||
;; Calculate the change to score from sliding the grid left or right.
|
||||
;;
|
||||
(define (score-increment grid)
|
||||
(apply + (map (λ (row)
|
||||
(combine-total (filter nonzero? row)))
|
||||
grid)))
|
||||
|
||||
;; Slide the grid in the specified direction and
|
||||
;; determine the transitions of the tiles.
|
||||
;;
|
||||
;; We'll use these operations to animate the sliding of the tiles.
|
||||
;;
|
||||
(define (moves-grid-action grid action)
|
||||
(let ([n (length (first grid))])
|
||||
(apply append
|
||||
(for/list ([row grid]
|
||||
[i (in-range n)])
|
||||
(add-row-coord i (action row))))))
|
||||
|
||||
(define (moves-grid-left grid)
|
||||
(moves-grid-action grid moves-row-left))
|
||||
|
||||
(define (moves-grid-right grid)
|
||||
(moves-grid-action grid moves-row-right))
|
||||
|
||||
(define (moves-grid-up grid)
|
||||
((compose transpose-moves moves-grid-left transpose) grid))
|
||||
|
||||
(define (moves-grid-down grid)
|
||||
((compose transpose-moves moves-grid-right transpose) grid))
|
||||
|
||||
;; Rotating the entire grid doesn't involve sliding.
|
||||
;; It's a convenience to allow the player to view the grid from a different
|
||||
;; orientation.
|
||||
(define (moves-grid-rotate grid)
|
||||
(let ([n (length (first grid))])
|
||||
(for/list ([item (moves-grid-action grid moves-row-none)])
|
||||
(match-define (list v (list i j) _) item)
|
||||
(list v (list i j) (list j (- n i 1))))))
|
||||
|
||||
;; Chop a list into a list of sub-lists of length n. Used to move from
|
||||
;; a flat representation of the grid into a list of rows.
|
||||
;;
|
||||
;;
|
||||
(define (chop lst [n *side*])
|
||||
(if (<= (length lst) n)
|
||||
(list lst)
|
||||
(cons (take lst n) (chop (drop lst n) n))))
|
||||
|
||||
;; The next few functions are used to determine where to place a new
|
||||
;; number in the grid...
|
||||
;;
|
||||
|
||||
;; How many zeros in the current state?
|
||||
;;
|
||||
(define (count-zeros state)
|
||||
(length (filter zero? state)))
|
||||
|
||||
;; What is the absolute index of the nth zero in lst?
|
||||
;;
|
||||
;; E.g. (index-of-nth-zero '(0 2 0 4) 1 2)) 1) -> 2
|
||||
;;
|
||||
(define (index-of-nth-zero lst n)
|
||||
(cond [(null? lst) #f]
|
||||
[(zero? (first lst))
|
||||
(if (zero? n)
|
||||
0
|
||||
(add1 (index-of-nth-zero (rest lst) (sub1 n))))]
|
||||
[else (add1 (index-of-nth-zero (rest lst) n))]))
|
||||
|
||||
;; Place the nth zero in the lst with val.
|
||||
;;
|
||||
;; E.g. (replace-nth-zero '(0 2 0 4) 1 2)) -> '(0 2 2 4)
|
||||
;;
|
||||
(define (replace-nth-zero lst n val)
|
||||
(let ([i (index-of-nth-zero lst n)])
|
||||
(append (take lst i) (cons val (drop lst (add1 i))))))
|
||||
|
||||
;; There's a 90% chance that a new tile will be a two; 10% a four.
|
||||
;;
|
||||
(define (new-tile)
|
||||
(if (> (random) 0.9) 4 2))
|
||||
|
||||
;; Create a random initial game-board with two non-zeros (2 or 4)
|
||||
;; and the rest 0s.
|
||||
;;
|
||||
;; E.g. '(0 0 0 0
|
||||
;; 0 2 0 0
|
||||
;; 2 0 0 0
|
||||
;; 0 0 0 0)
|
||||
;;
|
||||
(define (initial-state [side *side*])
|
||||
(shuffle (append (list (new-tile) (new-tile))
|
||||
(make-list (- (sqr side) 2) 0))))
|
||||
|
||||
;; The game finishes when no matter which way you slide, the board doesn't
|
||||
;; change.
|
||||
;;
|
||||
(define (finished? state [n *side*])
|
||||
(let ([grid (chop state n)])
|
||||
(for/and ([op (list left right up down)])
|
||||
(equal? grid (op grid)))))
|
||||
|
||||
;;--------------------------------------------------------------------
|
||||
;; Graphics
|
||||
;;
|
||||
(define *text-size* 30)
|
||||
(define *max-text-width* 40)
|
||||
(define *tile-side* 50)
|
||||
(define *grid-spacing* 5)
|
||||
(define *grid-side* (+ (* *side* *tile-side*)
|
||||
(* (add1 *side*) *grid-spacing*)))
|
||||
|
||||
;; Memoization - caching images takes the strain off the gc
|
||||
;;
|
||||
(define-syntax define-memoized
|
||||
(syntax-rules ()
|
||||
[(_ (f args ...) bodies ...)
|
||||
(define f
|
||||
(let ([results (make-hash)])
|
||||
(lambda (args ...)
|
||||
((λ vals
|
||||
(when (not (hash-has-key? results vals))
|
||||
(hash-set! results vals (begin bodies ...)))
|
||||
(hash-ref results vals))
|
||||
args ...))))]))
|
||||
|
||||
;; Look-up the (i,j)th element in the flat representation.
|
||||
;;
|
||||
(define (square/ij state i j)
|
||||
(list-ref state (+ (* *side* i) j)))
|
||||
|
||||
;; Linear interpolation between a and b:
|
||||
;;
|
||||
;; (interpolate 0.0 a b) -> a
|
||||
;; (interpolate 1.0 a b) -> b
|
||||
;;
|
||||
(define (interpolate k a b)
|
||||
(+ (* (- 1 k) a)
|
||||
(* k b)))
|
||||
|
||||
;; Key value lookup with default return - is there an out-of-the-box function
|
||||
;; for this?
|
||||
;;
|
||||
(define (lookup key lst default)
|
||||
(let ([value (assoc key lst)])
|
||||
(if value (second value) default)))
|
||||
|
||||
|
||||
;; Make a tile without a number on it in the appropriate color.
|
||||
;;
|
||||
(define (plain-tile n)
|
||||
(square *tile-side*
|
||||
'solid
|
||||
(lookup n *tile-bg-colors* *default-tile-bg-color*)))
|
||||
|
||||
;; Make text for a tile
|
||||
;;
|
||||
(define (tile-text n)
|
||||
(let* ([t (text (lookup n *text* (number->string n))
|
||||
*text-size*
|
||||
(lookup n *tile-fg-colors* *default-tile-fg-color*))]
|
||||
[side (max (image-width t) (image-height t))])
|
||||
(scale (if (> side *max-text-width*) (/ *max-text-width* side) 1) t)))
|
||||
|
||||
(define-memoized (make-tile n)
|
||||
(overlay
|
||||
(tile-text n)
|
||||
(plain-tile n)))
|
||||
|
||||
;; Place a tile on an image of the grid at (i,j)
|
||||
;;
|
||||
(define (place-tile/ij tile i j grid-image)
|
||||
(define (pos k)
|
||||
(+ (* (add1 k) *grid-spacing*)
|
||||
(* k *tile-side*)))
|
||||
(underlay/xy grid-image (pos j) (pos i) tile))
|
||||
|
||||
;; Make an image of the grid from the flat representation
|
||||
;;
|
||||
(define *last-state* null) ; Cache the previous grid to avoid
|
||||
(define *last-grid* null) ; senseless regeneration
|
||||
|
||||
(define (state->image state)
|
||||
(unless (equal? state *last-state*)
|
||||
(set! *last-grid*
|
||||
(for*/fold ([im (square *grid-side* 'solid *grid-color*)])
|
||||
([i (in-range *side*)]
|
||||
[j (in-range *side*)])
|
||||
(place-tile/ij (make-tile (square/ij state i j))
|
||||
i j
|
||||
im)))
|
||||
(set! *last-state* state))
|
||||
*last-grid*)
|
||||
|
||||
(define *empty-grid-image*
|
||||
(state->image (make-list (sqr *side*) 0)))
|
||||
|
||||
;; Convert the sparse representation of moves into a single frame in an
|
||||
;; animation at time k, where k is between 0.0 (start state) and 1.0
|
||||
;; (final state).
|
||||
;;
|
||||
(define (moves->frame moves k)
|
||||
(for*/fold ([grid *empty-grid-image*])
|
||||
([m moves])
|
||||
(match-define (list value (list i1 j1) (list i2 j2)) m)
|
||||
(place-tile/ij (make-tile value)
|
||||
(interpolate k i1 i2) (interpolate k j1 j2)
|
||||
grid)))
|
||||
|
||||
;; Animation of simultaneously moving tiles.
|
||||
;;
|
||||
(define (animate-moving-tiles state op)
|
||||
(let ([grid (chop state)])
|
||||
(build-list 9 (λ (i)
|
||||
(λ ()
|
||||
(moves->frame (op grid)
|
||||
(* 0.1 (add1 i))))))))
|
||||
|
||||
;; Animation of a tile appearing in a previously blank square.
|
||||
;;
|
||||
(define (animate-appearing-tile state value index)
|
||||
(let ([start (state->image state)]
|
||||
[tile (make-tile value)]
|
||||
[i (quotient index *side*)]
|
||||
[j (remainder index *side*)])
|
||||
(build-list 4 (λ (m)
|
||||
(λ ()
|
||||
(place-tile/ij (overlay
|
||||
(scale (* 0.2 (add1 m)) tile)
|
||||
(plain-tile 0))
|
||||
i j
|
||||
start))))))
|
||||
|
||||
;;--------------------------------------------------------------
|
||||
;;
|
||||
;; The Game
|
||||
;;
|
||||
|
||||
;; an image-procedure is a procedure of no arguments that produces an image
|
||||
|
||||
;; a world contains:
|
||||
;; state is a ?
|
||||
;; score is a number
|
||||
;; winning-total is #f or a number, representing the final score <-- is this
|
||||
;; necessary?
|
||||
;; frames is a (list-of image-procedure)
|
||||
;; start-time is a number, in seconds
|
||||
(define-struct world (state score winning-total frames start-time) #:transparent)
|
||||
|
||||
;; The game is over when any animations have been finished and
|
||||
;; no more moves are possible.
|
||||
;;
|
||||
;; note that winning the game does *not* end the game.
|
||||
;;
|
||||
(define (game-over? w)
|
||||
(match-define (world state score wt frames start-time) w)
|
||||
(and (null? frames) ; Finish animations to reach final state and show the banner
|
||||
(or (finished? state)
|
||||
(out-of-time? (world-start-time w)))))
|
||||
|
||||
;; Is the player out of time?
|
||||
(define (out-of-time? start-time)
|
||||
(and *time-limit* (< (+ start-time *time-limit*) (current-seconds))))
|
||||
|
||||
;; Given an arrow key return the operations to change the state and
|
||||
;; produce the sliding animation.
|
||||
;;
|
||||
(define (key->ops a-key)
|
||||
(cond
|
||||
[(key=? a-key "left") (list left moves-grid-left)]
|
||||
[(key=? a-key "right") (list right moves-grid-right)]
|
||||
[(key=? a-key "up") (list up moves-grid-up)]
|
||||
[(key=? a-key "down") (list down moves-grid-down)]
|
||||
[else (list #f #f)]))
|
||||
|
||||
;; Respond to a key-press
|
||||
;;
|
||||
(define (change w a-key)
|
||||
(match-let ([(list op moves-op) (key->ops a-key)]
|
||||
[(world st score wt frames start-time) w])
|
||||
(cond [(out-of-time? start-time) w] ; Stop accepting key-presses
|
||||
[op
|
||||
(let* ([grid (chop st)]
|
||||
[slide-state (flatten (op grid))])
|
||||
(if (equal? slide-state st)
|
||||
w ; sliding had no effect
|
||||
(let* ([replace (random (count-zeros slide-state))]
|
||||
[index (index-of-nth-zero slide-state replace)]
|
||||
[value (new-tile)]
|
||||
[new-state (replace-nth-zero slide-state replace value)]
|
||||
[horizontal? (member a-key (list "left" "right"))])
|
||||
(make-world new-state
|
||||
(+ score (score-increment
|
||||
(if horizontal? grid (transpose grid))))
|
||||
(cond [wt wt]
|
||||
[(won-game? new-state)
|
||||
(apply + (flatten new-state))]
|
||||
[else #f])
|
||||
(append frames
|
||||
(animate-moving-tiles st moves-op)
|
||||
(animate-appearing-tile slide-state value index))
|
||||
start-time))))]
|
||||
[(key=? a-key " ") ; rotate the board
|
||||
(make-world ((compose flatten transpose reverse) (chop st))
|
||||
score wt
|
||||
(append frames
|
||||
(animate-moving-tiles st moves-grid-rotate))
|
||||
start-time)]
|
||||
[else w]))) ; unrecognised key - no effect
|
||||
|
||||
;; Are we there yet?
|
||||
;;
|
||||
(define (won-game? state)
|
||||
(= (apply max state) *tile-that-wins*))
|
||||
|
||||
;; Banner overlay text: e.g. You won! / Game Over, etc.
|
||||
;;
|
||||
(define (banner txt state [color 'black])
|
||||
(let ([b-text (text txt 30 color)])
|
||||
(overlay
|
||||
b-text
|
||||
(rectangle (* 1.2 (image-width b-text))
|
||||
(* 1.4 (image-height b-text))
|
||||
'solid 'white)
|
||||
(state->image state))))
|
||||
|
||||
;; Convert number of seconds to "h:mm:ss" or "m:ss" format
|
||||
;;
|
||||
(define (number->time-string s)
|
||||
(define hrs (quotient s 3600))
|
||||
(define mins (quotient (remainder s 3600) 60))
|
||||
(define secs (remainder s 60))
|
||||
(define (xx n)
|
||||
(cond [(<= n 0) "00"]
|
||||
[(<= n 9) (format "0~a" n)]
|
||||
[else (remainder n 60)]))
|
||||
(if (>= s 3600)
|
||||
(format "~a:~a:~a" hrs (xx mins) (xx secs))
|
||||
(format "~a:~a" mins (xx secs))))
|
||||
|
||||
(define (time-remaining start)
|
||||
(+ *time-limit* start (- (current-seconds))))
|
||||
|
||||
(define (time-elapsed start)
|
||||
(- (current-seconds) start))
|
||||
|
||||
;; Display the grid with score below.
|
||||
;;
|
||||
;; If there are frames, show the next one. Otherwise show the steady state.
|
||||
;;
|
||||
(define (show-world w)
|
||||
(match-define (world state score wt frames start-time) w)
|
||||
(let* ([board (if (null? frames)
|
||||
(cond [(finished? state) (banner "Game over" state)]
|
||||
[(out-of-time? start-time) (banner "Out of Time" state 'red)]
|
||||
|
||||
;; Q: Why wt (i.e. winning-total) rather than won-game?
|
||||
;; A: wt allows the keen player to continue playing...
|
||||
[(equal? (apply + (flatten state)) wt) (banner "You won!" state)]
|
||||
[else (state->image state)])
|
||||
((first frames)))]
|
||||
[score-text (text (format "Score: ~a" score) 16 'dimgray)]
|
||||
[seconds ((if *time-limit* time-remaining time-elapsed) start-time)]
|
||||
[time-text (text (format "Time: ~a"
|
||||
(number->time-string seconds))
|
||||
16
|
||||
(cond [(or (> seconds *amber-alert*) (not *time-limit*)) 'gray]
|
||||
[(> seconds *red-alert*) 'orange]
|
||||
[else 'red]))])
|
||||
(scale *magnification*
|
||||
(above
|
||||
board
|
||||
(rectangle 0 5 'solid 'white)
|
||||
(beside
|
||||
score-text
|
||||
(rectangle (- (image-width board)
|
||||
(image-width score-text)
|
||||
(image-width time-text)) 0 'solid 'white)
|
||||
time-text)))))
|
||||
|
||||
;; Move to the next frame in the animation.
|
||||
;;
|
||||
(define (advance-frame w)
|
||||
(match-define (world state score wt frames start-time) w)
|
||||
(if (null? frames)
|
||||
w
|
||||
(make-world state score wt (rest frames) start-time)))
|
||||
|
||||
;; Use this state to preview the appearance of all the tiles
|
||||
;;
|
||||
(define (all-tiles-state)
|
||||
(let ([all-tiles '(0 2 4 8 16 32 64 128 256 512 1024 2048 4096)])
|
||||
(append all-tiles (make-list (- (sqr *side*) (length all-tiles)) 0))))
|
||||
|
||||
;; The event loop
|
||||
;;
|
||||
(define (start)
|
||||
(big-bang (make-world (initial-state)
|
||||
;(all-tiles-state)
|
||||
0 #f null (current-seconds))
|
||||
(to-draw show-world)
|
||||
(on-key change)
|
||||
(on-tick advance-frame 0.01)
|
||||
(stop-when game-over? show-world)
|
||||
(name "2048 - Racket edition")))
|
||||
|
||||
;;
|
||||
;; TESTS
|
||||
;;
|
||||
(module+ test
|
||||
(set-side! 4)
|
||||
|
||||
(check-equal? (slide-left '(0 0 0 0)) '(0 0 0 0))
|
||||
(check-equal? (slide-left '(1 2 3 4)) '(1 2 3 4))
|
||||
(check-equal? (slide-left '(2 0 4 0)) '(2 4 0 0))
|
||||
(check-equal? (slide-left '(0 0 2 4)) '(2 4 0 0))
|
||||
(check-equal? (slide-left '(2 0 2 0)) '(4 0 0 0))
|
||||
(check-equal? (slide-left '(0 8 8 0)) '(16 0 0 0))
|
||||
(check-equal? (slide-left '(4 4 8 8)) '(8 16 0 0))
|
||||
(check-equal? (slide-right '(4 4 8 8)) '(0 0 8 16))
|
||||
(check-equal? (slide-right '(4 4 4 0)) '(0 0 4 8))
|
||||
|
||||
(check-equal? (moves-row-left '(0 0 0 0)) '())
|
||||
(check-equal? (moves-row-left '(1 2 3 4))
|
||||
'((1 0 0)
|
||||
(2 1 1)
|
||||
(3 2 2)
|
||||
(4 3 3)))
|
||||
|
||||
(check-equal? (moves-row-left '(2 0 4 0)) '((2 0 0)
|
||||
(4 2 1)))
|
||||
|
||||
(check-equal? (moves-row-right '(2 0 4 0)) '((4 2 3)
|
||||
(2 0 2)))
|
||||
|
||||
(check-equal? (moves-row-left '(0 0 2 4)) '((2 2 0)
|
||||
(4 3 1)))
|
||||
|
||||
(check-equal? (moves-row-left '(2 0 2 0)) '((2 0 0)
|
||||
(2 2 0)))
|
||||
|
||||
(check-equal? (moves-row-left '(2 2 2 0)) '((2 0 0)
|
||||
(2 1 0)
|
||||
(2 2 1)))
|
||||
|
||||
(check-equal? (moves-row-right '(2 2 2 0)) '((2 2 3)
|
||||
(2 1 3)
|
||||
(2 0 2)))
|
||||
|
||||
(check-equal? (moves-row-left '(2 2 4 4)) '((2 0 0)
|
||||
(2 1 0)
|
||||
(4 2 1)
|
||||
(4 3 1)))
|
||||
|
||||
(check-equal? (moves-row-right '(2 2 4 4)) '((4 3 3)
|
||||
(4 2 3)
|
||||
(2 1 2)
|
||||
(2 0 2)))
|
||||
|
||||
(check-equal? (add-row-coord 7 '((2 0 0)
|
||||
(2 1 0)
|
||||
(4 2 1)))
|
||||
'((2 (7 0) (7 0))
|
||||
(2 (7 1) (7 0))
|
||||
(4 (7 2) (7 1))))
|
||||
|
||||
(check-equal? (left '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((16 0 0 0)
|
||||
(16 0 0 0)
|
||||
( 4 8 0 0)
|
||||
( 4 2 0 0)))
|
||||
(check-equal? (right '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((0 0 0 16)
|
||||
(0 0 0 16)
|
||||
(0 0 4 8)
|
||||
(0 0 2 4)))
|
||||
(check-equal? (up '((0 16 2 0)
|
||||
(8 0 2 2)
|
||||
(8 0 4 2)
|
||||
(0 0 4 2)))
|
||||
'((16 16 4 4)
|
||||
(0 0 8 2)
|
||||
(0 0 0 0)
|
||||
(0 0 0 0)))
|
||||
(check-equal? (down '((0 16 2 0)
|
||||
(8 0 2 2)
|
||||
(8 0 4 2)
|
||||
(0 0 4 2)))
|
||||
'((0 0 0 0)
|
||||
(0 0 0 0)
|
||||
(0 0 4 2)
|
||||
(16 16 8 4)))
|
||||
|
||||
(check-equal? (left '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((16 0 0 0)
|
||||
(16 0 0 0)
|
||||
( 4 8 0 0)
|
||||
( 4 2 0 0)))
|
||||
|
||||
(check-equal? (moves-grid-left '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((8 (0 1) (0 0))
|
||||
(8 (0 2) (0 0))
|
||||
(16 (1 0) (1 0))
|
||||
(2 (2 0) (2 0))
|
||||
(2 (2 1) (2 0))
|
||||
(4 (2 2) (2 1))
|
||||
(4 (2 3) (2 1))
|
||||
(2 (3 1) (3 0))
|
||||
(2 (3 2) (3 0))
|
||||
(2 (3 3) (3 1))))
|
||||
|
||||
(check-equal? (moves-grid-right '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((8 (0 2) (0 3))
|
||||
(8 (0 1) (0 3))
|
||||
(16 (1 0) (1 3))
|
||||
(4 (2 3) (2 3))
|
||||
(4 (2 2) (2 3))
|
||||
(2 (2 1) (2 2))
|
||||
(2 (2 0) (2 2))
|
||||
(2 (3 3) (3 3))
|
||||
(2 (3 2) (3 3))
|
||||
(2 (3 1) (3 2))))
|
||||
|
||||
|
||||
(check-equal? (moves-grid-up '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((16 (1 0) (0 0))
|
||||
(2 (2 0) (1 0))
|
||||
(8 (0 1) (0 1))
|
||||
(2 (2 1) (1 1))
|
||||
(2 (3 1) (1 1))
|
||||
(8 (0 2) (0 2))
|
||||
(4 (2 2) (1 2))
|
||||
(2 (3 2) (2 2))
|
||||
(4 (2 3) (0 3))
|
||||
(2 (3 3) (1 3))))
|
||||
|
||||
(check-equal? (moves-grid-down '(( 0 8 8 0)
|
||||
(16 0 0 0)
|
||||
( 2 2 4 4)
|
||||
( 0 2 2 2)))
|
||||
'((2 (2 0) (3 0))
|
||||
(16 (1 0) (2 0))
|
||||
(2 (3 1) (3 1))
|
||||
(2 (2 1) (3 1))
|
||||
(8 (0 1) (2 1))
|
||||
(2 (3 2) (3 2))
|
||||
(4 (2 2) (2 2))
|
||||
(8 (0 2) (1 2))
|
||||
(2 (3 3) (3 3))
|
||||
(4 (2 3) (2 3))))
|
||||
|
||||
(check-equal? (chop '(1 2 3 4 5 6 7 8) 4)
|
||||
'((1 2 3 4) (5 6 7 8)))
|
||||
|
||||
(check-equal? (length (initial-state 5)) 25)
|
||||
|
||||
(let* ([initial (initial-state)]
|
||||
[initial-sum (apply + initial)]
|
||||
[largest-3 (take (sort initial >) 3)])
|
||||
(check-equal? (length initial) 16)
|
||||
(check-true (or (= initial-sum 4)
|
||||
(= initial-sum 6)
|
||||
(= initial-sum 8)))
|
||||
(check-true (or (equal? largest-3 '(2 2 0))
|
||||
(equal? largest-3 '(4 2 0))
|
||||
(equal? largest-3 '(4 4 0)))))
|
||||
|
||||
(check-equal? (count-zeros '(1 0 1 0 0 0 1)) 4)
|
||||
(check-equal? (count-zeros '(1 1)) 0)
|
||||
(check-equal? (replace-nth-zero '(0 0 0 1 2 0) 2 5)
|
||||
'(0 0 5 1 2 0))
|
||||
|
||||
(check-true (finished? '(1 2 3 4) 2))
|
||||
(check-false (finished? '(2 2 3 4) 2)))
|
||||
|
||||
(start)
|
||||
115
Task/2048/Raku/2048.raku
Normal file
115
Task/2048/Raku/2048.raku
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
use Term::termios;
|
||||
|
||||
constant $saved = Term::termios.new(fd => 1).getattr;
|
||||
constant $termios = Term::termios.new(fd => 1).getattr;
|
||||
# raw mode interferes with carriage returns, so
|
||||
# set flags needed to emulate it manually
|
||||
$termios.unset_iflags(<BRKINT ICRNL ISTRIP IXON>);
|
||||
$termios.unset_lflags(< ECHO ICANON IEXTEN ISIG>);
|
||||
$termios.setattr(:DRAIN);
|
||||
|
||||
# reset terminal to original setting on exit
|
||||
END { $saved.setattr(:NOW) }
|
||||
|
||||
constant n = 4; # board size
|
||||
constant cell = 6; # cell width
|
||||
constant ansi = True; # color!
|
||||
|
||||
my @board = ( ['' xx n] xx n );
|
||||
my $save = '';
|
||||
my $score = 0;
|
||||
|
||||
constant $top = join '─' x cell, '┌', '┬' xx n-1, '┐';
|
||||
constant $mid = join '─' x cell, '├', '┼' xx n-1, '┤';
|
||||
constant $bot = join '─' x cell, '└', '┴' xx n-1, '┘';
|
||||
|
||||
my %dir = (
|
||||
"\e[A" => 'up',
|
||||
"\e[B" => 'down',
|
||||
"\e[C" => 'right',
|
||||
"\e[D" => 'left',
|
||||
);
|
||||
|
||||
my @ANSI = <0 1;97 1;93 1;92 1;96 1;91 1;95 1;94 1;30;47 1;43
|
||||
1;42 1;46 1;41 1;45 1;44 1;33;43 1;33;42 1;33;41 1;33;44>;
|
||||
|
||||
sub row (@row) { '│' ~ (join '│', @row».¢er) ~ '│' }
|
||||
|
||||
sub center ($s){
|
||||
my $c = cell - $s.chars;
|
||||
my $pad = ' ' x ceiling($c/2);
|
||||
my $tile = sprintf "%{cell}s", "$s$pad";
|
||||
my $idx = $s ?? $s.log(2) !! 0;
|
||||
ansi ?? "\e[{@ANSI[$idx]}m$tile\e[0m" !! $tile;
|
||||
}
|
||||
|
||||
sub draw-board {
|
||||
run('clear');
|
||||
print qq:to/END/;
|
||||
|
||||
|
||||
Press direction arrows to move.
|
||||
|
||||
Press q to quit.
|
||||
|
||||
$top
|
||||
{ join "\n\t$mid\n\t", map { .&row }, @board }
|
||||
$bot
|
||||
|
||||
Score: $score
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
sub squash (@c) {
|
||||
my @t = grep { .chars }, @c;
|
||||
map { combine(@t[$_], @t[$_+1]) if @t[$_] && @t[$_+1] == @t[$_] }, ^@t-1;
|
||||
@t = grep { .chars }, @t;
|
||||
@t.push: '' while @t < n;
|
||||
@t;
|
||||
}
|
||||
|
||||
sub combine ($v is rw, $w is rw) { $v += $w; $w = ''; $score += $v; }
|
||||
|
||||
proto sub move (|) {*};
|
||||
|
||||
multi move('up') {
|
||||
map { @board[*;$_] = squash @board[*;$_] }, ^n;
|
||||
}
|
||||
|
||||
multi move('down') {
|
||||
map { @board[*;$_] = reverse squash reverse @board[*;$_] }, ^n;
|
||||
}
|
||||
|
||||
multi move('left') {
|
||||
map { @board[$_] = squash @board[$_] }, ^n;
|
||||
}
|
||||
|
||||
multi move('right') {
|
||||
map { @board[$_;*] = reverse squash reverse @board[$_] }, ^n;
|
||||
}
|
||||
|
||||
sub another {
|
||||
my @empties;
|
||||
for @board.kv -> $r, @row {
|
||||
@empties.push(($r, $_)) for @row.grep(:k, '');
|
||||
}
|
||||
my ( $x, $y ) = @empties.roll;
|
||||
@board[$x; $y] = (flat 2 xx 9, 4).roll;
|
||||
}
|
||||
|
||||
sub save () { join '|', flat @board».list }
|
||||
|
||||
loop {
|
||||
another if $save ne save();
|
||||
draw-board;
|
||||
$save = save();
|
||||
|
||||
# Read up to 4 bytes from keyboard buffer.
|
||||
# Page navigation keys are 3-4 bytes each.
|
||||
# Specifically, arrow keys are 3.
|
||||
my $key = $*IN.read(4).decode;
|
||||
|
||||
move %dir{$key} if so %dir{$key};
|
||||
last if $key eq 'q'; # (q)uit
|
||||
}
|
||||
88
Task/2048/Red/2048.red
Normal file
88
Task/2048/Red/2048.red
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
Red [Needs: 'View]
|
||||
|
||||
random/seed now
|
||||
board: random [2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
||||
|
||||
; ----------- move engine -----------
|
||||
tasse: function [b] [
|
||||
forall b [while [b/1 = 0] [remove b]]
|
||||
head append/dup b 0 4 - length? b
|
||||
]
|
||||
somme: function [b] [
|
||||
tasse b
|
||||
repeat n 3 [
|
||||
m: n + 1
|
||||
if all [b/:n <> 0 b/:n = b/:m] [
|
||||
poke b n b/:n * 2
|
||||
poke b m 0
|
||||
]
|
||||
]
|
||||
tasse b
|
||||
]
|
||||
reshape: function [b d][
|
||||
res: copy []
|
||||
switch d [
|
||||
up [repeat n 4 [extract/index/into b 4 n res] res]
|
||||
down [repeat n 4 [extract/index/into b 4 n res] reverse res]
|
||||
left [res: copy b]
|
||||
right [res: reverse copy b]
|
||||
]
|
||||
]
|
||||
mov: function [b d][
|
||||
b1: reshape b d
|
||||
moved: copy []
|
||||
foreach [x y z t] b1 [append moved somme reduce [x y z t]]
|
||||
reshape moved d
|
||||
]
|
||||
|
||||
; --------- GUI ---------
|
||||
colors: [0 gray 2 snow 4 linen 8 brick 16 brown 32 sienna
|
||||
64 water 128 teal 256 olive 512 khaki 1024 tanned 2028 wheat]
|
||||
tsize: 110x110
|
||||
padsize: 4x4
|
||||
padlen: 114
|
||||
mainsize: tsize * 4 + (padsize * 5)
|
||||
tfont: make font! [size: 30 color: black style: 'bold]
|
||||
|
||||
display: does [
|
||||
foreach face lay/pane [
|
||||
n: face/data
|
||||
face/text: either board/:n = 0 [""] [form board/:n]
|
||||
face/color: reduce select colors board/:n
|
||||
]
|
||||
]
|
||||
lay: layout [
|
||||
size mainsize
|
||||
title "2048 game"
|
||||
backdrop white
|
||||
on-key [
|
||||
if find [up down left right] d: event/key [
|
||||
if board <> newboard: mov board d [
|
||||
board: newboard
|
||||
if find board 2048 [alert "You win!"]
|
||||
until [
|
||||
pos: random 16
|
||||
0 = board/:pos
|
||||
]
|
||||
poke board pos either 1 = random 10 [4] [2]
|
||||
display
|
||||
conds: reduce [not find board 0]
|
||||
foreach d [up down left right] [
|
||||
append conds board = mov board d
|
||||
]
|
||||
if all conds [alert "You lose!"]
|
||||
]
|
||||
]
|
||||
]
|
||||
space padsize
|
||||
]
|
||||
repeat n length? board [append lay/pane make face! [
|
||||
type: 'base
|
||||
offset: padsize + padlen * as-pair (n - 1 % 4) (n - 1 / 4)
|
||||
size: tsize
|
||||
color: reduce select colors board/:n
|
||||
data: n
|
||||
font: tfont
|
||||
]]
|
||||
display
|
||||
view lay
|
||||
436
Task/2048/Ring/2048.ring
Normal file
436
Task/2048/Ring/2048.ring
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
# Project : 2048 Game
|
||||
|
||||
load "stdlib.ring"
|
||||
load "guilib.ring"
|
||||
|
||||
C_GAMETITLE = '2048 Game'
|
||||
C_WINDOWBACKGROUND = "background-color: gray;"
|
||||
if isMobile()
|
||||
C_LABELFONTSIZE = "font-size:120px;"
|
||||
C_BUTTONFONTSIZE = "font-size:160px;"
|
||||
else
|
||||
C_LABELFONTSIZE = "font-size:50px;"
|
||||
C_BUTTONFONTSIZE = "font-size:80px;"
|
||||
ok
|
||||
C_PLAYERSCORESTYLE = "color:white;background-color:rgb(50,50,50);border-radius:17px;" + C_LABELFONTSIZE
|
||||
C_NEWGAMESTYLE = 'color:white;background-color:rgb(50,50,50);border-radius:17px;' + C_LABELFONTSIZE
|
||||
C_EMPTYBUTTONSTYLE = 'border-radius:17px;background-color:silver;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON2STYLE = 'border-radius:17px;color:black; background-color: yellow ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON4STYLE = 'border-radius:17px;color:black; background-color: violet ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON8STYLE = 'border-radius:17px;color:white; background-color: purple ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON16STYLE = 'border-radius:17px;color:white; background-color: blue ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON32STYLE = 'border-radius:17px;color:white; background-color: red ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON64STYLE = 'border-radius:17px;color:black; background-color: lightgray ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON128STYLE = 'border-radius:17px;color:black; background-color: white ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON256STYLE = 'border-radius:17px;color:white; background-color: black ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON512STYLE = 'border-radius:17px;color:white; background-color: Purple ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON1024STYLE = 'border-radius:17px;color:black; background-color: Yellow ;' + C_BUTTONFONTSIZE
|
||||
C_BUTTON2048STYLE = 'border-radius:17px;color:white; background-color: Green ;' + C_BUTTONFONTSIZE
|
||||
C_LAYOUTSPACING = 10
|
||||
C_PLAYERSCORE = 'Player Score : '
|
||||
|
||||
size = 4
|
||||
limit = 2
|
||||
num = 0
|
||||
flag = 0
|
||||
x1 = 0
|
||||
x2 = 0
|
||||
y1 = 0
|
||||
y2 = 0
|
||||
nScore = 0
|
||||
button = newlist(size,size)
|
||||
buttonsave = newlist(size,size)
|
||||
LayoutButtonRow = list(size+2)
|
||||
moveleft = []
|
||||
moveright = []
|
||||
moveup = []
|
||||
movedown = []
|
||||
myfilter2 = null
|
||||
myfilter3 = null
|
||||
winheight = 0
|
||||
winwidth = 0
|
||||
|
||||
app = new qApp {
|
||||
StyleFusion()
|
||||
processevents()
|
||||
win = new qWidget() {
|
||||
setWindowTitle(C_GAMETITLE)
|
||||
setgeometry(100,100,600,700)
|
||||
setminimumwidth(300)
|
||||
setminimumheight(300)
|
||||
if not isMobile()
|
||||
grabkeyboard()
|
||||
ok
|
||||
setstylesheet(C_WINDOWBACKGROUND)
|
||||
move(490,100)
|
||||
for n = 1 to size
|
||||
for m = 1 to size
|
||||
button[n][m] = new MyButton(win)
|
||||
next
|
||||
next
|
||||
newgame = new qLabel(win)
|
||||
playerscore = new qLabel(win)
|
||||
myfilter3 = new qAllEvents(win) {
|
||||
setMouseButtonPressEvent("pPress()")
|
||||
setMouseButtonReleaseEvent("pRelease()")}
|
||||
installeventfilter(myfilter3)
|
||||
myfilter2 = new qAllEvents(win) {
|
||||
setkeypressevent("keypress()") }
|
||||
installeventfilter(myfilter2)
|
||||
winwidth = win.width()
|
||||
winheight = win.height()
|
||||
for n = 1 to size + 2
|
||||
LayoutButtonRow[n] = new QHBoxLayout() {
|
||||
setSpacing(C_LAYOUTSPACING)
|
||||
}
|
||||
next
|
||||
for n = 1 to size
|
||||
for m = 1 to size
|
||||
button[n][m] { temp = text() }
|
||||
buttonsave[n][m] = temp
|
||||
button[n][m] = new MyButton(win) {
|
||||
setalignment(Qt_AlignHCenter | Qt_AlignVCenter)
|
||||
setstylesheet(C_EMPTYBUTTONSTYLE)
|
||||
show()
|
||||
}
|
||||
next
|
||||
next
|
||||
for n = 1 to size
|
||||
for m = 1 to size
|
||||
LayoutButtonRow[n].AddWidget(button[m][n])
|
||||
win.show()
|
||||
temp = buttonsave[n][m]
|
||||
button[n][m].settext(temp)
|
||||
next
|
||||
LayoutButtonRow[n].setSpacing(C_LAYOUTSPACING)
|
||||
next
|
||||
playerscore {
|
||||
setGeometry(0,4*floor(winheight/6),winwidth,floor(winheight/6))
|
||||
setalignment(Qt_AlignHCenter | Qt_AlignVCenter)
|
||||
settext(C_PLAYERSCORE + nScore)
|
||||
setStylesheet(C_PLAYERSCORESTYLE)
|
||||
show()
|
||||
}
|
||||
newgame {
|
||||
setGeometry(0,5*floor(winheight/6),winwidth,floor(winheight/6))
|
||||
setalignment(Qt_AlignHCenter | Qt_AlignVCenter)
|
||||
setstylesheet(C_NEWGAMESTYLE)
|
||||
settext('New Game')
|
||||
myfilter4 = new qallevents(newgame)
|
||||
myfilter4.setMouseButtonPressEvent("pbegin()")
|
||||
installeventfilter(myfilter4)
|
||||
show()
|
||||
}
|
||||
LayoutButtonRow[size+1].AddWidget(playerscore)
|
||||
LayoutButtonRow[size+2].AddWidget(newgame)
|
||||
LayoutButtonMain = new QVBoxLayout() {
|
||||
setSpacing(C_LAYOUTSPACING)
|
||||
for n = 1 to size+2
|
||||
AddLayout(LayoutButtonRow[n])
|
||||
win.show()
|
||||
next
|
||||
}
|
||||
win.setLayout(LayoutButtonMain)
|
||||
win.show()
|
||||
pbegin()
|
||||
show()
|
||||
}
|
||||
exec()
|
||||
}
|
||||
|
||||
func pPress()
|
||||
x1 = myfilter3.getglobalx()
|
||||
y1 = myfilter3.getglobaly()
|
||||
|
||||
func pRelease()
|
||||
x2 = myfilter3.getglobalx()
|
||||
y2 = myfilter3.getglobaly()
|
||||
difx = x2 - x1
|
||||
dify = y2 - y1
|
||||
if fabs(difx) > fabs(dify)
|
||||
if difx < 0
|
||||
pleft()
|
||||
else
|
||||
pRight()
|
||||
ok
|
||||
else
|
||||
if dify < 0
|
||||
pUp()
|
||||
else
|
||||
pDown()
|
||||
ok
|
||||
ok
|
||||
|
||||
func keypress()
|
||||
nKey = myfilter2.getkeycode()
|
||||
switch nKey
|
||||
on 16777234 pleft()
|
||||
on 16777236 pright()
|
||||
on 16777235 pup()
|
||||
on 16777237 pdown()
|
||||
off
|
||||
|
||||
func pbegin()
|
||||
numbers = [['2','2'],['2','4']]
|
||||
randnew = newlist(2,2)
|
||||
for n = 1 to size
|
||||
for m = 1 to size
|
||||
button[n][m].setStylesheet(C_EMPTYBUTTONSTYLE)
|
||||
button[n][m].settext('')
|
||||
next
|
||||
next
|
||||
while true
|
||||
rn1 = random(size - 1) + 1
|
||||
rm1 = random(size - 1) + 1
|
||||
rn2 = random(size - 1) + 1
|
||||
rm2 = random(size - 1) + 1
|
||||
bool = (rn1 = rn2) and (rm1 = rm2)
|
||||
if not bool
|
||||
exit
|
||||
ok
|
||||
end
|
||||
rand = random(limit - 1) + 1
|
||||
button[rn1][rm1].settext(numbers[rand][1])
|
||||
button[rn2][rm2].settext(numbers[rand][2])
|
||||
nScore = 0
|
||||
playerscore.settext(C_PLAYERSCORE)
|
||||
|
||||
func pMoveInDirection cFunc
|
||||
num = gameover()
|
||||
if num = size*size
|
||||
flag = 1
|
||||
msgBox('You lost!')
|
||||
pbegin()
|
||||
ok
|
||||
if flag = 0
|
||||
call cFunc()
|
||||
sleep(0.5)
|
||||
newnum()
|
||||
ok
|
||||
|
||||
func pdown()
|
||||
pMoveInDirection(:pMoveDown)
|
||||
|
||||
func pup()
|
||||
pMoveInDirection(:pMoveUp)
|
||||
|
||||
func pleft()
|
||||
pMoveInDirection(:pMoveLeft)
|
||||
|
||||
func pright()
|
||||
pMoveInDirection(:pMoveRight)
|
||||
|
||||
func pmoveleft()
|
||||
for n = 1 to size
|
||||
moveleft = []
|
||||
for m = 1 to size
|
||||
button[m][n] {temp = text()}
|
||||
if temp != ''
|
||||
add(moveleft,temp)
|
||||
ok
|
||||
next
|
||||
movetilesleft(n,moveleft)
|
||||
next
|
||||
|
||||
func pmoveright()
|
||||
for n = 1 to size
|
||||
moveright = []
|
||||
for m = size to 1 step -1
|
||||
button[m][n] {temp = text()}
|
||||
if temp != ''
|
||||
add(moveright,temp)
|
||||
ok
|
||||
next
|
||||
movetilesright(n,moveright)
|
||||
next
|
||||
return
|
||||
|
||||
func pmoveup()
|
||||
for n = 1 to size
|
||||
moveup = []
|
||||
for m = 1 to size
|
||||
button[n][m] {temp = text()}
|
||||
if temp != ''
|
||||
add(moveup,temp)
|
||||
ok
|
||||
next
|
||||
movetilesup(n,moveup)
|
||||
next
|
||||
return
|
||||
|
||||
func pmovedown()
|
||||
for n = 1 to size
|
||||
movedown = []
|
||||
for m = size to 1 step -1
|
||||
button[n][m] {temp = text()}
|
||||
if temp != ''
|
||||
add(movedown,temp)
|
||||
ok
|
||||
next
|
||||
movetilesdown(n,movedown)
|
||||
next
|
||||
return
|
||||
|
||||
func movetilesleft(nr,moveleft)
|
||||
for p = 1 to len(moveleft) - 1
|
||||
temp1 = moveleft[p]
|
||||
temp2 = moveleft[p+1]
|
||||
temp = string(number(temp1) + number(temp2))
|
||||
if (temp1 = temp2) and (temp1 != '0') and (temp2 != '0') and (temp1 != '') and (temp2 != '')
|
||||
if temp != '0' and temp != ''
|
||||
nScore = nScore + temp
|
||||
playerscore.settext(C_PLAYERSCORE + nScore)
|
||||
flag = 1
|
||||
moveleft[p] = temp
|
||||
del(moveleft,p+1)
|
||||
ok
|
||||
ok
|
||||
next
|
||||
for n = 1 to len(moveleft)
|
||||
button[n][nr].settext(moveleft[n])
|
||||
next
|
||||
for n = len(moveleft) + 1 to size
|
||||
if n <= size
|
||||
button[n][nr].setStylesheet(C_EMPTYBUTTONSTYLE)
|
||||
button[n][nr].settext('')
|
||||
ok
|
||||
next
|
||||
return
|
||||
|
||||
func movetilesright(nr,moveright)
|
||||
flag = 0
|
||||
for p = 2 to len(moveright)
|
||||
temp1 = moveright[p]
|
||||
temp2 = moveright[p-1]
|
||||
if (temp1 = temp2) and (temp1 != '0') and (temp2 != '0') and (temp1 != '') and (temp2 != '')
|
||||
temp = string(number(temp1) + number(temp2))
|
||||
if temp != '0' and temp != ''
|
||||
nScore = nScore + temp
|
||||
playerscore.settext(C_PLAYERSCORE + nScore)
|
||||
flag = 1
|
||||
moveright[p] = temp
|
||||
del(moveright,p-1)
|
||||
ok
|
||||
ok
|
||||
next
|
||||
for n = 1 to len(moveright)
|
||||
button[size-n+1][nr].settext(moveright[n])
|
||||
next
|
||||
for n = 1 to size - len(moveright)
|
||||
if n <= size
|
||||
button[n][nr].setStylesheet(C_EMPTYBUTTONSTYLE)
|
||||
button[n][nr].settext('')
|
||||
ok
|
||||
next
|
||||
|
||||
|
||||
func movetilesup(nr,moveup)
|
||||
flag = 0
|
||||
for p = 1 to len(moveup) - 1
|
||||
temp1 = moveup[p]
|
||||
temp2 = moveup[p+1]
|
||||
if (temp1 = temp2) and (temp1 != '0') and (temp2 != '0') and (temp1 != '') and (temp2 != '')
|
||||
temp = string(number(temp1) + number(temp2))
|
||||
if temp != '0' and temp != ''
|
||||
nScore = nScore + temp
|
||||
playerscore.settext(C_PLAYERSCORE + nScore)
|
||||
flag = 1
|
||||
moveup[p] = temp
|
||||
del(moveup,p+1)
|
||||
ok
|
||||
ok
|
||||
next
|
||||
for n = 1 to len(moveup)
|
||||
button[nr][n].settext(moveup[n])
|
||||
next
|
||||
for n = len(moveup) + 1 to size
|
||||
if n <= size
|
||||
button[nr][n].setStylesheet(C_EMPTYBUTTONSTYLE)
|
||||
button[nr][n].settext('')
|
||||
ok
|
||||
next
|
||||
|
||||
func movetilesdown(nr,movedown)
|
||||
flag = 0
|
||||
for p = 1 to len(movedown) - 1
|
||||
temp1 = movedown[p]
|
||||
temp2 = movedown[p+1]
|
||||
if (temp1 = temp2) and (temp1 != '0') and (temp2 != '0') and (temp1 != '') and (temp2 != '')
|
||||
temp = string(number(temp1) + number(temp2))
|
||||
if temp != '0' and temp != ''
|
||||
nScore = nScore + temp
|
||||
playerscore.settext(C_PLAYERSCORE + nScore)
|
||||
flag = 1
|
||||
movedown[p] = temp
|
||||
del(movedown,p+1)
|
||||
ok
|
||||
ok
|
||||
next
|
||||
for n = 1 to len(movedown)
|
||||
button[nr][size-n+1].settext(movedown[n])
|
||||
next
|
||||
for n = size - len(movedown) to 1 step -1
|
||||
if n <= size
|
||||
button[nr][n].setStylesheet(C_EMPTYBUTTONSTYLE)
|
||||
app.processevents()
|
||||
button[nr][n].settext('')
|
||||
ok
|
||||
next
|
||||
|
||||
func newnum()
|
||||
while true
|
||||
rn = random(size - 1) + 1
|
||||
rm = random(size - 1) + 1
|
||||
if button[rn][rm].text() = ''
|
||||
button[rn][rm].settext('2')
|
||||
exit
|
||||
ok
|
||||
end
|
||||
return
|
||||
|
||||
func gameover()
|
||||
num = 0
|
||||
flag = 0
|
||||
for n = 1 to size
|
||||
for m = 1 to size
|
||||
if button[n][m].text() != ''
|
||||
num = num + 1
|
||||
ok
|
||||
next
|
||||
next
|
||||
return num
|
||||
|
||||
func msgBox(text) {
|
||||
m = new qMessageBox(win) {
|
||||
setWindowTitle('2048 Game')
|
||||
setText(text)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
func showarray(vect)
|
||||
see "["
|
||||
svect = ""
|
||||
for n = 1 to len(vect)
|
||||
svect = svect + vect[n] + " "
|
||||
next
|
||||
svect = left(svect, len(svect) - 1)
|
||||
see svect
|
||||
see "]" + nl
|
||||
|
||||
class MyButton from qLabel
|
||||
func setText(cValue)
|
||||
Super.setText(cValue)
|
||||
switch cValue
|
||||
on '2' setStyleSheet(C_BUTTON2STYLE)
|
||||
on '4' setStylesheet(C_BUTTON4STYLE)
|
||||
on '8' setStylesheet(C_BUTTON8STYLE)
|
||||
on '16' setStylesheet(C_BUTTON16STYLE)
|
||||
on '32' setStylesheet(C_BUTTON32STYLE)
|
||||
on '64' setStylesheet(C_BUTTON64STYLE)
|
||||
on '128' setStylesheet(C_BUTTON128STYLE)
|
||||
on '256' setStylesheet(C_BUTTON256STYLE)
|
||||
on '512' setStylesheet(C_BUTTON512STYLE)
|
||||
on '1024' setStylesheet(C_BUTTON1024STYLE)
|
||||
on '2048' setStylesheet(C_BUTTON2048STYLE)
|
||||
off
|
||||
198
Task/2048/Ruby/2048.rb
Normal file
198
Task/2048/Ruby/2048.rb
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'io/console'
|
||||
|
||||
class Board
|
||||
def initialize size=4, win_limit=2048, cell_width = 6
|
||||
@size = size; @cw = cell_width; @win_limit = win_limit
|
||||
@board = Array.new(size) {Array.new(size, 0)}
|
||||
@moved = true; @score = 0; @no_more_moves = false
|
||||
spawn
|
||||
end
|
||||
|
||||
def draw
|
||||
print "\n\n" if @r_vert
|
||||
print ' ' if @r_hori
|
||||
print '┌' + (['─' * @cw] * @size).join('┬') + '┐'
|
||||
@board.each do |row|
|
||||
print "\n"
|
||||
formated = row.map {|num| num == 0 ? ' ' * @cw : format(num)}
|
||||
print ' ' if @r_hori
|
||||
puts '│' + formated.join('│') + '│'
|
||||
print ' ' if @r_hori
|
||||
print '├' + ([' ' * @cw] * @size).join('┼') + '┤'
|
||||
end
|
||||
print "\r"
|
||||
print ' ' if @r_hori
|
||||
puts '└' + (['─' * @cw] * @size).join('┴') + '┘'
|
||||
end
|
||||
|
||||
def move direction
|
||||
case direction
|
||||
when :up
|
||||
@board = column_map {|c| logic(c)}
|
||||
@r_vert = false if $rumble
|
||||
when :down
|
||||
@board = column_map {|c| logic(c.reverse).reverse}
|
||||
@r_vert = true if $rumble
|
||||
when :left
|
||||
@board = row_map {|r| logic(r)}
|
||||
@r_hori = false if $rumble
|
||||
when :right
|
||||
@board = row_map {|r| logic(r.reverse).reverse}
|
||||
@r_hori = true if $rumble
|
||||
end
|
||||
spawn
|
||||
@moved = false
|
||||
end
|
||||
|
||||
def print_score
|
||||
puts "Your Score is #@score."
|
||||
puts "Congratulations, you have won!" if to_enum.any? {|e| e >= @win_limit}
|
||||
end
|
||||
|
||||
def no_more_moves?; @no_more_moves; end
|
||||
def won?; to_enum.any? {|e| e >= @win_limit}; end
|
||||
def reset!; initialize @size, @win_limit, @cw; end
|
||||
|
||||
private
|
||||
|
||||
def set x, y, val
|
||||
@board[y][x] = val
|
||||
end
|
||||
|
||||
def spawn
|
||||
free_pos = to_enum.select{|elem,x,y| elem == 0}.map{|_,x,y| [x,y]}
|
||||
unless free_pos.empty?
|
||||
set *free_pos.sample, rand > 0.1 ? 2 : 4 if @moved
|
||||
else
|
||||
snap = @board
|
||||
unless @stop
|
||||
@stop = true
|
||||
%i{up down left right}.each{|s| move(s)}
|
||||
@no_more_moves = true if snap.flatten == @board.flatten
|
||||
@board = snap
|
||||
@stop = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def logic list
|
||||
jump = false
|
||||
result =
|
||||
list.reduce([]) do |res, val|
|
||||
if res.last == val && !jump
|
||||
res[-1] += val
|
||||
@score += val
|
||||
jump = true
|
||||
elsif val != 0
|
||||
res.push val
|
||||
jump = false
|
||||
end
|
||||
res
|
||||
end
|
||||
result += [0] * (@size - result.length)
|
||||
@moved ||= list != result
|
||||
result
|
||||
end
|
||||
|
||||
def column_map
|
||||
xboard = @board.transpose
|
||||
xboard.map!{|c| yield c }
|
||||
xboard.transpose
|
||||
end
|
||||
|
||||
def row_map
|
||||
@board.map {|r| yield r }
|
||||
end
|
||||
|
||||
def to_enum
|
||||
@enum ||= Enumerator.new(@size * @size) do |yielder|
|
||||
(@size*@size).times do |i|
|
||||
yielder.yield (@board[i / @size][i % @size]), (i % @size), (i / @size )
|
||||
end
|
||||
end
|
||||
@enum.rewind
|
||||
end
|
||||
|
||||
def format(num)
|
||||
if $color
|
||||
cstart = "\e[" + $colors[Math.log(num, 2)] + "m"
|
||||
cend = "\e[0m"
|
||||
else
|
||||
cstart = cend = ""
|
||||
end
|
||||
cstart + num.to_s.center(@cw) + cend
|
||||
end
|
||||
end
|
||||
|
||||
$color = true
|
||||
$colors = %W{0 1;97 1;93 1;92 1;96 1;91 1;95 1;94 1;30;47 1;43 1;42
|
||||
1;46 1;41 1;45 1;44 1;33;43 1;33;42 1;33;41 1;33;44}
|
||||
$rumble = false
|
||||
|
||||
$check_score = true
|
||||
unless ARGV.empty?
|
||||
puts "Usage: #$0 [gridsize] [score-threshold] [padwidth] [--no-color] [--rumble]"; exit if %W[-h --help].include?(ARGV[0])
|
||||
args = ARGV.map(&:to_i).reject{|n| n == 0}
|
||||
b = Board.new(*args) unless args.empty?
|
||||
$rumble = true if ARGV.any?{|a| a =~ /rumble/i }
|
||||
$color = false if ARGV.any?{|a| a =~ /no.?color/i}
|
||||
end
|
||||
|
||||
b ||= Board.new
|
||||
puts "\e[H\e[2J"
|
||||
b.draw
|
||||
puts "Press h for help, q to quit"
|
||||
loop do
|
||||
input = STDIN.getch
|
||||
if input == "\e"
|
||||
2.times {input << STDIN.getch}
|
||||
end
|
||||
|
||||
case input
|
||||
when "\e[A", "w" then b.move(:up)
|
||||
when "\e[B", "s" then b.move(:down)
|
||||
when "\e[C", "d" then b.move(:right)
|
||||
when "\e[D", "a" then b.move(:left)
|
||||
|
||||
when "q","\u0003","\u0004" then b.print_score; exit
|
||||
|
||||
when "h"
|
||||
puts <<-EOM.gsub(/^\s*/, '')
|
||||
┌─ ─┐
|
||||
│Use the arrow-keys or WASD on your keyboard to push board in the given direction.
|
||||
│Tiles with the same number merge into one.
|
||||
│Get a tile with a value of #{ARGV[1] || 2048} to win.
|
||||
│In case you cannot move or merge any tiles anymore, you loose.
|
||||
│You can start this game with different settings by providing commandline argument:
|
||||
│For instance:
|
||||
│ %> #$0 6 8192 --rumble
|
||||
└─ ─┘
|
||||
PRESS q TO QUIT (or Ctrl-C or Ctrl-D)
|
||||
EOM
|
||||
input = STDIN.getch
|
||||
end
|
||||
|
||||
puts "\e[H\e[2J"
|
||||
b.draw
|
||||
|
||||
if b.no_more_moves? or $check_score && b.won?
|
||||
b.print_score
|
||||
if b.no_more_moves?
|
||||
puts "No more moves possible"
|
||||
puts "Again? (y/n)"
|
||||
exit if STDIN.gets.chomp.downcase == "n"
|
||||
$check_score = true
|
||||
b.reset!
|
||||
puts "\e[H\e[2J"
|
||||
b.draw
|
||||
else
|
||||
puts "Continue? (y/n)"
|
||||
exit if STDIN.gets.chomp.downcase == "n"
|
||||
$check_score = false
|
||||
puts "\e[H\e[2J"
|
||||
b.draw
|
||||
end
|
||||
end
|
||||
end
|
||||
184
Task/2048/Rust/2048.rust
Normal file
184
Task/2048/Rust/2048.rust
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
use std::io::{self,BufRead};
|
||||
extern crate rand;
|
||||
|
||||
enum Usermove {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
fn print_game(field :& [[u32;4];4] ){
|
||||
println!("{:?}",&field[0] );
|
||||
println!("{:?}",&field[1] );
|
||||
println!("{:?}",&field[2] );
|
||||
println!("{:?}",&field[3] );
|
||||
}
|
||||
|
||||
fn get_usermove()-> Usermove {
|
||||
let umove: Usermove ;
|
||||
loop{
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
|
||||
match input.chars().nth(0){
|
||||
Some('a') =>{umove = Usermove::Left ;break },
|
||||
Some('w') =>{umove = Usermove::Up ;break },
|
||||
Some('s') =>{umove = Usermove::Down ;break },
|
||||
Some('d') =>{umove = Usermove::Right;break },
|
||||
_ => {println!("input was {}: invalid character should be a,s,w or d ",input.chars().nth(0).unwrap());} ,
|
||||
}
|
||||
}
|
||||
umove
|
||||
}
|
||||
|
||||
//this function inplements the user moves.
|
||||
//for every element it looks if the element is zero
|
||||
// if the element is zero it looks against the direction of the movement if any
|
||||
//element is not zero then it will move it to the element its place then it will look for
|
||||
//a matching element
|
||||
// if the element is not zero then it will look for a match if no match is found
|
||||
// then it will look for the next element
|
||||
|
||||
fn do_game_step(step : &Usermove, field:&mut [[u32;4];4]){
|
||||
match *step {
|
||||
Usermove::Left =>{
|
||||
for array in field{
|
||||
for col in 0..4 {
|
||||
for testcol in (col+1)..4 {
|
||||
if array[testcol] != 0 {
|
||||
if array[col] == 0 {
|
||||
array[col] += array[testcol];
|
||||
array[testcol] = 0;
|
||||
}
|
||||
else if array[col] == array[testcol] {
|
||||
array[col] += array[testcol];
|
||||
array[testcol] = 0;
|
||||
break;
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} ,
|
||||
Usermove::Right=>{
|
||||
for array in field{
|
||||
for col in (0..4).rev() {
|
||||
for testcol in (0..col).rev() {
|
||||
if array[testcol] != 0 {
|
||||
if array[col] == 0 {
|
||||
array[col] += array[testcol];
|
||||
array[testcol] = 0;
|
||||
}
|
||||
else if array[col] == array[testcol] {
|
||||
array[col] += array[testcol];
|
||||
array[testcol] = 0;
|
||||
break;
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} ,
|
||||
Usermove::Down =>{
|
||||
for col in 0..4 {
|
||||
for row in (0..4).rev() {
|
||||
for testrow in (0..row).rev() {
|
||||
if field[testrow][col] != 0 {
|
||||
if field[row][col] == 0 {
|
||||
field[row][col] += field[testrow][col];
|
||||
field[testrow][col] = 0;
|
||||
} else if field[row][col] == field[testrow][col] {
|
||||
field[row][col] += field[testrow][col];
|
||||
field[testrow][col] = 0;
|
||||
break;
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} ,
|
||||
Usermove::Up =>{
|
||||
for col in 0..4 {
|
||||
for row in 0..4{
|
||||
for testrow in (row+1)..4 {
|
||||
if field[testrow][col] != 0 {
|
||||
if field[row][col] == 0 {
|
||||
field[row][col] += field[testrow][col];
|
||||
field[testrow][col] = 0;
|
||||
} else if field[row][col] == field[testrow][col] {
|
||||
field[row][col] += field[testrow][col];
|
||||
field[testrow][col] = 0;
|
||||
break;
|
||||
}else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn( field: &mut [[u32;4];4]){
|
||||
loop{
|
||||
let x = rand::random::<usize>();
|
||||
if field[x % 4][(x/4)%4] == 0 {
|
||||
if x % 10 == 0 {
|
||||
field[x % 4][(x/4)%4]= 4;
|
||||
}else{
|
||||
field[x % 4][(x/4)%4]= 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut field : [[u32; 4];4] = [[0;4];4];
|
||||
let mut test : [[u32; 4];4] ;
|
||||
'gameloop:loop {
|
||||
//check if there is still an open space
|
||||
test=field.clone();
|
||||
spawn(&mut field);
|
||||
//if all possible moves do not yield a change then there is no valid move left
|
||||
//and it will be game over
|
||||
for i in [Usermove::Up,Usermove::Down,Usermove::Left,Usermove::Right].into_iter(){
|
||||
do_game_step(i, &mut test);
|
||||
if test != field{
|
||||
break;//found a valid move
|
||||
}
|
||||
match *i{
|
||||
Usermove::Right=> {
|
||||
println!("No more valid move, you lose");
|
||||
break 'gameloop;
|
||||
},
|
||||
_=>{},
|
||||
}
|
||||
}
|
||||
print_game(&field);
|
||||
println!("move the blocks");
|
||||
|
||||
test=field.clone();
|
||||
while test==field {
|
||||
do_game_step(&get_usermove(), &mut field);
|
||||
}
|
||||
|
||||
for row in field.iter(){
|
||||
if row.iter().any(|x| *x == 2048){
|
||||
print_game(&field );
|
||||
println!("You Won!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
193
Task/2048/Scala/2048.scala
Normal file
193
Task/2048/Scala/2048.scala
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
import java.awt.event.{KeyAdapter, KeyEvent, MouseAdapter, MouseEvent}
|
||||
import java.awt.{BorderLayout, Color, Dimension, Font, Graphics2D, Graphics, RenderingHints}
|
||||
import java.util.Random
|
||||
|
||||
import javax.swing.{JFrame, JPanel, SwingUtilities}
|
||||
|
||||
object Game2048 {
|
||||
val target = 2048
|
||||
var highest = 0
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
SwingUtilities.invokeLater(() => {
|
||||
val f = new JFrame
|
||||
f.setDefaultCloseOperation(3)
|
||||
f.setTitle("2048")
|
||||
f.add(new Game, BorderLayout.CENTER)
|
||||
f.pack()
|
||||
f.setLocationRelativeTo(null)
|
||||
f.setVisible(true)
|
||||
})
|
||||
}
|
||||
|
||||
class Game extends JPanel {
|
||||
private val (rand , side)= (new Random, 4)
|
||||
private var (tiles, gamestate)= (Array.ofDim[Tile](side, side), Game2048.State.start)
|
||||
|
||||
final private val colorTable =
|
||||
Seq(new Color(0x701710), new Color(0xFFE4C3), new Color(0xfff4d3), new Color(0xffdac3), new Color(0xe7b08e), new Color(0xe7bf8e),
|
||||
new Color(0xffc4c3), new Color(0xE7948e), new Color(0xbe7e56), new Color(0xbe5e56), new Color(0x9c3931), new Color(0x701710))
|
||||
|
||||
setPreferredSize(new Dimension(900, 700))
|
||||
setBackground(new Color(0xFAF8EF))
|
||||
setFont(new Font("SansSerif", Font.BOLD, 48))
|
||||
setFocusable(true)
|
||||
addMouseListener(new MouseAdapter() {
|
||||
override def mousePressed(e: MouseEvent): Unit = {
|
||||
startGame()
|
||||
repaint()
|
||||
}
|
||||
})
|
||||
addKeyListener(new KeyAdapter() {
|
||||
override def keyPressed(e: KeyEvent): Unit = {
|
||||
e.getKeyCode match {
|
||||
case KeyEvent.VK_UP => moveUp()
|
||||
case KeyEvent.VK_DOWN => moveDown()
|
||||
case KeyEvent.VK_LEFT => moveLeft()
|
||||
case KeyEvent.VK_RIGHT => moveRight()
|
||||
case _ =>
|
||||
}
|
||||
repaint()
|
||||
}
|
||||
})
|
||||
|
||||
override def paintComponent(gg: Graphics): Unit = {
|
||||
super.paintComponent(gg)
|
||||
val g = gg.asInstanceOf[Graphics2D]
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
|
||||
drawGrid(g)
|
||||
}
|
||||
|
||||
private def drawGrid(g: Graphics2D): Unit = {
|
||||
val (gridColor, emptyColor, startColor) = (new Color(0xBBADA0), new Color(0xCDC1B4), new Color(0xFFEBCD))
|
||||
|
||||
if (gamestate == State.running) {
|
||||
g.setColor(gridColor)
|
||||
g.fillRoundRect(200, 100, 499, 499, 15, 15)
|
||||
for (
|
||||
r <- 0 until side;
|
||||
c <- 0 until side
|
||||
) if (Option(tiles(r)(c)).isEmpty) {
|
||||
g.setColor(emptyColor)
|
||||
g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7)
|
||||
}
|
||||
else drawTile(g, r, c)
|
||||
} else {
|
||||
g.setColor(startColor)
|
||||
g.fillRoundRect(215, 115, 469, 469, 7, 7)
|
||||
g.setColor(gridColor.darker)
|
||||
g.setFont(new Font("SansSerif", Font.BOLD, 128))
|
||||
g.drawString("2048", 310, 270)
|
||||
g.setFont(new Font("SansSerif", Font.BOLD, 20))
|
||||
if (gamestate == Game2048.State.won) g.drawString("you made it!", 390, 350)
|
||||
else if (gamestate == Game2048.State.over) g.drawString("game over", 400, 350)
|
||||
g.setColor(gridColor)
|
||||
g.drawString("click to start a new game", 330, 470)
|
||||
g.drawString("(use arrow keys to move tiles)", 310, 530)
|
||||
}
|
||||
}
|
||||
|
||||
private def drawTile(g: Graphics2D, r: Int, c: Int): Unit = {
|
||||
val value = tiles(r)(c).value
|
||||
g.setColor(colorTable((math.log(value) / math.log(2)).toInt + 1))
|
||||
g.fillRoundRect(215 + c * 121, 115 + r * 121, 106, 106, 7, 7)
|
||||
g.setColor(if (value < 128) colorTable.head else colorTable(1))
|
||||
val (s , fm)= (value.toString, g.getFontMetrics)
|
||||
val asc = fm.getAscent
|
||||
val (x, y) = (215 + c * 121 + (106 - fm.stringWidth(s)) / 2,115 + r * 121 + (asc + (106 - (asc + fm.getDescent)) / 2))
|
||||
g.drawString(s, x, y)
|
||||
}
|
||||
|
||||
private def moveUp(checkingAvailableMoves: Boolean = false) = move(0, -1, 0, checkingAvailableMoves)
|
||||
|
||||
private def moveDown(checkingAvailableMoves: Boolean = false) = move(side * side - 1, 1, 0, checkingAvailableMoves)
|
||||
|
||||
private def moveLeft(checkingAvailableMoves: Boolean = false) = move(0, 0, -1, checkingAvailableMoves)
|
||||
|
||||
private def moveRight(checkingAvailableMoves: Boolean = false) = move(side * side - 1, 0, 1, checkingAvailableMoves)
|
||||
|
||||
private def clearMerged(): Unit = for (row <- tiles; tile <- row) if (Option(tile).isDefined) tile.setMerged()
|
||||
|
||||
private def movesAvailable() = moveUp(true) || moveDown(true) || moveLeft(true) || moveRight(true)
|
||||
|
||||
def move(countDownFrom: Int, yIncr: Int, xIncr: Int, checkingAvailableMoves: Boolean): Boolean = {
|
||||
var moved = false
|
||||
for (i <- 0 until side * side) {
|
||||
val j = math.abs(countDownFrom - i)
|
||||
var( r,c) = (j / side, j % side)
|
||||
if (Option(tiles(r)(c)).isDefined) {
|
||||
var (nextR, nextC, breek) = (r + yIncr, c + xIncr, false)
|
||||
while ((nextR >= 0 && nextR < side && nextC >= 0 && nextC < side) && !breek) {
|
||||
val (next, curr) = (tiles(nextR)(nextC),tiles(r)(c))
|
||||
if (Option(next).isEmpty)
|
||||
if (checkingAvailableMoves) return true
|
||||
else {
|
||||
tiles(nextR)(nextC) = curr
|
||||
tiles(r)(c) = null
|
||||
r = nextR
|
||||
c = nextC
|
||||
nextR += yIncr
|
||||
nextC += xIncr
|
||||
moved = true
|
||||
}
|
||||
else if (next.canMergeWith(curr)) {
|
||||
if (checkingAvailableMoves) return true
|
||||
Game2048.highest = math.max(next.mergeWith(curr), Game2048.highest)
|
||||
tiles(r)(c) = null
|
||||
breek = true
|
||||
moved = true
|
||||
} else breek = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (moved) if (Game2048.highest < Game2048.target) {
|
||||
clearMerged()
|
||||
addRandomTile()
|
||||
if (!movesAvailable) gamestate = State.over
|
||||
}
|
||||
else if (Game2048.highest == Game2048.target) gamestate = State.won
|
||||
moved
|
||||
}
|
||||
|
||||
private def startGame(): Unit = {
|
||||
if (gamestate ne Game2048.State.running) {
|
||||
Game2048.highest = 0
|
||||
gamestate = Game2048.State.running
|
||||
tiles = Array.ofDim[Tile](side, side)
|
||||
addRandomTile()
|
||||
addRandomTile()
|
||||
}
|
||||
}
|
||||
|
||||
private def addRandomTile(): Unit = {
|
||||
var pos = rand.nextInt(side * side)
|
||||
var (row, col) = (0, 0)
|
||||
do {
|
||||
pos = (pos + 1) % (side * side)
|
||||
row = pos / side
|
||||
col = pos % side
|
||||
} while (Option(tiles(row)(col)).isDefined)
|
||||
tiles(row)(col) = new Tile(if (rand.nextInt(10) == 0) 4 else 2)
|
||||
}
|
||||
|
||||
class Tile(var value: Int) {
|
||||
private var merged = false
|
||||
|
||||
def setMerged(): Unit = merged = false
|
||||
|
||||
def mergeWith(other: Tile): Int = if (canMergeWith(other)) {
|
||||
merged = true
|
||||
value *= 2
|
||||
value
|
||||
} else -1
|
||||
|
||||
def canMergeWith(other: Tile): Boolean = !merged && Option(other).isDefined && !other.merged && value == other.value
|
||||
}
|
||||
}
|
||||
|
||||
object State extends Enumeration {
|
||||
type State = Value
|
||||
val start, won, running, over = Value
|
||||
}
|
||||
|
||||
}
|
||||
190
Task/2048/Seed7/2048.seed7
Normal file
190
Task/2048/Seed7/2048.seed7
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
$ include "seed7_05.s7i";
|
||||
include "console.s7i";
|
||||
include "keybd.s7i";
|
||||
|
||||
const integer: boardLength is 4;
|
||||
const integer: boardSize is boardLength * boardLength;
|
||||
const integer: target is 2048;
|
||||
|
||||
const type: stateType is new struct
|
||||
var integer: fieldsOccupied is 0;
|
||||
var integer: largestNumber is 0;
|
||||
var integer: score is 0;
|
||||
var array array integer: board is boardLength times boardLength times 0;
|
||||
end struct;
|
||||
|
||||
const proc: addTile (inout stateType: state) is func
|
||||
local
|
||||
var integer: row is 0;
|
||||
var integer: col is 0;
|
||||
var integer: field is 2;
|
||||
begin
|
||||
if state.fieldsOccupied < boardSize then
|
||||
repeat
|
||||
col := rand(1, boardLength);
|
||||
row := rand(1, boardLength);
|
||||
until state.board[row][col] = 0;
|
||||
if rand(1, 10) = 10 then
|
||||
field := 4;
|
||||
end if;
|
||||
state.board[row][col] := field;
|
||||
incr(state.fieldsOccupied);
|
||||
state.largestNumber := max(field, state.largestNumber);
|
||||
end if;
|
||||
end func;
|
||||
|
||||
const proc: showBoard (in stateType: state) is func
|
||||
local
|
||||
var integer: row is 0;
|
||||
var integer: field is 0;
|
||||
begin
|
||||
writeln("┌────┬────┬────┬────┐");
|
||||
for key row range state.board do
|
||||
for field range state.board[row] do
|
||||
if field = 0 then
|
||||
write("│ ");
|
||||
else
|
||||
write("│" <& field lpad (5 + length(str(field))) div 2 rpad 4);
|
||||
end if;
|
||||
end for;
|
||||
writeln("│");
|
||||
if row < maxIdx(state.board) then
|
||||
writeln("├────┼────┼────┼────┤");
|
||||
end if;
|
||||
end for;
|
||||
writeln("└────┴────┴────┴────┘");
|
||||
end func;
|
||||
|
||||
const func boolean: doMove (inout stateType: state, in integer: startRow,
|
||||
in integer: startCol, in integer: deltaRow, in integer: deltaCol, in boolean: doMerge) is func
|
||||
result
|
||||
var boolean: boardChanged is FALSE;
|
||||
local
|
||||
const set of integer: boardRange is {1 .. boardLength};
|
||||
var integer: row is 1;
|
||||
var integer: col is 1;
|
||||
var integer: nextRow is 0;
|
||||
var integer: nextCol is 0;
|
||||
begin
|
||||
row := startRow;
|
||||
col := startCol;
|
||||
while row in boardRange and col in boardRange do
|
||||
while row in boardRange and col in boardRange do
|
||||
nextRow := row + deltaRow;
|
||||
nextCol := col + deltaCol;
|
||||
if state.board[row][col] = 0 and
|
||||
nextRow in boardRange and nextCol in boardRange and
|
||||
state.board[nextRow][nextCol] <> 0 then
|
||||
boardChanged := TRUE;
|
||||
state.board[row][col] := state.board[nextRow][nextCol];
|
||||
state.board[nextRow][nextCol] := 0;
|
||||
if row - deltaRow in boardRange and col - deltaCol in boardRange then
|
||||
nextRow := row - deltaRow;
|
||||
nextCol := col - deltaCol;
|
||||
end if;
|
||||
end if;
|
||||
row := nextRow;
|
||||
col := nextCol;
|
||||
end while;
|
||||
|
||||
if doMerge then
|
||||
if deltaRow <> 0 then
|
||||
row := startRow;
|
||||
elsif deltaCol <> 0 then
|
||||
col := startCol;
|
||||
end if;
|
||||
while row in boardRange and col in boardRange do
|
||||
nextRow := row + deltaRow;
|
||||
nextCol := col + deltaCol;
|
||||
if state.board[row][col] <> 0 and
|
||||
nextRow in boardRange and nextCol in boardRange and
|
||||
state.board[nextRow][nextCol] = state.board[row][col] then
|
||||
boardChanged := TRUE;
|
||||
state.board[row][col] *:= 2;
|
||||
state.largestNumber := max(state.board[row][col], state.largestNumber);
|
||||
state.score +:= state.board[row][col];
|
||||
state.board[nextRow][nextCol] := 0;
|
||||
decr(state.fieldsOccupied);
|
||||
end if;
|
||||
row := nextRow;
|
||||
col := nextCol;
|
||||
end while;
|
||||
end if;
|
||||
|
||||
if deltaRow = 0 then
|
||||
incr(row);
|
||||
col := startCol;
|
||||
elsif deltaCol = 0 then
|
||||
incr(col);
|
||||
row := startRow;
|
||||
end if;
|
||||
end while;
|
||||
if doMerge and boardChanged then
|
||||
ignore(doMove(state, startRow, startCol, deltaRow, deltaCol, FALSE));
|
||||
end if;
|
||||
end func;
|
||||
|
||||
const func boolean: canMove (in stateType: state) is func
|
||||
result
|
||||
var boolean: canMove is FALSE;
|
||||
local
|
||||
var integer: row is 0;
|
||||
var integer: col is 0;
|
||||
begin
|
||||
for row range 1 to boardLength until canMove do
|
||||
for col range 1 to boardLength until canMove do
|
||||
canMove := state.board[row][col] = 0 or
|
||||
(row < boardLength and state.board[row][col] = state.board[succ(row)][col]) or
|
||||
(col < boardLength and state.board[row][col] = state.board[row][succ(col)]);
|
||||
end for;
|
||||
end for;
|
||||
end func;
|
||||
|
||||
const proc: main is func
|
||||
local
|
||||
var stateType: state is stateType.value;
|
||||
var integer: highscore is 0;
|
||||
var char: command is ' ';
|
||||
var boolean: quit is FALSE;
|
||||
var boolean: moveOkay is FALSE;
|
||||
begin
|
||||
OUT := open(CONSOLE);
|
||||
addTile(state);
|
||||
repeat
|
||||
setPos(STD_CONSOLE, 1, 1);
|
||||
showBoard(state);
|
||||
highscore := max(highscore, state.score);
|
||||
writeln("Score = " <& state.score <& " Highscore = " <& highscore);
|
||||
if canMove(state) and state.largestNumber < target then
|
||||
writeln("Press arrow keys to move, R to Restart, Q to Quit");
|
||||
elsif state.largestNumber >= target then
|
||||
writeln("You win! Press R to Restart, Q to Quit ");
|
||||
else
|
||||
writeln("Game over! Press R to Restart, Q to Quit ");
|
||||
end if;
|
||||
repeat
|
||||
moveOkay := FALSE;
|
||||
command := getc(KEYBOARD);
|
||||
case command of
|
||||
when {'r', 'R'}:
|
||||
state := stateType.value;
|
||||
clear(STD_CONSOLE);
|
||||
moveOkay := TRUE;
|
||||
when {'q', 'Q'}:
|
||||
moveOkay := TRUE;
|
||||
quit := TRUE;
|
||||
when {KEY_LEFT}:
|
||||
moveOkay := doMove(state, 1, 1, 0, 1, TRUE);
|
||||
when {KEY_RIGHT}:
|
||||
moveOkay := doMove(state, 1, boardLength, 0, -1, TRUE);
|
||||
when {KEY_UP}:
|
||||
moveOkay := doMove(state, 1, 1, 1, 0, TRUE);
|
||||
when {KEY_DOWN}:
|
||||
moveOkay := doMove(state, boardLength, 1, -1, 0, TRUE);
|
||||
end case;
|
||||
if moveOkay and not quit then
|
||||
addTile(state);
|
||||
end if;
|
||||
until moveOkay;
|
||||
until quit;
|
||||
end func;
|
||||
276
Task/2048/Tcl/2048.tcl
Normal file
276
Task/2048/Tcl/2048.tcl
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
# A minimal implementation of the game 2048 in Tcl.
|
||||
# For a maintained version with expanded functionality see
|
||||
# https://tcl.wiki/40557.
|
||||
package require Tcl 8.5
|
||||
package require struct::matrix
|
||||
package require struct::list
|
||||
|
||||
# Board size.
|
||||
set size 4
|
||||
|
||||
# Iterate over all cells of the game board and run script for each.
|
||||
#
|
||||
# The game board is a 2D matrix of a fixed size that consists of elements
|
||||
# called "cells" that each can contain a game tile (corresponds to numerical
|
||||
# values of 2, 4, 8, ..., 2048) or nothing (zero).
|
||||
#
|
||||
# - cellList is a list of cell indexes (coordinates), which are
|
||||
# themselves lists of two numbers each. They each represent the location
|
||||
# of a given cell on the board.
|
||||
# - varName1 are varName2 are names of the variables the will be assigned
|
||||
# the index values.
|
||||
# - cellVarName is the name of the variable that at each step of iteration
|
||||
# will contain the numerical value of the present cell. Assigning to it will
|
||||
# change the cell's value.
|
||||
# - script is the script to run.
|
||||
proc forcells {cellList varName1 varName2 cellVarName script} {
|
||||
upvar $varName1 i
|
||||
upvar $varName2 j
|
||||
upvar $cellVarName c
|
||||
foreach cell $cellList {
|
||||
set i [lindex $cell 0]
|
||||
set j [lindex $cell 1]
|
||||
set c [cell-get $cell]
|
||||
uplevel $script
|
||||
cell-set "$i $j" $c
|
||||
}
|
||||
}
|
||||
|
||||
# Generate a list of cell indexes for all cells on the board, i.e.,
|
||||
# {{0 0} {0 1} ... {0 size-1} {1 0} {1 1} ... {size-1 size-1}}.
|
||||
proc cell-indexes {} {
|
||||
global size
|
||||
set list {}
|
||||
foreach i [::struct::list iota $size] {
|
||||
foreach j [::struct::list iota $size] {
|
||||
lappend list [list $i $j]
|
||||
}
|
||||
}
|
||||
return $list
|
||||
}
|
||||
|
||||
# Check if a number is a valid cell index (is 0 to size-1).
|
||||
proc valid-index {i} {
|
||||
global size
|
||||
expr {0 <= $i && $i < $size}
|
||||
}
|
||||
|
||||
# Return 1 if the predicate pred is true when applied to all items on the list
|
||||
# or 0 otherwise.
|
||||
proc map-and {list pred} {
|
||||
set res 1
|
||||
foreach item $list {
|
||||
set res [expr {$res && [$pred $item]}]
|
||||
if {! $res} break
|
||||
}
|
||||
return $res
|
||||
}
|
||||
|
||||
# Check if list represents valid cell coordinates.
|
||||
proc valid-cell? cell {
|
||||
map-and $cell valid-index
|
||||
}
|
||||
|
||||
# Get the value of a game board cell.
|
||||
proc cell-get cell {
|
||||
board get cell {*}$cell
|
||||
}
|
||||
|
||||
# Set the value of a game board cell.
|
||||
proc cell-set {cell value} {
|
||||
board set cell {*}$cell $value
|
||||
}
|
||||
|
||||
# Filter a list of board cell indexes cellList to only have those indexes
|
||||
# that correspond to empty board cells.
|
||||
proc empty {cellList} {
|
||||
::struct::list filterfor x $cellList {[cell-get $x] == 0}
|
||||
}
|
||||
|
||||
# Pick a random item from the given list.
|
||||
proc pick list {
|
||||
lindex $list [expr {int(rand() * [llength $list])}]
|
||||
}
|
||||
|
||||
# Put a "2" into an empty cell on the board.
|
||||
proc spawn-new {} {
|
||||
set emptyCell [pick [empty [cell-indexes]]]
|
||||
if {[llength $emptyCell] > 0} {
|
||||
forcells [list $emptyCell] i j cell {
|
||||
set cell 2
|
||||
}
|
||||
}
|
||||
return $emptyCell
|
||||
}
|
||||
|
||||
# Return vector sum of lists v1 and v2.
|
||||
proc vector-add {v1 v2} {
|
||||
set result {}
|
||||
foreach a $v1 b $v2 {
|
||||
lappend result [expr {$a + $b}]
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
# If checkOnly is false try to shift all cells one step in the direction of
|
||||
# directionVect. If checkOnly is true just say if that move is possible.
|
||||
proc move-all {directionVect {checkOnly 0}} {
|
||||
set changedCells 0
|
||||
|
||||
forcells [cell-indexes] i j cell {
|
||||
set newIndex [vector-add "$i $j" $directionVect]
|
||||
set removedStar 0
|
||||
|
||||
# For every nonempty source cell and valid destination cell...
|
||||
if {$cell != 0 && [valid-cell? $newIndex]} {
|
||||
if {[cell-get $newIndex] == 0} {
|
||||
# Destination is empty.
|
||||
if {$checkOnly} {
|
||||
# -level 2 is to return from both forcells and move-all.
|
||||
return -level 2 true
|
||||
} else {
|
||||
# Move tile to empty cell.
|
||||
cell-set $newIndex $cell
|
||||
set cell 0
|
||||
incr changedCells
|
||||
}
|
||||
} elseif {([cell-get $newIndex] eq $cell) &&
|
||||
[string first + $cell] == -1} {
|
||||
# Destination is the same number as source.
|
||||
if {$checkOnly} {
|
||||
return -level 2 true
|
||||
} else {
|
||||
# When merging two tiles into one mark the new tile with
|
||||
# the marker of "+" to ensure it doesn't get combined
|
||||
# again this turn.
|
||||
cell-set $newIndex [expr {2 * $cell}]+
|
||||
set cell 0
|
||||
incr changedCells
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {$checkOnly} {
|
||||
return false
|
||||
}
|
||||
|
||||
# Remove "changed this turn" markers at the end of the turn.
|
||||
if {$changedCells == 0} {
|
||||
forcells [cell-indexes] i j cell {
|
||||
set cell [string trim $cell +]
|
||||
}
|
||||
}
|
||||
return $changedCells
|
||||
}
|
||||
|
||||
# Is it possible to move any tiles in the direction of directionVect?
|
||||
proc can-move? {directionVect} {
|
||||
move-all $directionVect 1
|
||||
}
|
||||
|
||||
# Check win condition. The player wins when there's a 2048 tile.
|
||||
proc check-win {} {
|
||||
forcells [cell-indexes] i j cell {
|
||||
if {$cell == 2048} {
|
||||
puts "You win!"
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check lose condition. The player loses when the win condition isn't met and
|
||||
# there are no possible moves.
|
||||
proc check-lose {possibleMoves} {
|
||||
set values [dict values $possibleMoves]
|
||||
if {!(true in $values || 1 in $values)} {
|
||||
puts "You lose."
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# Pretty-print the board. Specify an index in highlight to highlight a cell.
|
||||
proc print-board {{highlight {-1 -1}}} {
|
||||
forcells [cell-indexes] i j cell {
|
||||
if {$j == 0} {
|
||||
puts ""
|
||||
}
|
||||
puts -nonewline [
|
||||
if {$cell != 0} {
|
||||
if {[::struct::list equal "$i $j" $highlight]} {
|
||||
format "\[%4s\]" $cell*
|
||||
} else {
|
||||
format "\[%4s\]" $cell
|
||||
}
|
||||
|
||||
} else {
|
||||
lindex "......"
|
||||
}
|
||||
]
|
||||
}
|
||||
puts "\n"
|
||||
}
|
||||
|
||||
proc main {} {
|
||||
global size
|
||||
|
||||
struct::matrix board
|
||||
|
||||
# Generate an empty board of a given size.
|
||||
board add columns $size
|
||||
board add rows $size
|
||||
forcells [cell-indexes] i j cell {
|
||||
set cell 0
|
||||
}
|
||||
|
||||
set controls {
|
||||
h {0 -1}
|
||||
j {1 0}
|
||||
k {-1 0}
|
||||
l {0 1}
|
||||
}
|
||||
|
||||
# Game loop.
|
||||
while true {
|
||||
set playerMove 0
|
||||
set possibleMoves {}
|
||||
|
||||
# Add new tile to the board and print the board highlighting this tile.
|
||||
print-board [spawn-new]
|
||||
|
||||
check-win
|
||||
|
||||
# Find possible moves.
|
||||
foreach {button vector} $controls {
|
||||
dict set possibleMoves $button [can-move? $vector]
|
||||
}
|
||||
check-lose $possibleMoves
|
||||
|
||||
# Get valid input from the player.
|
||||
while {$playerMove == 0} {
|
||||
# Print prompt.
|
||||
puts -nonewline "Move ("
|
||||
foreach {button vector} $controls {
|
||||
if {[dict get $possibleMoves $button]} {
|
||||
puts -nonewline $button
|
||||
}
|
||||
}
|
||||
puts ")?"
|
||||
|
||||
set playerInput [gets stdin]
|
||||
|
||||
# Validate input.
|
||||
if {[dict exists $possibleMoves $playerInput] &&
|
||||
[dict get $possibleMoves $playerInput]} {
|
||||
set playerMove [dict get $controls $playerInput]
|
||||
}
|
||||
}
|
||||
|
||||
# Apply current move until no changes occur on the board.
|
||||
while true {
|
||||
if {[move-all $playerMove] == 0} break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main
|
||||
239
Task/2048/Visual-Basic-.NET/2048.vb
Normal file
239
Task/2048/Visual-Basic-.NET/2048.vb
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
Friend Class Tile
|
||||
Public Sub New()
|
||||
Me.Value = 0
|
||||
Me.IsBlocked = False
|
||||
End Sub
|
||||
Public Property Value As Integer
|
||||
Public Property IsBlocked As Boolean
|
||||
End Class
|
||||
|
||||
Friend Enum MoveDirection
|
||||
Up
|
||||
Down
|
||||
Left
|
||||
Right
|
||||
End Enum
|
||||
|
||||
Friend Class G2048
|
||||
Public Sub New()
|
||||
_isDone = False
|
||||
_isWon = False
|
||||
_isMoved = True
|
||||
_score = 0
|
||||
InitializeBoard()
|
||||
End Sub
|
||||
|
||||
Private Sub InitializeBoard()
|
||||
For y As Integer = 0 To 3
|
||||
For x As Integer = 0 To 3
|
||||
_board(x, y) = New Tile()
|
||||
Next
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Private _isDone As Boolean
|
||||
Private _isWon As Boolean
|
||||
Private _isMoved As Boolean
|
||||
Private _score As Integer
|
||||
Private ReadOnly _board As Tile(,) = New Tile(3, 3) {}
|
||||
Private ReadOnly _rand As Random = New Random()
|
||||
Const empty As String = " "
|
||||
|
||||
Public Sub [Loop]()
|
||||
AddTile()
|
||||
While True
|
||||
If _isMoved Then AddTile()
|
||||
DrawBoard()
|
||||
If _isDone Then Exit While
|
||||
WaitKey()
|
||||
End While
|
||||
Dim endMessage As String = If(_isWon, "You've made it!", "Game Over!")
|
||||
Console.WriteLine(endMessage)
|
||||
End Sub
|
||||
|
||||
Public Sub DrawBoard()
|
||||
Console.Clear()
|
||||
Console.WriteLine("Score: " & _score & vbNewLine)
|
||||
For y As Integer = 0 To 3
|
||||
Console.WriteLine("+------+------+------+------+")
|
||||
Console.Write("| ")
|
||||
For x As Integer = 0 To 3
|
||||
If _board(x, y).Value = 0 Then
|
||||
Console.Write(empty.PadRight(4))
|
||||
Else
|
||||
Console.Write(_board(x, y).Value.ToString().PadRight(4))
|
||||
End If
|
||||
Console.Write(" | ")
|
||||
Next
|
||||
Console.WriteLine()
|
||||
Next
|
||||
Console.WriteLine("+------+------+------+------+" & vbNewLine & vbNewLine)
|
||||
End Sub
|
||||
|
||||
Private Sub WaitKey()
|
||||
_isMoved = False
|
||||
Console.WriteLine("(W) Up (S) Down (A) Left (D) Right")
|
||||
Dim input As Char
|
||||
Char.TryParse(Console.ReadKey().Key.ToString(), input)
|
||||
Select Case input
|
||||
Case "W"c
|
||||
Move(MoveDirection.Up)
|
||||
Case "A"c
|
||||
Move(MoveDirection.Left)
|
||||
Case "S"c
|
||||
Move(MoveDirection.Down)
|
||||
Case "D"c
|
||||
Move(MoveDirection.Right)
|
||||
End Select
|
||||
For y As Integer = 0 To 3
|
||||
For x As Integer = 0 To 3
|
||||
_board(x, y).IsBlocked = False
|
||||
Next
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Private Sub AddTile()
|
||||
For y As Integer = 0 To 3
|
||||
For x As Integer = 0 To 3
|
||||
If _board(x, y).Value <> 0 Then Continue For
|
||||
Dim a As Integer, b As Integer
|
||||
Do
|
||||
a = _rand.Next(0, 4)
|
||||
b = _rand.Next(0, 4)
|
||||
Loop While _board(a, b).Value <> 0
|
||||
Dim r As Double = _rand.NextDouble()
|
||||
_board(a, b).Value = If(r > 0.89F, 4, 2)
|
||||
If CanMove() Then Return
|
||||
Next
|
||||
Next
|
||||
_isDone = True
|
||||
End Sub
|
||||
|
||||
Private Function CanMove() As Boolean
|
||||
For y As Integer = 0 To 3
|
||||
For x As Integer = 0 To 3
|
||||
If _board(x, y).Value = 0 Then Return True
|
||||
Next
|
||||
Next
|
||||
For y As Integer = 0 To 3
|
||||
For x As Integer = 0 To 3
|
||||
If TestAdd(x + 1, y, _board(x, y).Value) OrElse TestAdd(x - 1, y, _board(x, y).Value) OrElse TestAdd(x, y + 1, _board(x, y).Value) OrElse TestAdd(x, y - 1, _board(x, y).Value) Then Return True
|
||||
Next
|
||||
Next
|
||||
Return False
|
||||
End Function
|
||||
|
||||
Private Function TestAdd(ByVal x As Integer, ByVal y As Integer, ByVal value As Integer) As Boolean
|
||||
If x < 0 OrElse x > 3 OrElse y < 0 OrElse y > 3 Then Return False
|
||||
Return _board(x, y).Value = value
|
||||
End Function
|
||||
|
||||
Private Sub MoveVertically(ByVal x As Integer, ByVal y As Integer, ByVal d As Integer)
|
||||
If _board(x, y + d).Value <> 0 AndAlso _board(x, y + d).Value = _board(x, y).Value AndAlso Not _board(x, y).IsBlocked AndAlso Not _board(x, y + d).IsBlocked Then
|
||||
_board(x, y).Value = 0
|
||||
_board(x, y + d).Value *= 2
|
||||
_score += _board(x, y + d).Value
|
||||
_board(x, y + d).IsBlocked = True
|
||||
_isMoved = True
|
||||
ElseIf _board(x, y + d).Value = 0 AndAlso _board(x, y).Value <> 0 Then
|
||||
_board(x, y + d).Value = _board(x, y).Value
|
||||
_board(x, y).Value = 0
|
||||
_isMoved = True
|
||||
End If
|
||||
If d > 0 Then
|
||||
If y + d < 3 Then MoveVertically(x, y + d, 1)
|
||||
Else
|
||||
If y + d > 0 Then MoveVertically(x, y + d, -1)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub MoveHorizontally(ByVal x As Integer, ByVal y As Integer, ByVal d As Integer)
|
||||
If _board(x + d, y).Value <> 0 AndAlso _board(x + d, y).Value = _board(x, y).Value AndAlso Not _board(x + d, y).IsBlocked AndAlso Not _board(x, y).IsBlocked Then
|
||||
_board(x, y).Value = 0
|
||||
_board(x + d, y).Value *= 2
|
||||
_score += _board(x + d, y).Value
|
||||
_board(x + d, y).IsBlocked = True
|
||||
_isMoved = True
|
||||
ElseIf _board(x + d, y).Value = 0 AndAlso _board(x, y).Value <> 0 Then
|
||||
_board(x + d, y).Value = _board(x, y).Value
|
||||
_board(x, y).Value = 0
|
||||
_isMoved = True
|
||||
End If
|
||||
If d > 0 Then
|
||||
If x + d < 3 Then MoveHorizontally(x + d, y, 1)
|
||||
Else
|
||||
If x + d > 0 Then MoveHorizontally(x + d, y, -1)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Move(ByVal direction As MoveDirection)
|
||||
Select Case direction
|
||||
Case MoveDirection.Up
|
||||
For x As Integer = 0 To 3
|
||||
Dim y As Integer = 1
|
||||
While y < 4
|
||||
If _board(x, y).Value <> 0 Then MoveVertically(x, y, -1)
|
||||
y += 1
|
||||
End While
|
||||
Next
|
||||
Case MoveDirection.Down
|
||||
For x As Integer = 0 To 3
|
||||
Dim y As Integer = 2
|
||||
While y >= 0
|
||||
If _board(x, y).Value <> 0 Then MoveVertically(x, y, 1)
|
||||
y -= 1
|
||||
End While
|
||||
Next
|
||||
Case MoveDirection.Left
|
||||
For y As Integer = 0 To 3
|
||||
Dim x As Integer = 1
|
||||
While x < 4
|
||||
If _board(x, y).Value <> 0 Then MoveHorizontally(x, y, -1)
|
||||
x += 1
|
||||
End While
|
||||
Next
|
||||
Case MoveDirection.Right
|
||||
For y As Integer = 0 To 3
|
||||
Dim x As Integer = 2
|
||||
While x >= 0
|
||||
If _board(x, y).Value <> 0 Then MoveHorizontally(x, y, 1)
|
||||
x -= 1
|
||||
End While
|
||||
Next
|
||||
End Select
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Module Module1
|
||||
Sub Main()
|
||||
RunGame()
|
||||
End Sub
|
||||
|
||||
Private Sub RunGame()
|
||||
Dim game As G2048 = New G2048()
|
||||
game.Loop()
|
||||
CheckRestart()
|
||||
End Sub
|
||||
|
||||
Private Sub CheckRestart()
|
||||
Console.WriteLine("(N) New game (P) Exit")
|
||||
While True
|
||||
Dim input As Char
|
||||
Char.TryParse(Console.ReadKey().Key.ToString(), input)
|
||||
Select Case input
|
||||
Case "N"c
|
||||
RunGame()
|
||||
Case "P"c
|
||||
Return
|
||||
Case Else
|
||||
ClearLastLine()
|
||||
End Select
|
||||
End While
|
||||
End Sub
|
||||
|
||||
Private Sub ClearLastLine()
|
||||
Console.SetCursorPosition(0, Console.CursorTop)
|
||||
Console.Write(New String(" ", Console.BufferWidth))
|
||||
Console.SetCursorPosition(0, Console.CursorTop - 1)
|
||||
End Sub
|
||||
End Module
|
||||
213
Task/2048/Wren/2048.wren
Normal file
213
Task/2048/Wren/2048.wren
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
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"])
|
||||
|
||||
var Tile = Struct.create("Tile", ["value", "isBlocked"])
|
||||
|
||||
class G2048 {
|
||||
construct new() {
|
||||
_isDone = false
|
||||
_isWon = false
|
||||
_isMoved = true
|
||||
_score = 0
|
||||
_board = List.filled(4, null)
|
||||
for (i in 0..3) {
|
||||
_board[i] = List.filled(4, null)
|
||||
for (j in 0..3) _board[i][j] = Tile.new(0, false)
|
||||
}
|
||||
_rand = Random.new()
|
||||
initializeBoard()
|
||||
}
|
||||
|
||||
initializeBoard() {
|
||||
for (y in 0..3) {
|
||||
for (x in 0..3) _board[x][y] = Tile.new(0, false)
|
||||
}
|
||||
}
|
||||
|
||||
loop() {
|
||||
addTile()
|
||||
while (true) {
|
||||
if (_isMoved) addTile()
|
||||
drawBoard()
|
||||
if (_isDone) break
|
||||
waitKey()
|
||||
}
|
||||
var endMessage = _isWon ? "You've made it!" : "Game Over!"
|
||||
System.print(endMessage)
|
||||
}
|
||||
|
||||
drawBoard() {
|
||||
System.print("\e[2J") // clear terminal
|
||||
System.print("Score: %(_score)\n")
|
||||
for (y in 0..3) {
|
||||
System.print("+------+------+------+------+")
|
||||
System.write("| ")
|
||||
for (x in 0..3) {
|
||||
if (_board[x][y].value == 0) {
|
||||
System.write(" ")
|
||||
} else {
|
||||
Fmt.write("$-4s", _board[x][y].value)
|
||||
}
|
||||
System.write(" | ")
|
||||
}
|
||||
System.print()
|
||||
}
|
||||
System.print("+------+------+------+------+\n\n")
|
||||
}
|
||||
|
||||
waitKey() {
|
||||
_isMoved = false
|
||||
var input = Str.upper(Input.option("(W) Up (S) Down (A) Left (D) Right: ", "WSADwsad"))
|
||||
if (input == "W") {
|
||||
move(MoveDirection.up)
|
||||
} else if (input == "A") {
|
||||
move(MoveDirection.left)
|
||||
} else if (input == "S") {
|
||||
move(MoveDirection.down)
|
||||
} else if (input == "D") {
|
||||
move(MoveDirection.right)
|
||||
}
|
||||
for (y in 0..3) {
|
||||
for (x in 0..3) _board[x][y].isBlocked = false
|
||||
}
|
||||
}
|
||||
|
||||
addTile() {
|
||||
for (y in 0..3) {
|
||||
for (x in 0..3) {
|
||||
if (_board[x][y].value != 0) continue
|
||||
var a
|
||||
var b
|
||||
while (true) {
|
||||
a = _rand.int(4)
|
||||
b = _rand.int(4)
|
||||
if (_board[a][b].value == 0) break
|
||||
}
|
||||
var r = _rand.float()
|
||||
_board[a][b].value = (r > 0.89) ? 4 : 2
|
||||
if (canMove()) return
|
||||
}
|
||||
}
|
||||
_isDone = true
|
||||
}
|
||||
|
||||
canMove() {
|
||||
for (y in 0..3) {
|
||||
for (x in 0..3) {
|
||||
if (_board[x][y].value == 0) return true
|
||||
}
|
||||
}
|
||||
|
||||
for (y in 0..3) {
|
||||
for (x in 0..3) {
|
||||
if (testAdd(x + 1, y, _board[x][y].value) ||
|
||||
testAdd(x - 1, y, _board[x][y].value) ||
|
||||
testAdd(x, y + 1, _board[x][y].value) ||
|
||||
testAdd(x, y - 1, _board[x][y].value)) return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
testAdd(x, y, value) {
|
||||
if (x < 0 || x > 3 || y < 0 || y > 3) return false
|
||||
return _board[x][y].value == value
|
||||
}
|
||||
|
||||
moveVertically(x, y, d) {
|
||||
if (_board[x][y + d].value != 0 &&
|
||||
_board[x][y + d].value == _board[x][y].value &&
|
||||
!_board[x][y].isBlocked &&
|
||||
!_board[x][y + d].isBlocked) {
|
||||
_board[x][y].value = 0
|
||||
_board[x][y + d].value = _board[x][y + d].value * 2
|
||||
_score = _score + _board[x][y + d].value
|
||||
_board[x][y + d].isBlocked = true
|
||||
_isMoved = true
|
||||
} else if (_board[x][y + d].value == 0 && _board[x][y].value != 0) {
|
||||
_board[x][y + d].value = _board[x][y].value
|
||||
_board[x][y].value = 0
|
||||
_isMoved = true
|
||||
}
|
||||
|
||||
if (d > 0) {
|
||||
if (y + d < 3) moveVertically(x, y + d, 1)
|
||||
} else {
|
||||
if (y + d > 0) moveVertically(x, y + d, -1)
|
||||
}
|
||||
}
|
||||
|
||||
moveHorizontally(x, y, d) {
|
||||
if (_board[x + d][y].value != 0 &&
|
||||
_board[x + d][y].value == _board[x][y].value &&
|
||||
!_board[x + d][y].isBlocked &&
|
||||
!_board[x][y].isBlocked) {
|
||||
_board[x][y].value = 0
|
||||
_board[x + d][y].value = _board[x + d][y].value * 2
|
||||
_score = _score + _board[x + d][y].value
|
||||
_board[x + d][y].isBlocked = true
|
||||
_isMoved = true
|
||||
} else if (_board[x + d][y].value == 0 && _board[x][y].value != 0) {
|
||||
_board[x + d][y].value = _board[x][y].value
|
||||
_board[x][y].value = 0
|
||||
_isMoved = true
|
||||
}
|
||||
|
||||
if (d > 0) {
|
||||
if (x + d < 3) moveHorizontally(x + d, y, 1)
|
||||
} else {
|
||||
if (x + d > 0) moveHorizontally(x + d, y, -1)
|
||||
}
|
||||
}
|
||||
|
||||
move(direction) {
|
||||
if (direction == MoveDirection.up) {
|
||||
for (x in 0..3) {
|
||||
for (y in 1..3) {
|
||||
if (_board[x][y].value != 0) moveVertically(x, y, -1)
|
||||
}
|
||||
}
|
||||
} else if (direction == MoveDirection.down) {
|
||||
for (x in 0..3) {
|
||||
for (y in 2..0) {
|
||||
if (_board[x][y].value != 0) moveVertically(x, y, 1)
|
||||
}
|
||||
}
|
||||
} else if (direction == MoveDirection.left) {
|
||||
for (y in 0..3) {
|
||||
for (x in 1..3) {
|
||||
if (_board[x][y].value != 0) moveHorizontally(x, y, -1)
|
||||
}
|
||||
}
|
||||
} else if (direction == MoveDirection.right) {
|
||||
for (y in 0..3) {
|
||||
for (x in 2..0) {
|
||||
if (_board[x][y].value != 0) moveHorizontally(x, y, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var runGame // forward declaration
|
||||
|
||||
var checkRestart = Fn.new {
|
||||
var input = Str.upper(Input.option("(N) New game (P) Exit: ", "NPnp"))
|
||||
if (input == "N") {
|
||||
runGame.call()
|
||||
} else if (input == "P") return
|
||||
}
|
||||
|
||||
runGame = Fn.new {
|
||||
var game = G2048.new()
|
||||
game.loop()
|
||||
checkRestart.call()
|
||||
}
|
||||
|
||||
runGame.call()
|
||||
61
Task/2048/XPL0/2048.xpl0
Normal file
61
Task/2048/XPL0/2048.xpl0
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
include c:\cxpl\codes; \intrinsic 'code' declarations
|
||||
int Box(16), Moved;
|
||||
|
||||
proc ShiftTiles(I0, DI); \Shift tiles, add adjacents, shift again
|
||||
int I0, DI;
|
||||
int Done, M, N, I;
|
||||
[Done:= false;
|
||||
loop [for M:= 1 to 3 do \shift all tiles in a single row or column
|
||||
[I:= I0;
|
||||
for N:= 1 to 3 do
|
||||
[if Box(I)=0 & Box(I+DI)#0 then
|
||||
[Box(I):= Box(I+DI); Box(I+DI):= 0; Moved:= true];
|
||||
I:= I+DI;
|
||||
];
|
||||
];
|
||||
if Done then return;
|
||||
Done:= true;
|
||||
I:= I0; \add identical adjacent tiles into a new tile
|
||||
for N:= 1 to 3 do
|
||||
[if Box(I)=Box(I+DI) & Box(I)#0 then
|
||||
[Box(I):= Box(I)+1; Box(I+DI):= 0; Moved:= true];
|
||||
I:= I+DI;
|
||||
];
|
||||
]; \loop back to close any gaps that were opened
|
||||
]; \ShiftTiles
|
||||
|
||||
int I, J, X, Y, C;
|
||||
[Clear;
|
||||
for I:= 0 to 15 do Box(I):= 0; \empty the box of tiles
|
||||
loop [repeat I:= Ran(16) until Box(I)=0; \in a random empty location
|
||||
Box(I):= if Ran(10) then 1 else 2; \insert a 2^1=2 or 2^2=4
|
||||
for I:= 0 to 15 do \show board with its tiles
|
||||
[X:= ((I&3)+5)*6; \get coordinates of tile
|
||||
Y:= I>>2*3+6;
|
||||
Attrib(((Box(I)+1)&7)<<4 + $F);\set color based on tile value
|
||||
for J:= 0 to 2 do \draw a square (6*8x3*16)
|
||||
[Cursor(X, Y+J);
|
||||
Text(6, " ");
|
||||
];
|
||||
if Box(I)#0 then \box contains a tile
|
||||
[J:= 1; \center numbers somewhat
|
||||
if Box(I) <= 9 then J:= 2;
|
||||
if Box(I) <= 3 then J:= 3;
|
||||
Cursor(X+J, Y+1);
|
||||
IntOut(6, 1<<Box(I));
|
||||
];
|
||||
];
|
||||
Moved:= false; \a tile must move to continue
|
||||
repeat repeat C:= ChIn(1) until C#0; \get key scan code, or ASCII
|
||||
for I:= 3 downto 0 do \for all rows or columns
|
||||
[case C of
|
||||
$4B: ShiftTiles(I*4, 1); \left arrow
|
||||
$4D: ShiftTiles(I*4+3, -1); \right arrow
|
||||
$50: ShiftTiles(I+12, -4); \down arrow
|
||||
$48: ShiftTiles(I, 4); \up arrow
|
||||
$1B: [Clear; exit] \Esc
|
||||
other []; \ignore all other keys
|
||||
];
|
||||
until Moved;
|
||||
];
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue