Turbo Pascal sample programs
The 11 programs bundled with the
Turbo Pascal Online IDE, from "Hello, World!" to text-mode demoscene
effects and a 640×480 Graph-unit demo. Every one runs in the browser --
click Open in the IDE and press Ctrl+F9.
WELCOME.PAS · HELLO.PAS · FIBO.PAS · STARS.PAS · QSORT.PAS · BLOOM.PAS · CUBE.PAS · MANDEL.PAS · FIRE.PAS · STARFLD.PAS · CUBE3D.PAS
WELCOME.PAS
The program the IDE opens with: asks for your name, then prints a table of factorials.
program Welcome; uses Crt; var name: string; i, fact: integer; function Factorial(n: integer): integer; begin if n <= 1 then Factorial := 1 else Factorial := n * Factorial(n - 1); end; begin ClrScr; TextColor(Yellow); WriteLn('Turbo Pascal Online IDE'); TextColor(LightGray); WriteLn('------------------------'); WriteLn; Write('What is your name? '); ReadLn(name); WriteLn('Hello, ', name, '! Welcome back to 1992.'); WriteLn; for i := 1 to 6 do begin fact := Factorial(i); WriteLn(i, '! = ', fact); end; WriteLn; TextColor(LightCyan); WriteLn('Press any key to exit...'); ReadKey; end.
HELLO.PAS
The smallest complete Turbo Pascal program there is.
program Hello; begin WriteLn('Hello, World!'); ReadLn; end.
FIBO.PAS
Prints the first ten Fibonacci numbers with an iterative three-variable swap.
program Fibo; { Prints the first Fibonacci numbers } var a, b, t, i: Integer; begin a := 0; b := 1; for i := 1 to 10 do begin WriteLn(a); t := a + b; a := b; b := t; end; end.
STARS.PAS
Clears the screen and draws a small block of asterisks.
program Stars; uses Crt; var i: Integer; begin ClrScr; for i := 1 to 5 do WriteLn('*****'); WriteLn('Done.'); end.
QSORT.PAS
Classic recursive quicksort with Hoare partitioning over a randomly filled array.
program QuickSort; uses Crt; { Classic recursive quicksort (Hoare partition) on a random array. } const N = 20; var a: array[1..20] of integer; i: integer; procedure Swap(var x, y: integer); var t: integer; begin t := x; x := y; y := t; end; procedure Sort(lo, hi: integer); var i, j, pivot: integer; begin if lo >= hi then Exit; pivot := a[(lo + hi) div 2]; i := lo; j := hi; repeat while a[i] < pivot do i := i + 1; while a[j] > pivot do j := j - 1; if i <= j then begin Swap(a[i], a[j]); i := i + 1; j := j - 1; end; until i > j; Sort(lo, j); Sort(i, hi); end; procedure PrintArray(msg: string); var i: integer; begin Write(msg); for i := 1 to N do Write(a[i]:4); WriteLn; end; begin ClrScr; Randomize; TextColor(White); WriteLn('QuickSort demo'); WriteLn('--------------'); TextColor(LightGray); for i := 1 to N do a[i] := Random(90) + 10; PrintArray('Before: '); Sort(1, N); TextColor(LightGreen); PrintArray('After: '); WriteLn; TextColor(LightCyan); WriteLn('Press any key...'); ReadKey; end.
BLOOM.PAS
A Bloom filter -- a probabilistic set that answers "definitely not present" or "probably present" -- built from a boolean bit array and three hash functions, with the false-positive rate measured at the end.
program BloomFilter; uses Crt; { Bloom filter: a probabilistic set. K hash functions set K bits per added word. Lookups answer "definitely not present" or "probably present" -- false positives are possible, false negatives are not. } const M = 32; { filter size in bits } K = 3; { number of hash functions } var bits: array[0..31] of boolean; words: array[1..6] of string; i, j, fp: integer; pct: real; w: string; function Hash(w: string; seed: integer): integer; var i, h: integer; begin h := seed; for i := 1 to Length(w) do h := (h * 31 + Ord(Copy(w, i, 1))) mod M; Hash := h; end; procedure AddWord(w: string); var n: integer; begin for n := 1 to K do bits[Hash(w, n * 7 + 1)] := true; end; function Contains(w: string): boolean; var n: integer; begin for n := 1 to K do if not bits[Hash(w, n * 7 + 1)] then Exit(false); Contains := true; end; procedure ShowBits; var i: integer; begin Write(' ['); for i := 0 to M - 1 do if bits[i] then begin TextColor(LightGreen); Write('#'); end else begin TextColor(DarkGray); Write('.'); end; TextColor(LightGray); WriteLn(']'); end; begin ClrScr; TextColor(White); WriteLn('Bloom filter demo'); WriteLn('-----------------'); TextColor(LightGray); WriteLn; for i := 0 to M - 1 do bits[i] := false; WriteLn('Adding: pascal, turbo, borland'); AddWord('pascal'); AddWord('turbo'); AddWord('borland'); ShowBits; WriteLn; words[1] := 'pascal'; words[2] := 'turbo'; words[3] := 'borland'; words[4] := 'python'; words[5] := 'java'; words[6] := 'linux'; for i := 1 to 6 do begin Write(words[i]:10, ' -> '); if Contains(words[i]) then begin TextColor(LightGreen); WriteLn('probably in the set'); end else begin TextColor(LightRed); WriteLn('definitely not'); end; TextColor(LightGray); end; WriteLn; WriteLn('Testing all 676 two-letter words (none were added):'); fp := 0; for i := 65 to 90 do for j := 65 to 90 do begin w := Chr(i) + Chr(j); if Contains(w) then begin fp := fp + 1; if fp <= 8 then Write(' ', w); end; end; WriteLn; pct := fp * 100.0 / 676; WriteLn(fp, ' false positives (', pct:0:1, '% of lookups for absent words)'); WriteLn; TextColor(LightCyan); WriteLn('Press any key...'); ReadKey; end.
CUBE.PAS
A rotating 3D wireframe cube. There is no Graph/BGI unit here, so the vertices are projected onto the character grid by hand and the edges drawn with Bresenham -- the way demos did it in text mode.
program Cube; uses Crt; { A rotating 3D wireframe cube, text-mode style. There's no Graph/BGI unit here, so "graphics" means projecting 3D points onto the character grid by hand: classic demoscene technique. } const Scale = 7.0; YSquash = 0.5; Dist = 4.0; var vx, vy, vz: array[1..8] of real; sx, sy: array[1..8] of integer; ea, eb: array[1..12] of integer; oldx, oldy: array[1..600] of integer; ax, ay, x0, y0, z0, x1, z1, xr, yr, zr, fx, fy: real; cx, cy, i, k, j, n, dx, dy, s, px, py, qx, qy, numOld, frame: integer; begin ClrScr; cx := 40; cy := 12; { unit cube vertices } vx[1] := -1; vy[1] := -1; vz[1] := -1; vx[2] := 1; vy[2] := -1; vz[2] := -1; vx[3] := 1; vy[3] := 1; vz[3] := -1; vx[4] := -1; vy[4] := 1; vz[4] := -1; vx[5] := -1; vy[5] := -1; vz[5] := 1; vx[6] := 1; vy[6] := -1; vz[6] := 1; vx[7] := 1; vy[7] := 1; vz[7] := 1; vx[8] := -1; vy[8] := 1; vz[8] := 1; { 12 edges, each a pair of vertex indices } ea[1] := 1; eb[1] := 2; ea[2] := 2; eb[2] := 3; ea[3] := 3; eb[3] := 4; ea[4] := 4; eb[4] := 1; ea[5] := 5; eb[5] := 6; ea[6] := 6; eb[6] := 7; ea[7] := 7; eb[7] := 8; ea[8] := 8; eb[8] := 5; ea[9] := 1; eb[9] := 5; ea[10] := 2; eb[10] := 6; ea[11] := 3; eb[11] := 7; ea[12] := 4; eb[12] := 8; ax := 0.4; ay := 0.0; numOld := 0; frame := 0; TextColor(LightCyan); while (not KeyPressed) and (frame < 100000) do begin { erase last frame's pixels } for i := 1 to numOld do begin GotoXY(oldx[i], oldy[i]); Write(' '); end; numOld := 0; { rotate + project all 8 vertices } for i := 1 to 8 do begin x0 := vx[i]; y0 := vy[i]; z0 := vz[i]; x1 := x0 * Cos(ay) + z0 * Sin(ay); z1 := z0 * Cos(ay) - x0 * Sin(ay); yr := y0 * Cos(ax) - z1 * Sin(ax); zr := y0 * Sin(ax) + z1 * Cos(ax); xr := x1; s := Trunc(Scale * Dist / (Dist + zr)); sx[i] := cx + Trunc(xr * s); sy[i] := cy + Trunc(yr * s * YSquash); end; { draw the 12 edges by stepping along each line } for k := 1 to 12 do begin px := sx[ea[k]]; py := sy[ea[k]]; qx := sx[eb[k]]; qy := sy[eb[k]]; dx := qx - px; dy := qy - py; if Abs(dx) > Abs(dy) then n := Abs(dx) else n := Abs(dy); if n = 0 then n := 1; for j := 0 to n do begin fx := px + (qx - px) * j / n; fy := py + (qy - py) * j / n; numOld := numOld + 1; oldx[numOld] := Trunc(fx); oldy[numOld] := Trunc(fy); GotoXY(Trunc(fx), Trunc(fy)); Write('#'); end; end; ay := ay + 0.12; ax := ax + 0.05; frame := frame + 1; Delay(40); end; GotoXY(1, 24); TextColor(LightGray); WriteLn('Rotating cube. Press any key to exit...'); ReadKey; end.
MANDEL.PAS
The Mandelbrot set rendered as shaded ASCII, each cell colored by how fast that point escapes.
program Mandel; uses Crt; { The Mandelbrot set, rendered as shaded ASCII. Escape-time per character cell, colored by how fast each point diverges. } const Cols = 78; Rows = 20; MaxIter = 20; var px, py, iter: integer; x0, y0, x, y, xx, yy, tmp: real; ch: char; begin ClrScr; for py := 0 to Rows - 1 do begin GotoXY(1, py + 1); for px := 0 to Cols - 1 do begin x0 := (px / Cols) * 3.2 - 2.3; y0 := (py / Rows) * 2.0 - 1.0; x := 0; y := 0; xx := 0; yy := 0; iter := 0; while (xx + yy <= 4.0) and (iter < MaxIter) do begin tmp := xx - yy + x0; y := 2 * x * y + y0; x := tmp; xx := x * x; yy := y * y; iter := iter + 1; end; if iter = MaxIter then begin ch := ' '; TextColor(Black); end else if iter > 12 then begin ch := '.'; TextColor(Blue); end else if iter > 8 then begin ch := '*'; TextColor(Cyan); end else if iter > 5 then begin ch := 'o'; TextColor(LightGreen); end else if iter > 3 then begin ch := 'O'; TextColor(Yellow); end else begin ch := '@'; TextColor(LightRed); end; Write(ch); end; end; GotoXY(1, Rows + 2); TextColor(LightGray); WriteLn('Mandelbrot set. Press any key...'); ReadKey; end.
FIRE.PAS
The demoscene fire effect: random heat is seeded along the bottom row, then cools and drifts upward each frame. Text mode only offers eight background colors, so the ramp stops at light gray.
program Fire; uses Crt; { The classic demoscene fire effect: seed random heat along the bottom row, let it cool and drift upward each frame. Text-mode backgrounds only give 8 colors, so the ramp is black-red-brown- light gray rather than the full black-to-white you'd get in Graph mode. } const W = 40; H = 12; MaxFrames = 800; var heat: array[1..480] of integer; x, y, idx, below, left, right, avg, decay: integer; frame: integer; begin ClrScr; Randomize; for idx := 1 to W * H do heat[idx] := 0; frame := 0; while (not KeyPressed) and (frame < MaxFrames) do begin for x := 1 to W do heat[(H - 1) * W + x] := 8 + Random(8); for y := 1 to H - 1 do for x := 1 to W do begin idx := (y - 1) * W + x; below := y * W + x; if x > 1 then left := below - 1 else left := below; if x < W then right := below + 1 else right := below; avg := (heat[below] + heat[left] + heat[right]) div 3; decay := Random(2); if avg - decay < 0 then heat[idx] := 0 else heat[idx] := avg - decay; end; for y := 1 to H do begin GotoXY(21, y); for x := 1 to W do begin idx := (y - 1) * W + x; case heat[idx] of 0: TextBackground(Black); 1..4: TextBackground(Red); 5..9: TextBackground(Brown); else TextBackground(LightGray); end; Write(' '); end; end; frame := frame + 1; Delay(50); end; TextBackground(Black); GotoXY(1, H + 2); TextColor(LightGray); WriteLn('Fire demo. Press any key...'); ReadKey; end.
STARFLD.PAS
Warp-speed starfield -- every star has a random direction and a depth that shrinks each frame.
program Starfield; uses Crt; { Warp-speed starfield: each star has a random direction and a depth that shrinks every frame, so it appears to fly past the viewer. } const NumStars = 50; Cx = 40; Cy = 12; MaxFrames = 100000; var dx, dy, ox, oy: array[1..50] of integer; z: array[1..50] of real; i, px, py, frame: integer; ch: char; begin ClrScr; Randomize; for i := 1 to NumStars do begin dx[i] := Random(61) - 30; if dx[i] = 0 then dx[i] := 1; dy[i] := Random(41) - 20; if dy[i] = 0 then dy[i] := 1; z[i] := 4.0 + Random(300) / 10.0; ox[i] := -1; oy[i] := -1; end; frame := 0; while (not KeyPressed) and (frame < MaxFrames) do begin for i := 1 to NumStars do begin if ox[i] >= 0 then begin GotoXY(ox[i], oy[i]); Write(' '); end; z[i] := z[i] - 0.15; if z[i] <= 0.5 then begin z[i] := 20.0 + Random(200) / 10.0; dx[i] := Random(61) - 30; if dx[i] = 0 then dx[i] := 1; dy[i] := Random(41) - 20; if dy[i] = 0 then dy[i] := 1; end; px := Cx + Trunc(dx[i] / z[i]); py := Cy + Trunc(dy[i] / z[i] / 2.0); if (px >= 1) and (px <= 79) and (py >= 1) and (py <= 24) then begin if z[i] > 12 then ch := '.' else if z[i] > 5 then ch := '+' else ch := '*'; if z[i] > 12 then TextColor(DarkGray) else if z[i] > 5 then TextColor(LightGray) else TextColor(White); GotoXY(px, py); Write(ch); ox[i] := px; oy[i] := py; end else begin ox[i] := -1; oy[i] := -1; end; end; frame := frame + 1; Delay(40); end; GotoXY(1, 24); TextColor(LightGray); WriteLn('Warp speed. Press any key...'); ReadKey; end.
CUBE3D.PAS
The same cube, but in real graphics mode: 640x480 pixels and 16 colors via the Graph unit, with each face drawn as a solid filled polygon. Faces turned away from the viewer are dropped by checking the winding order of their projected corners.
program Cube3D; uses Graph, Crt; { A solid, shaded cube spinning in 640x480 VGA graphics mode -- real pixels this time, not characters. Each face is one FillPoly; the faces pointing away from the viewer are skipped by looking at the winding order of their projected corners, which is all the hidden-surface removal a convex solid needs. } const Scale = 170.0; { model units to pixels } Dist = 3.4; { how far away the viewer sits, in model units } type Vec = record x, y, z: real; end; var gd, gm: integer; v: array[1..8] of Vec; { cube corners, model space } sx, sy: array[1..8] of integer; { the same corners, projected } face: array[1..6] of array[1..4] of integer; faceCol: array[1..6] of integer; poly: array[1..4] of PointType; angX, angY: real; cx, cy, i, f, a, b, c, d, area: integer; ch: char; procedure SetCorner(n: integer; x, y, z: real); begin v[n].x := x; v[n].y := y; v[n].z := z; end; procedure SetFace(n, p1, p2, p3, p4, col: integer); begin face[n][1] := p1; face[n][2] := p2; face[n][3] := p3; face[n][4] := p4; faceCol[n] := col; end; { Yaw, then pitch, then a perspective divide onto the screen. } procedure Project(n: integer); var x, y, z, t, k: real; begin x := v[n].x; y := v[n].y; z := v[n].z; t := x * Cos(angY) - z * Sin(angY); z := x * Sin(angY) + z * Cos(angY); x := t; t := y * Cos(angX) - z * Sin(angX); z := y * Sin(angX) + z * Cos(angX); y := t; k := Scale / (z + Dist); sx[n] := cx + Round(x * k); sy[n] := cy - Round(y * k); end; begin gd := Detect; InitGraph(gd, gm, ''); cx := GetMaxX div 2; cy := GetMaxY div 2; SetCorner(1, -1, -1, -1); SetCorner(2, 1, -1, -1); SetCorner(3, 1, 1, -1); SetCorner(4, -1, 1, -1); SetCorner(5, -1, -1, 1); SetCorner(6, 1, -1, 1); SetCorner(7, 1, 1, 1); SetCorner(8, -1, 1, 1); { Corners are listed the same way round on every face, so one sign test tells us which faces are turned towards us. } SetFace(1, 1, 2, 3, 4, LightRed); { front } SetFace(2, 5, 8, 7, 6, LightGreen); { back } SetFace(3, 1, 4, 8, 5, LightBlue); { left } SetFace(4, 2, 6, 7, 3, Yellow); { right } SetFace(5, 1, 5, 6, 2, LightMagenta); { bottom } SetFace(6, 4, 3, 7, 8, LightCyan); { top } angX := 0.0; angY := 0.0; while not KeyPressed do begin ClearDevice; for i := 1 to 8 do Project(i); for f := 1 to 6 do begin a := face[f][1]; b := face[f][2]; c := face[f][3]; d := face[f][4]; { Signed area of the projected quad: negative means we are looking at the outside of this face. } area := (sx[b] - sx[a]) * (sy[c] - sy[a]) - (sy[b] - sy[a]) * (sx[c] - sx[a]); if area < 0 then begin poly[1].x := sx[a]; poly[1].y := sy[a]; poly[2].x := sx[b]; poly[2].y := sy[b]; poly[3].x := sx[c]; poly[3].y := sy[c]; poly[4].x := sx[d]; poly[4].y := sy[d]; SetFillStyle(SolidFill, faceCol[f]); SetColor(White); FillPoly(4, poly); end; end; SetColor(LightGray); OutTextXY(8, 8, 'Graph unit: 640x480, 16 colors'); OutTextXY(8, GetMaxY - 16, 'Press any key to return to the IDE'); angX := angX + 0.031; angY := angY + 0.019; Delay(20); end; ch := ReadKey; CloseGraph; WriteLn('Back in text mode. That was ', ch, ' you pressed.'); end.
Writing your own
Start from any of these, or open a blank window with File › New. The About page lists exactly which Turbo Pascal features the interpreter supports, and File › Share link... will turn whatever you write into a link you can send to someone else.