TankGame

by James Farnsworth: Y8 Age: ~13

Introduction

Program TankGame is a most pleasing contribution which we would have welcomed even from a much older student. It is imaginative, challenging (using dynamic arrays, for example) and could inspire others to write console games for two players sharing a keyboard. James provides clear instructions in the opening screen:

Instructions

Instructions

This is a screenshot from a battle.

Battle

Battle

As a consequence of the inability of a tank to move past a shell, it is possible for the tanks to be cut off from each other (unable to hit the opposition). Usefully, the game ends immediately in such a situation:

Stalemate

Stalemate

Another useful feature is the option to continue with another battle, so that you can easily play a "best of three" or a "best of five" series against an opponent.

The Code

program TankGame;
{
    Copyright (c) 2013 James Farnsworth

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/ 

}
{$mode objfpc}{$H+}

uses
  SysUtils, Crt, Classes;

var
  XPosShotsP1, YPosShotsP1, XPosShotsP2, YPosShotsP2: array of integer;
  P1numofshots, P2numofshots, Count, num_p1_z_pressed, num_p2_z_pressed, winner: integer;
  //winner is 0 if there is currently no winner, 1 if p1 has won, 2 if p2 has won, and 3 if it is a stalemate
  P1YPos, P2YPos, p1lowestallowed, p1highestallowed, p2lowestallowed,
  p2highestallowed: integer;
  userkey: char;
  exit: boolean;
  exit2: string;
const
  p1highestbulletallowed: integer = 27;
  p2highestbulletallowed: integer = 4;
begin
  clrScr;
  cursorOff;
  goToXY(windmaxX div 2 - (31 div 2), 2);
  write('Tank Game - by James');
  goToXY(1, 4);
  write('The aim of the game is to shoot the opposing tank. You could try and do this by');
  goToXY(1, 5);
  write('shooting them outright, but this is hard. Instead you can trap them as tanks');
  goToXY(1, 6);
  write('cannot drive over shells, then try to shoot them. Player 1 uses the ''W'' key');
  goToXY(1, 7);
  write('to  move up, the ''S'' or ''A'' keys to move down, and the ''Z'' key to shoot.');
  goToXY(1, 8);
  write('Player 2 uses the ''I'' key to move up, the ''J'' or ''K'' keys to move down,');
  goToXY(1, 9);
  write('and the ''M'' key  to shoot. To be able to shoot, you must first reload by');
  goToXY(1, 10);
  write('pressing the ''shoot'' key 3 times. (P1 is on the left and P2 is on the right)');
  readln;
  repeat
    clrScr;
    exit := False;
    winner := 0;
    exit2 := '-';
    p1lowestallowed := windmaxY;
    p2lowestallowed := windmaxY;
    p1highestallowed := 1;
    p2highestallowed := 1;
    p1highestbulletallowed := 27;
    p2highestbulletallowed := 4;
    P1YPos := windmaxY div 2;
    P2YPos := windmaxY div 2;
    clrScr;
    goToXY(4, P1YPos);
    write(chr(177), chr(177), chr(177), '-');
    goToXY(24, P2YPos);
    write('-', chr(177), chr(177), chr(177));
    p1numofshots := 0;
    p2numofshots := 0;
    setLength(xposshotsp2, p2numofshots + 1);
    setLength(yposshotsp2, p2numofshots + 1);
    setLength(xposshotsp1, p1numofshots + 1);
    setLength(yposshotsp1, p1numofshots + 1);
    for Count := 1 to windmaxY do
    begin
      goToXY(15, Count);
      write('|');
    end;
    repeat
      if keypressed then
        userkey := readkey
      else
        userkey := '#';  //A value that is not used
      //p1's controls
      if (userkey = 'w') and (P1YPos > p1highestallowed) then
      begin
        goToXY(4, P1YPos);
        write('    ');
        P1YPos := P1YPos - 1;
        goToXY(4, P1YPos);
        write(chr(177), chr(177), chr(177), '-');
      end;
      if ((userkey = 'a') or (userkey = 's')) and (P1YPos < p1lowestallowed) then
      begin
        goToXY(4, P1YPos);
        write('    ');
        inc(P1YPos);
        goToXY(4, P1YPos);
        write(chr(177), chr(177), chr(177), '-');
      end;
      if (userkey = 'z') then
      begin
        inc(num_p1_z_pressed);
        if (num_p1_z_pressed mod 4 = 0) then
        begin
          inc(P1numofshots);
          setLength(XPosShotsP1, P1numofshots);
          setLength(YPosShotsP1, P1numofshots);
          YposshotsP1[P1numofshots - 1] := P1Ypos;
          Xposshotsp1[p1numofshots - 1] := 8;
        end;
      end;
      //p2's controls
      if (userkey = 'i') and (P2YPos > p2highestallowed) then
      begin
        goToXY(24, P2YPos);
        write('    ');
        P2YPos := P2YPos - 1;
        goToXY(24, P2YPos);
        write('-', chr(177), chr(177), chr(177));
      end;
      if ((userkey = 'j') or (userkey = 'k')) and (P2YPos < p2lowestallowed) then
      begin
        goToXY(24, P2YPos);
        write('    ');
        inc(P2YPos);
        goToXY(24, P2YPos);
        write('-', chr(177), chr(177), chr(177));
      end;
      if (userkey = 'm') then
      begin
        inc(num_p2_z_pressed);
        if (num_p2_z_pressed mod 4 = 0) then
        begin
          inc(P2numofshots);
          setLength(XPosShotsP2, P2numofshots);
          setLength(YPosShotsP2, P2numofshots);
          YposshotsP2[P2numofshots - 1] := P2Ypos;
          Xposshotsp2[p2numofshots - 1] := 23;
        end;
      end;
      //MOVE SHELLS ON
      if (p1numofshots > 0) then
      begin
        for Count := 0 to P1numofshots - 1 do
        begin
          //Go to previous position of shell
          goToXY(xposshotsp1[Count] - 1, yposshotsp1[Count]);
          if (whereX > 7) and (whereX < 27) then  //Do not destroy own gun!
            write(' ');  //Delete shell from previous position
          goToXY(xposshotsp1[Count], yposshotsp1[Count]);
          if whereX <= p1highestbulletallowed then
          begin
            write('-');
            inc(XPosShotsP1[Count]);
          end;
        end;
      end;
      if (p2numofshots > 0) then
      begin
        for Count := 0 to P2numofshots - 1 do
        begin
          //Go to previous position of shell
          goToXY(xposshotsp2[Count] + 1, yposshotsp2[Count]);
          if (xposshotsp2[Count] < 23) and (xposshotsp2[Count] > 3) then
            //Do not destroy own gun!
            write(' ');  //Delete shell from previous position
          goToXY(xposshotsp2[Count], yposshotsp2[Count]);
          if xposshotsp2[Count] >= p2highestbulletallowed then
          begin
            write('-');
            XPosShotsP2[Count] := XPosShotsP2[Count] - 1;
          end;
        end;
      end;
      for Count := 1 to windmaxY do
      begin
        goToXY(15, Count);
        write('|');
      end;
      //end of game or lowest player can go logic
      if (p1numofshots > 0) then
      begin
        for Count := 0 to p1numofshots do
        begin
          if ((xposshotsp1[Count] = p1highestbulletallowed) and
            (yposshotsp1[Count] > P2ypos)) and
            (yposshotsp1[Count] <= p2lowestallowed) then
          begin
            p2lowestallowed := yposshotsp1[Count] - 1;
          end;
          if ((xposshotsp1[Count] = p1highestbulletallowed) and
            (yposshotsp1[Count] < P2ypos)) and
            (yposshotsp1[Count] >= p2highestallowed) then
          begin
            p2highestallowed := yposshotsp1[Count] + 1;
          end;
          if (xposshotsp1[Count] = p1highestbulletallowed) and
            (yposshotsp1[Count] = p2ypos) then
          begin
            exit := True;
            winner := 1;
          end;
        end;
      end;
      if (p2numofshots > 0) then
      begin
        for Count := 0 to p2numofshots do
        begin
          if ((xposshotsp2[Count] = p2highestbulletallowed) and
            (yposshotsp2[Count] > P1ypos)) and
            (yposshotsp2[Count] <= p1lowestallowed) then
          begin
            p1lowestallowed := yposshotsp2[Count] - 1;
          end;
          if ((xposshotsp2[Count] = p2highestbulletallowed) and
            (yposshotsp2[Count] < p1ypos)) and
            (yposshotsp2[Count] >= p1highestallowed) then
          begin
            p1highestallowed := yposshotsp2[Count] + 1;
          end;
          if (xposshotsp2[Count] = p2highestbulletallowed) and
            (yposshotsp2[Count] = p1ypos) then
          begin
            exit := True;
            winner := 2;
          end;
        end;
      end;
      if (p1highestallowed > p2lowestallowed) or
        (p2highestallowed > p1lowestallowed) then
      begin
        exit := True;
        winner := 3;
      end;
      sleep(50);
    until (exit);
    if (winner = 1) then
    begin
      clrscr;
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) - 1);
      write('####################');
      goToXY((windmaxx div 2) - 10, windmaxy div 2);
      write('      P1 wins!      ');
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) + 1);
      write('####################');
    end;
    if (winner = 2) then
    begin
      clrscr;
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) - 1);
      write('####################');
      goToXY((windmaxx div 2) - 10, windmaxy div 2);
      write('      P2 wins!      ');
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) + 1);
      write('####################');
    end;
    if (winner = 3) then
    begin
      clrscr;
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) - 1);
      write('####################');
      goToXY((windmaxx div 2) - 10, windmaxy div 2);
      write('     Stalemate!     ');
      goToXY((windmaxx div 2) - 10, (windmaxy div 2) + 1);
      write('####################');
    end;
    sleep(3000);
    repeat
      clrscr;
      exit2 := '-';
      goToXY((windmaxx div 2) - 10, windmaxy div 2);
      write('Play it again? [y/n] ');
      readln(exit2);
    until (uppercase(exit2) = 'N') or (uppercase(exit2) = 'Y');
    for Count := 0 to p1numofshots - 1 do
    begin
      xposshotsp1[Count] := 0;
      yposshotsp1[Count] := 0;
    end;
    for Count := 0 to p2numofshots - 1 do
    begin
      xposshotsp2[Count] := 0;
      yposshotsp2[Count] := 0;
    end;
  until (uppercase(exit2) = 'N');
end.

Remarks

Could you write a crt game for two players?

Programming - a skill for life!

Three programs (including Notes) and Raspberry Pi guidance by James Farnsworth