Bowling Challenge Solution.
For my YouTube channel, I recorded myself solving the Bowling Challenge. This challenge isn’t entirely new to me, I’ve solved it once before as part of the hiring process for an employer. That was several years ago however, and while I remembered that this was an entertaining challenge, I remembered little about how I’d solved it.
In the video, I make several mistakes, and several poor design decisions, which I then catch and reverse out of. While I was a little tired at the time of recording this, having worked a full work day already, I do not make excuses for these mistakes. Instead, I am pleased that they happened and that I left them in the video. The point being, I’m not trying to be “perfect”, but rather to share my thought process as I work the problem.
The code (which may be found below) is not perfect either, nor is it actually what I might submit to an interviewer. When I accomplished this task previously in order to be hired, I took some extra time to review my code before submitting it. This however is not quite the point. If I were challenged to perform this task in a live situation, before a potential employer, I believe that the process of making and correcting mistakes is more valuable than would be acing the task on a first try. It’s a fact of development that we make poor design decisions and mistakes, and then reverse them out. What matters to most interviewers is that you do indeed recognize and self correct those decisions.
I doubt that this challenge ever would be used as a live challenge, because even if you were to perfect it on a first try, it ought to take 30 minutes or more for most. That said, I’m sure there are some interviewers that would be so brutal 🙂 When attending an in-person aptitude test, of course, arrive well rested and ready to present at your best.
Link to the challenge write up: https://codingdojo.org/kata/Bowling/
Warts and all, here’s my effort… ( Source below )
program bowling;
{$mode delphiunicode}{$H+}
uses
SysUtils
;
type
TFrame = record
RemainingRolls: uint8; // number of rolls remaining, until frame complete.
Score: uint8;
end;
const
cMaxFramesPerGame = 20;
var
Score: uint32;
PrevScore: uint8;
SecondRoll: boolean;
FrameIndex: nativeuint;
Frames: array [ 0 .. pred( cMaxFramesPerGame ) ] of TFrame;
procedure UpdateScore( const Value: uint8 );
var
lctl: nativeuint;
begin
PrevScore := Value;
if FrameIndex = 0 then exit;
for lctl := FrameIndex downto 0 do begin
if Frames[ lctl ].RemainingRolls = 0 then continue;
Frames[ lctl ].Score := Frames[ lctl ].Score + Value;
dec( Frames[ lctl ].RemainingRolls );
if Frames[ lctl ].RemainingRolls = 0 then begin
Score := Score + Frames[ lctl ].Score;
end;
end;
end;
function CharToScore( const CH: char ): uint8;
begin
Result := ord( CH ) - $30; // 0x30 = '0' character in ascii.
end;
procedure AddFrame( const Score: uint8; const RemainingRolls: uint8 );
var
NewFrameIdx: nativeuint;
begin
NewFrameIdx := succ( FrameIndex );
if NewFrameIdx > pred( Length( Frames ) ) then begin
Writeln('Is this some special extended game?!');
exit;
end;
Frames[ NewFrameIdx ].Score := Score;
Frames[ NewFrameIdx ].RemainingRolls := RemainingRolls;
FrameIndex := NewFrameIdx;
end;
procedure ApplyRoll( const CH: Char );
var
v: uint8;
begin
case CH of
'-' : begin
Score := Score + PrevScore;
UpdateScore( 0 );
SecondRoll := not SecondRoll;
end;
'/' : begin // spare
UpdateScore( 10 - PrevScore );
AddFrame( 10, 1 );
SecondRoll := False;
end;
'X' : begin // strike
UpdateScore( 10 );
AddFrame( 10, 2 );
end;
'0','1','2','3','4',
'5','6','7','8','9' : begin
v := CharToScore( CH );
if SecondRoll then begin
Score := Score + v + PrevScore;
end;
SecondRoll := not SecondRoll;
UpdateScore( V );
end;
else exit;
end;
end;
function ReadInput: boolean;
var
strData: string;
CH: char;
begin
Write( ': ' );
Readln( strData );
strData := strData.Trim;
for CH in strData do begin
ApplyRoll( CH );
end;
if Length( strData ) < 1 then exit( true );
CH := strData[ Length( strData ) ];
Result := CH <> '~';
end;
begin
Score := 0;
FrameIndex := 0;
PrevScore := 0;
SecondRoll := False;
FillChar( Frames[ 0 ], sizeof( TFrame ) * cMaxFramesPerGame, 0 );
repeat
Writeln( 'Current Score : ', Score );
until not ReadInput;
end.