🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of Selticq

Selticq's solution

to Robot Name in the Delphi Pascal Track

Published at Mar 22 2021 · 0 comments
Instructions
Test suite
Solution

Manage robot factory settings.

When a robot comes off the factory floor, it has no name.

The first time you turn on a robot, a random name is generated in the format of two uppercase letters followed by three digits, such as RX837 or BC811.

Every once in a while we need to reset a robot to its factory settings, which means that its name gets wiped. The next time you ask, that robot will respond with a new random name.

The names must be random: they should not follow a predictable sequence. Using random names means a risk of collisions. Your solution must ensure that every existing robot has a unique name.

Testing

In order to run the tests for this track, you will need to install DUnitX. Please see the installation instructions for more information.

Loading Exercises into Delphi

If Delphi is properly installed, and *.dpr file types have been associated with Delphi, then double clicking the supplied *.dpr file will start Delphi and load the exercise/project. control + F9 is the keyboard shortcut to compile the project or pressing F9 will compile and run the project.

Alternatively you may opt to start Delphi and load your project via. the File drop down menu.

When Questions Come Up

We monitor the Pascal-Delphi support room on gitter.im to help you with any questions that might arise.

Submitting Exercises

Note that, when trying to submit an exercise, make sure the exercise file you're submitting is in the exercism/delphi/<exerciseName> directory.

For example, if you're submitting ubob.pas for the Bob exercise, the submit command would be something like exercism submit <path_to_exercism_dir>/delphi/bob/ubob.pas.

Source

A debugging session with Paul Blackwell at gSchool. http://gschool.it

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you may request help from a mentor.

uRobotNameTests.pas

unit uRobotNameTests;

interface
uses
  DUnitX.TestFramework, uRobotName, System.Generics.Collections;

const
  CanonicalVersion = '0.0.0.1';

type
  [TestFixture]
  TRobotNameTest = class(TObject)
  private
    FRobot : TRobot;
    Names : TList<string>;
    Robots : TObjectList<TRobot>;
  public
    [Setup]
    procedure Setup;
    [TearDown]
    procedure TearDown;

    [Test]
//    [Ignore('Comment the "[Ignore]" statement to run the test')]
    procedure name_properly_formated;

    [Test]
    [Ignore]
    procedure is_name_persistent;

    [Test]
    [Ignore]
    procedure is_able_to_reset_name;

    [Test]
    [Ignore]
    procedure each_robot_have_unique_name;
  end;

implementation

uses
  System.RegularExpressions, System.Classes, SysUtils, Windows;

procedure TRobotNameTest.is_name_persistent;
begin
  Assert.AreEqual(FRobot.Name, FRobot.Name);
end;

procedure TRobotNameTest.name_properly_formated;
begin
  Assert.IsTrue(TRegEx.IsMatch(FRobot.Name, '^[A-Z]{2}\d{3}$'), 'expected format''ssddd'', found ' + FRobot.Name);
end;

procedure TRobotNameTest.Setup;
var
  i, j : char;
  k : integer;
begin
  Names := TList<string>.create;
  for i := 'A' to 'Z' do
    for j := 'A' to 'Z' do
      for k := 0 to 999 do
        Names.Add(i + j + format('%.*d', [3, k]));
  Robots := TObjectList<TRobot>.Create;
  FRobot := TRobot.Create;
end;

procedure TRobotNameTest.TearDown;
begin
  Names.DisposeOf;
  Robots.DisposeOf;
  FRobot.DisposeOf;
end;

procedure TRobotNameTest.each_robot_have_unique_name;
var
  i, ind : integer;
  Rob: TRobot;

  Procedure WriteXY( x , y : Integer; s : string);
  var
   LCoord: TCoord;
   begin
     LCoord.X := x;
     LCoord.Y := y;
     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), LCoord);
     Write(s);
   end;

begin
  for i := 0 to 20000 do
  begin
    Rob := TRobot.Create;
    Assert.IsTrue(Names.BinarySearch(Rob.Name, ind), format('Robot #: %*.d, named %s is not unique',[5, ind, Rob.Name]));
    Names.Delete(ind);
    Robots.BinarySearch(Rob, ind);
    Robots.Insert(ind, Rob);
    WriteXY(2, 9, format('Robot #: %*.d, named %s, is unique',[5, i, Rob.Name]));
  end;
end;

procedure TRobotNameTest.is_able_to_reset_name;
var
  old : string;
  i : Integer;

begin
  Robots.Add(TRobot.Create);
  old := Robots.Last.Name;
  Names.Remove(old);
  for i := 0 to 10 do
  begin
    Names.Add(old);
    old := Robots.Last.Name;
    Robots.Last.Reset;
    Assert.IsTrue(Names.Contains(Robots.Last.Name), 'Robot name after reset is not unique');
    Names.Remove(Robots.Last.Name);
    Assert.AreNotEqual(old, Robots.Last.Name, 'Robot name after reset is not changed');
  end;
end;

initialization
  TDUnitX.RegisterTestFixture(TRobotNameTest);
end.
unit uRobotName;

interface

uses
  System.Generics.Collections;

type TRobot = class
    private
      class var Names: TList<String>;
      FName: String;
      function GenerateRandomName(): String;
      function GetName(): String;
    public
      class constructor Create();
      class destructor Destroy();
      constructor Create();
      procedure Reset();
      property Name: String read GetName;
end;

implementation

uses
  System.SysUtils;

class constructor TRobot.Create();
begin
  Names := TList<String>.Create();
end;

class destructor TRobot.Destroy();
begin
  if Assigned(Names) then
    Names.Free();
end;

constructor TRobot.Create();
begin
  Inherited Create();
  FName := String.Empty;
  Randomize();
end;

function TRobot.GenerateRandomName(): String;
begin
  repeat
    Result := Char(65 + Random(26))
        + Char(65 + Random(26))
        + Random(10).ToString()
        + Random(10).ToString()
        + Random(10).ToString();
  until not Names.Contains(Result);
end;

function TRobot.GetName(): String;
begin
  if FName = String.Empty then
    begin
      FName := GenerateRandomName();
      Names.Add(FName);
    end;
  Result := FName;
end;

procedure TRobot.Reset();
begin
  Names.Delete(Names.IndexOf(FName));
  FName := String.Empty;
end;

end.

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?