Pascal đã đc đưa vào chương trình học phổ thông với mục đích phát triển tư duy. Tuy nhiên nhiều người đã rất vất vã để vượt qua nó. Bởi vì các bạn không thích thú thôi. Suốt ngày cứ bắt giải phương trình bậc nhất, phương trình bậc hai, sắp xếp dãy số tăng dần, tìm ra phần tử lớn nhất hay nhỏ nhất chẳng hạn, bla.bla.. Và có 1 thực tế là, ai cũng chỉ biết đây là 1 môn bắt buộc và học thôi mà chẳng biết học như vậy thì ứng dụng vào thực tế đc gì nữa .?.?.?...

Hôm nay, mình sẽ cho các bạn thấy, chỉ với vài câu lệnh đơn giản mà các bạn đã đc học, nếu biết sáng tạo sử dụng nó sẽ tạo ra 1 trò chơi đơn giản như thế nào... Và còn nhiều hơn thế nữa...

Game này có ý tưởng từ game rắn săn mồi trên mấy cái điện thoại trắng đen ấy ^^. Chế biến lại trên Pascal như sau: mình sẽ dùng vòng lặp vô tận repeat...until để chạy, các vòng lặp cách nhau bằng một khoảng thời gian delay (100-300 miliseconds), kết hợp với sự điều khiển của người chơi bằng cách ấn các phím W A S D để điều khiển con rắn di chuyển lên, xuống, qua trái, qua phải; và tăng 1 điểm, tăng chiều dài rắn khi ăn đc 1 viên thức ăn. Chỉ đơn giản vậy thôi

K dài dòng nữa, bắt đầu thôi

Trước hết, khởi tạo các biến cần dùng
uses crt;
const width = 80; {Kích thước màn hình: TurboPascal 80x25 và FreePascal 120x30}
      height = 25;

      KeyList = ['a', 's', 'd', 'w', 'K', 'M', 'P', 'H']; { Các phím ấn hợp lệ}
      path = 'RANK-SNAKE-GAME.DAT';

type point = record  { Tọa độ 1 điểm trên màn hình (x, y): trục x từ trái sang phải, trục y từ trên xuống dưới, góc tọa độ (0, 0) là góc trên bên trái màn hình}
           x, y: byte;
         end;

     player = record  { Thông tin người chơi gồm: Tên và Điểm}
            name: string[50];
            score: word;
         end;

var body: array[0..10000] of point; { Body của Snake là 1 mảng Point}
    free: array[1..width,1..height] of boolean; { Điểm (x, y) mà snake không được di chuyển vào khi free[x,y]=false}
    rank: array[1..11] of player; { Bảng xếp hạng}
    food: point; { Thức ăn}
    you: player;
    level, i, j, n: word;
    hasFence: boolean;
    newKey, key, move: char;
    fi, fo: text;
    f: file;

Tiếp theo, tạo một vài hàm, thủ tục cần dùng trong chương trình

Hoán vị 2 player

procedure swap(var a, b: player); { Hoán vị 2 player}
var t: player;
begin
    t := a; a := b; b := t;
end;


Đọc dữ liệu bảng xếp hạng từ file

procedure readData; { Đọc dữ liệu bảng xếp hạng từ file}
begin
    { Kiểm tra nếu file không tồn tại thì tạo file trống (Tránh bị lỗi khi đọc)}
    assign(f, path);
    {$I-}
    reset(f);
    if ioresult <> 0 then rewrite(f);
    close(f);

    { Lưu dữ liệu đã đọc đc vào mảng Rank}
    assign(fi, path); reset(fi);
    for i:=1 to 10 do
    begin
        readln(fi, rank[i].name);
        readln(fi, rank[i].score);
    end;
    close(fi);
end;


Lưu dữ liệu bảng xếp hạng ra file

procedure writeData; { Lưu dữ liệu ra file sử dụng cho lần chơi sau}
begin
    assign(fo, path); rewrite(fo);
    for i:=1 to 10 do
    begin
        writeln(fo, rank[i].name);
        writeln(fo, rank[i].score);
    end;
    close(fo);
end;


Delay chương trình, ngăn cách các vòng lặp

procedure delayTime;  { delay(x) là tạm dừng chương trình x mili giây}
begin
    case level of
        1: delay(200);
        2: delay(100);
        3: delay(50);
        else delay(200);
    end;
end;


Hiển thị menu ra màn hình

procedure writeMenuText; { Hiển thị menu ra màn hình}
begin
    clrscr;
    writeln;
    writeln('Xin chao ban den voi game Ran san moi !');
    writeln;
    writeln('   [1] Choi ngay');
    writeln('   [2] Cai dat');
    writeln('   [3] Huong dan');
    writeln('   [4] Gioi thieu');
    writeln('   [5] Diem cao');
    writeln('   [6] Thoat');
    writeln;
    write('Chon: ');
    readln(key);
end;


Chọn mức độ chơi: Khó, Trung bình và Dễ

procedure writeChooseLevel;  { Chọn mức độ chơi}
begin
    clrscr;
    writeln;
    writeln('Chon muc do: ');
    writeln;
    writeln('   [1] De');
    writeln('   [2] Trung binh');
    writeln('   [3] Kho');
    writeln;
    writeln('An Enter neu muon quay lai Menu.');
    writeln;
    write('Ban chon muc do nao: ');
    readln(key);
    if key <> '' then level := ord(key) - 48 else level := 1;
end;


In bảng xếp hạng ra màn hình

procedure writeRank(startLine : integer); { In bảng xếp hạng ra màn hình}
begin
    writeln;
    writeln('     NAME                              SCORE');
    writeln;
    for i:=1 to 10 do
    begin
        write(i:2,'. ');
        writeln(rank[i].name);
        gotoxy(41, i+startLine);
        writeln(rank[i].score);
    end;
    writeln;
end;


Nhập tên người chơi

procedure writeInputName;   { Nhập tên người chơi}
begin
    clrscr;
    writeln;
    repeat
        write('Nhap ten nguoi choi: '); readln(you.name);
        if length(you.name)=0 then writeln('Vui long nhap lai!');
        writeln;
    until length(you.name) <> 0;
    writeln('An ENTER de Bat dau >>>');
    readln;
end;


Khởi tạo: hàng rào và con rắn trước lúc bắt đầu

procedure writeInit; {Khởi tạo trước khi bắt đầu chơi}
begin
    clrscr;
    fillchar(free, sizeof(free), true); { Toàn bộ mảng free đc khởi tạo là true}
    if hasFence then  { Tạo hàng rào}
    begin
        { Cạnh bên trái màn hình}
        for i:=1 to height-1 do
        begin
            writeln('#'); free[1,i]:=false;
        end;

        { Cạnh trên cùng màn hình}
        gotoxy(2,1);
        for i:=1 to width-1 do
        begin
            write('#'); free[i, 1]:=false;
        end;

        { Cạnh dưới cùng màn hình}
        gotoxy(2,height-1);
        for i:=1 to width-1 do
        begin
            write('#'); free[i, height-1]:=false;
        end;

        { Cạnh bên phải màn hình}
        for i:=1 to height-1 do
        begin
            gotoxy(width, i); write('#'); free[width, i]:=false;
        end;
    end else
    begin { Nếu không bật chế độ hàng rào thì chỉ có hàng rào ở cạnh dưới cùng}
	    gotoxy(1,height-1);
        for i:=1 to width do write('#');
    end;

    you.score:=0;

    { Khởi tạo body của Snake lúc ban đầu gồm 3 mắc xích}
    body[1].x:=39; body[1].y:=11; body[2].x:=40; body[2].y:=11; body[3].x:=41; body[3].y:=11;
    free[39,11]:=false; free[40,11]:=false;
    n:=3;

    { Vẽ Snake ra màn hình}
    gotoxy(body[1].x,body[1].y); write(char(9));
    gotoxy(body[2].x,body[2].y); write(char(9));
    gotoxy(body[3].x,body[3].y); write('+');

    gotoxy(1,height); write('Di chuyen: A S D W. An phim bat ky de Tam dung. "E" Ket thuc!');
    gotoxy(width-10,height); write('Diem:',0:5);

    move:='d';

    { Tạo thức ăn}
    food.x:=60; food.y:=11;
    gotoxy(60,11); write('*');
end;


Lấy tọa độ điểm B dựa vào tọa độ điểm ban đầu là A, và phím đang đc ấn là gì
Ví dụ: A(2,5) và người dùng ấn phím W, ta đc B(2,4)

{ Lấy tọa độ 1 điểm dựa vào điểm trước đó và hướng điều khiển}
{ K M P H lần lượt là các phím Left, Right, Down, Up}
procedure getNextPoint(currentPoint: point; move: char; var nextPoint: point);
begin
    nextPoint := currentPoint;
    case move of
      	'a', 'K': begin dec(nextPoint.x); end;
	    'd', 'M': begin inc(nextPoint.x); end;
	    's', 'P': begin inc(nextPoint.y); end;
		'w', 'H': begin dec(nextPoint.y); end;
	end;
end;


Cập nhật lại Snake

procedure updateSnake(move: char);  { Cập nhật Snake}
begin
    { Cập nhật lại body của Snake}
    getNextPoint(body[n], move, body[n+1]);
	for i:=0 to n do body[i] := body[i+1];

    { Kéo Snake vào màn hình khi di chuyển ra ngoài}
	if not hasFence then
	begin
        if body[n].x = 0 then body[n].x := width;
	    if body[n].x = width+1 then body[n].x := 1;
        if body[n].y = 0 then body[n].y := height-2;
	    if body[n].y = height-1 then body[n].y := 1;
	end;

    { Sau đó vẽ lại Snake ra màn hình}
	gotoxy(body[0].x, body[0].y); write(' '); free[body[0].x, body[0].y]:=true;
	gotoxy(body[n-1].x, body[n-1].y); write(char(9)); free[body[n-1].x,body[n-1].y]:=false;
	gotoxy(body[n].x, body[n].y); write('+');

    { Khi Snake ăn thức ăn}
	if (body[n].x=food.x) and (body[n].y=food.y) then
    begin
        { Tăng độ dài của Snake}
        inc(n);
        getNextPoint(body[n-1], move, body[n]);
	    gotoxy(body[n-1].x, body[n-1].y); write(char(9)); free[body[n-1].x, body[n-1].y]:=false;
	    gotoxy(body[n].x, body[n].y); write('+');

        inc(you.score);
        gotoxy(width-5,height); write(you.score:5);

        { Tạo 1 Food mới}
        repeat
	        food.x:=random(width-1-2)+2;
            food.y:=random(height-3-2)+2;
        until free[food.x,food.y];
        gotoxy(food.x,food.y); write('*');
	end;

    gotoxy(1, height-1); { Đưa con trỏ xuống dưới màn hình}
end;


Kết hợp các hàm và thủ tục phía trên lại, ta đc chương trình hoàn chỉnh
uses crt;
const width = 80; {Console Screen: TurboPascal 80x25, FreePascal 120x30}
      height = 25;

      KeyList = ['a', 's', 'd', 'w', 'K', 'M', 'P', 'H']; { Cac phim bam hop le}
      path = 'RANK-SNAKE-GAME.DAT';

type point = record  { Toa do 1 diem tren man hinh (x, y)}
           x, y: byte;
         end;

     player = record  { Thong tin 1 nguoi choi gom: ten va diem}
            name: string[50];
            score: word;
         end;

var body: array[0..10000] of point; { Snake la 1 mang point}
    free: array[1..width,1..height] of boolean; { Diem (x, y) ma snake khong duoc di chuyen vao khi free[x,y]=false}
    rank: array[1..11] of player; { Bang xep hang}
    food: point; { Thuc an}
    you: player;
    level, i, j, n: word;
    hasFence: boolean;
    newKey, key, move: char;
    fi, fo: text;
    f: file;

procedure swap(var a, b: player); { Hoan vi 2 player}
var t: player;
begin
    t := a; a := b; b := t;
end;

procedure readData; { Doc du lieu tu file}
begin
    { Kiem tra neu file chua duoc tao thi tao file moi (Tranh bi loi khi doc du lieu)}
    assign(f, path);
    {$I-}
    reset(f);
    if ioresult <> 0 then rewrite(f);
    close(f);

    { Doc du lieu luu vao mang Rank}
    assign(fi, path); reset(fi);
    for i:=1 to 10 do
    begin
        readln(fi, rank[i].name);
        readln(fi, rank[i].score);
    end;
    close(fi);
end;

procedure writeData; { Luu du lieu ra file su dung cho lan choi sau}
begin
    assign(fo, path); rewrite(fo);
    for i:=1 to 10 do
    begin
        writeln(fo, rank[i].name);
        writeln(fo, rank[i].score);
    end;
    close(fo);
end;



procedure delayTime;  { delay(x) la tam dung chuong trinh x mili giay}
begin
    case level of
        1: delay(200);
        2: delay(100);
        3: delay(50);
        else delay(200);
    end;
end;

procedure writeMenuText; { In Menu ra man hinh}
begin
    clrscr;
    writeln;
    writeln('Xin chao ban den voi game Ran san moi !');
    writeln;
    writeln('   [1] Choi ngay');
    writeln('   [2] Cai dat');
    writeln('   [3] Huong dan');
    writeln('   [4] Gioi thieu');
    writeln('   [5] Diem cao');
    writeln('   [6] Thoat');
    writeln;
    write('Chon: ');
    readln(key);
end;


procedure writeChooseLevel;  { Chon muc do}
begin
    clrscr;
    writeln;
    writeln('Chon muc do: ');
    writeln;
    writeln('   [1] De');
    writeln('   [2] Trung binh');
    writeln('   [3] Kho');
    writeln;
    writeln('An Enter neu muon quay lai Menu.');
    writeln;
    write('Ban chon muc do nao: ');
    readln(key);
    if key <> '' then level := ord(key) - 48 else level := 1;
end;

procedure writeInit; { Khoi tao truoc khi bat dau play}
begin
    clrscr;
    fillchar(free, sizeof(free), true); { Toan bo mang free dc khoi tao la true}
    if hasFence then  { Tao hang rao}
    begin
        { Canh ben trai man hinh}
        for i:=1 to height-1 do
        begin
            writeln('#'); free[1,i]:=false;
        end;

        { Canh ben tren man hinh}
        gotoxy(2,1);
        for i:=1 to width-1 do
        begin
            write('#'); free[i, 1]:=false;
        end;

        { Canh ben duoi man hinh}
        gotoxy(2,height-1);
        for i:=1 to width-1 do
        begin
            write('#'); free[i, height-1]:=false;
        end;

        { Canh ben phai man hinh}
        for i:=1 to height-1 do
        begin
            gotoxy(width, i); write('#'); free[width, i]:=false;
        end;
    end else
    begin { Neu khong bat che do hang rao thi chi tao canh ben duoi}
	    gotoxy(1,height-1);
        for i:=1 to width do write('#');
    end;

    you.score:=0;

    { Khoi tao Snake}
    body[1].x:=39; body[1].y:=11; body[2].x:=40; body[2].y:=11; body[3].x:=41; body[3].y:=11;
    free[39,11]:=false; free[40,11]:=false;
    n:=3;

    { Ve Snake ra man hinh}
    gotoxy(body[1].x,body[1].y); write(char(9));
    gotoxy(body[2].x,body[2].y); write(char(9));
    gotoxy(body[3].x,body[3].y); write('+');

    gotoxy(1,height); write('Di chuyen: A S D W. An phim bat ky de Tam dung. "E" Ket thuc!');
    gotoxy(width-10,height); write('Diem:',0:5);

    move:='d';

    { Tao thuc an}
    food.x:=60; food.y:=11;
    gotoxy(60,11); write('*');
end;

procedure writeRank(startLine : integer); { In bang xep hang ra man hinh}
begin
    writeln;
    writeln('     NAME                              SCORE');
    writeln;
    for i:=1 to 10 do
    begin
        write(i:2,'. ');
        writeln(rank[i].name);
        gotoxy(41, i+startLine);
        writeln(rank[i].score);
    end;
    writeln;
end;

procedure writeInputName;   { Nhap ten nguoi choi}
begin
    clrscr;
    writeln;
    repeat
        write('Nhap ten nguoi choi: '); readln(you.name);
        if length(you.name)=0 then writeln('Vui long nhap lai!');
        writeln;
    until length(you.name) <> 0;
    writeln('An ENTER de Bat dau >>>');
    readln;
end;

{ Lay 1 point moi dua vao point truoc do, khi player an 1 phim tren ban phim}
{ K M P H lan luot la cac phim Left, Right, Down, Up}
procedure getNextPoint(currentPoint: point; move: char; var nextPoint: point);
begin
    nextPoint := currentPoint;
    case move of
      	'a', 'K': begin dec(nextPoint.x); end;
	    'd', 'M': begin inc(nextPoint.x); end;
	    's', 'P': begin inc(nextPoint.y); end;
		'w', 'H': begin dec(nextPoint.y); end;
	end;
end;

procedure updateSnake(move: char);  { Cap nhat Snake}
begin
    { Cap nhat lai mang toa do cua Snack}
    getNextPoint(body[n], move, body[n+1]);
	for i:=0 to n do body[i] := body[i+1];

    { Keo snake vao trong man hinh khi di chuyen ra ngoai}
	if not hasFence then
	begin
        if body[n].x = 0 then body[n].x := width;
	    if body[n].x = width+1 then body[n].x := 1;
        if body[n].y = 0 then body[n].y := height-2;
	    if body[n].y = height-1 then body[n].y := 1;
	end;

    { Sau do ve lai Snake ra man hinh}
	gotoxy(body[0].x, body[0].y); write(' '); free[body[0].x, body[0].y]:=true;
	gotoxy(body[n-1].x, body[n-1].y); write(char(9)); free[body[n-1].x,body[n-1].y]:=false;
	gotoxy(body[n].x, body[n].y); write('+');

    { Khi Snake an Thuc an}
	if (body[n].x=food.x) and (body[n].y=food.y) then
    begin
        { Tang do dai cua Snake}
        inc(n);
        getNextPoint(body[n-1], move, body[n]);
	    gotoxy(body[n-1].x, body[n-1].y); write(char(9)); free[body[n-1].x, body[n-1].y]:=false;
	    gotoxy(body[n].x, body[n].y); write('+');

        inc(you.score);
        gotoxy(width-5,height); write(you.score:5);

        { Tao 1 Food moi}
        repeat
	        food.x:=random(width-1-2)+2;
            food.y:=random(height-3-2)+2;
        until free[food.x,food.y];
        gotoxy(food.x,food.y); write('*');
	end;

    gotoxy(1, height-1); { Dua con tro xuong duoi man hinh de nhin dep hon}
end;

procedure menu;
begin
    writeMenuText; { In Menu ra man hinh}
    case key of
        '1': begin
            writeChooseLevel; { Chon muc do}
		    if key='' then menu;

		    writeInputName; { Nhap ten}
            writeInit; { Khoi tao}

            repeat
                delayTime;  { Tam dung chuong trinh}
                if keypressed then move:=readkey;       { Neu an 1 phim hop le thi cap nhat lai}
		        if move in KeyList then updateSnake(move);
            until (not free[body[n].x,body[n].y]) or (move='e'); { Game over khi head cham vao body}

            { Sap xep lai bang xep hang va luu vao file}
            rank[11].score:=you.score;
            rank[11].name:= you.name;
            for i:=1 to 10 do
                for j:=i+1 to 11 do
                    if rank[i].score < rank[j].score then swap(rank[i], rank[j]);
            writeData;

            { In bang xep hang ra man hinh}
            delay(1000);
            clrscr;
            writeln;
            writeln('Chuc mung ', you.name, '. Ban nhan duoc ', you.score, ' diem !');
            writeRank(5);
            writeln('An ENTER de quay lai Menu');
            readln;
            menu;
        end;

        '2': begin { Cai dat}
            clrscr;
            writeln;
            writeln('Che do Hang rao:');
            writeln;
            writeln('   [1] Bat');
            writeln('   [2] Tat');
            writeln;
            write('Chon: ');
            readln(key);
            writeln;

            if key='1' then begin writeln('Ban da Bat che do hang rao!'); hasFence:=true; end
                else begin writeln('Ban da Tat che do hang rao!'); hasFence:=false; end;

            writeln;
            writeln('An Enter de quay lai Menu');
            readln;
            menu;
        end;

        '3': begin { Huong dan}
            clrscr;
            writeln;
            writeln('   Dung cac phim: A (trai), D (phai), W (len), S (xuong) de dieu khien');
            writeln('chu ran di chuyen. Hay co gang an that nhieu thuc an de dat diem cao nhat.');
            writeln('Chuc ban may man!!!');
            writeln;
            writeln('An Enter de quay lai Menu.');
            readln;
            menu;
        end;

        '4': begin  { Thong tin tac gia}
            clrscr;
            writeln;
            writeln('Written by: Tran Huu Nhiem !!!');
            writeln;
            writeln('An Enter de quay lai Menu !');
            readln;
            menu;
        end;

        '5': begin  { In bang xep hang}
            clrscr;
            readData;
            writeRank(3);
            writeln;
            writeln('An ENTER de quay lai Menu');
            readln;
            menu;
        end;

        '6': halt;  { Thoat chuong trinh}
    end;
end;

BEGIN
    randomize;
    hasFence:=false; { Ban đầu mặc định chơi với chế độ không hàng rào}
	readData; {Đọc bảng xếp hạng từ file}
    menu;
    readln;
END.


Video:
Download:
Download mã nguồn .PAS trên Google Drive