Recent

Author Topic: [SOLVED] Runtime error 201 only when running compiled program on Windows  (Read 12018 times)

chipnikz

  • Newbie
  • Posts: 5
Hi everyone, started college 2 months ago and really liking Pascal classes so far. Never programmed before, so I could use a little help with this.

About 1 week ago I started on my semester's final project: we have to create a Candy Crush clone (Color Crush) which functions basically like the game.

8 days later I finally finished the program, and as far as I can tell it works well in Linux. However, when running the compiled .exe under Windows, as soon as I start the game (by pressing J) it exits itself with a runtime error 201. I know this means there's a problem with the arrays used, but I don't understand why it works perfectly in Linux/where the problem could be.

Here's the entire program, because I honestly don't know what could be causing the problem:

Code: [Select]
Program ColorCrush;
Uses CRT;
Const
MaxFil = 10;
MinFilVisible = 6;
MinFil = 1;
MaxCol = 5;
MinCol = 1;
Moves = 5;
Arriba1 = 'W';
Arriba2 = 'w';
Abajo1 = 'S';
Abajo2 = 's';
Derecha1 = 'D';
Derecha2 = 'd';
Izquierda1 = 'A';
Izquierda2 = 'a';
Azul = 'A ';
Blanco = 'B ';
Rojo = 'R ';
Verde = 'V ';


Type CandyMat = array [MinFil..MaxFil,MinCol..MaxCol] of String;
Type ArregloPunt = array [1..10] of Integer;
Type ArregloNick = array [1..10] of String;

Procedure AnalizarValor (Var MatrizCandy : CandyMat;Valor,I,J : Integer);

begin
If Valor = 0 then
MatrizCandy[I,J] := Azul;
If Valor = 1 then
MatrizCandy[I,J] := Blanco;
If Valor = 2 then
MatrizCandy[I,J] := Rojo;
If Valor = 3 then
MatrizCandy[I,J] := Verde;
end;

Procedure CargarCrush (Var MatrizCandy : CandyMat; InicioF,FinF,InicioC,FinC : Integer);
Var I,J,X : Integer;

begin
For I := InicioF to FinF do
For J := InicioC to FinC do
begin
X := Random(4);
AnalizarValor(MatrizCandy,X,I,J);
end;
end;

Procedure InicCrush (Var MatrizCandy : CandyMat);
Var I,J : Integer;

begin
Randomize;
For I := MinFil to MaxFil do
For J := MinCol to MaxCol do
CargarCrush(MatrizCandy,I,MaxFil,J,MaxCol);
end;

Function ReconstruirVertical (MatrizCandy : CandyMat;InicioF,FinF,InicioC,FinC:Integer) : Boolean;
Var I,J : Integer;
begin
ReconstruirVertical := False;
For J := InicioC to FinC do
For I := InicioF to FinF do
If (I <= MaxFil - 2) and (MatrizCandy[I,J] = MatrizCandy[I+1,J]) and (MatrizCandy[I+1,J] = MatrizCandy[I+2,J]) then
ReconstruirVertical := True;
end;

Function ReconstruirHorizontal (MatrizCandy : CandyMat;InicioF,FinF,InicioC,FinC:Integer) : Boolean;
Var I,J : Integer;
begin
ReconstruirHorizontal := False;
For I := InicioF to FinF do
For J := InicioC to FinC do
If (J <= MaxCol - 2) and  (MatrizCandy[I,J] = MatrizCandy[I,J+1]) and (MatrizCandy[I,J+1] = MatrizCandy[I,J+2]) then
ReconstruirHorizontal := True;
end;

Function Reconstruir (MatrizCandy : CandyMat;InicioF,FinF,InicioC,FinC:Integer) : Boolean;
Var I,J : Integer;
begin
Reconstruir := False;
For I := InicioF to FinF do
For J := InicioC to FinC do
If ((J <= MaxCol - 2) and  (MatrizCandy[I,J] = MatrizCandy[I,J+1]) and (MatrizCandy[I,J+1] = MatrizCandy[I,J+2])) or ((I <= MaxFil - 2) and (MatrizCandy[I,J] = MatrizCandy[I+1,J]) and (MatrizCandy[I+1,J] = MatrizCandy[I+2,J])) then
Reconstruir := True;
end;

Procedure MostrarCandyC (MatrizCandy : CandyMat);
Var I,J : Integer;

begin
For I := MinFilVisible to MaxFil do
begin
WriteLn('');
For J := MinCol to MaxCol do
begin
If MatrizCandy[I,J] = Azul then
begin
TextColor(Blue);
Write(MatrizCandy[I,J]);
end;
If MatrizCandy[I,J] = Blanco then
begin
TextColor(8);
Write(MatrizCandy[I,J]);
end;
If MatrizCandy[I,J] = Rojo then
begin
TextColor(Red);
Write(MatrizCandy[I,J]);
end;
If MatrizCandy[I,J] = Verde then
begin
TextColor(Green);
Write(MatrizCandy[I,J]);
end;
end;
end;
WriteLn('');
TextColor(7);
end;

Function CoincidenciaHorizontal (MatrizCandy : CandyMat; Fila,Columna : Integer) : Boolean;

begin
CoincidenciaHorizontal := False;
If (Columna <= MaxCol - 2) and (MatrizCandy[Fila,Columna] = MatrizCandy[Fila,Columna+1]) and (MatrizCandy[Fila,Columna+1] = MatrizCandy[Fila,Columna+2]) then
CoincidenciaHorizontal := True;
end;

Function CoincidenciaVertical (MatrizCandy : CandyMat; Fila,Columna : Integer) : Boolean;

begin
CoincidenciaVertical := False;
If (Fila <= MaxFil - 2) and (MatrizCandy[Fila,Columna] = MatrizCandy[Fila+1,Columna]) and (MatrizCandy[Fila+1,Columna] = MatrizCandy[Fila+2,Columna]) then
CoincidenciaVertical := True;
end;

Function PuntajeHorizontal (MatrizCandy : CandyMat; Fila,InCol,FinCol : Integer) : Integer;
Var Y,X : Integer;

begin
X := FinCol - InCol + 1;
If MatrizCandy[Fila,InCol] = Rojo then
Y := X else
If MatrizCandy[Fila,InCol] = Verde then
Y := 2*X else
If MatrizCandy[Fila,InCol] = Azul then
Y := 3*X else
If MatrizCandy[Fila,InCol] = Blanco then
Y := 4*X;
PuntajeHorizontal := Y;
end;

Function PuntajeVertical (MatrizCandy : CandyMat; Columna,InFil,FinFil : Integer) : Integer;
Var X,Y : Integer;

begin
begin
X := FinFil - InFil + 1;
If MatrizCandy[InFil,Columna] = Rojo then
Y := X else
If MatrizCandy[InFil,Columna] = Verde then
Y := 2*X else
If MatrizCandy[InFil,Columna] = Azul then
Y := 3*X else
If MatrizCandy[InFil,Columna] = Blanco then
Y := 4*X;
PuntajeVertical:= Y;
end;
end;

Procedure Reemplazo (Var MatrizCandy : CandyMat; InicioF,FinF,InicioC,FinC : Integer);
Var I,J : Integer;

begin
For I := InicioF to FinF do
For J := InicioC to FinC do
begin
Randomize;
While (MatrizCandy[I,J] = MatrizCandy[I,J+1]) and (MatrizCandy[I,J] = MatrizCandy[I,J+2]) do
CargarCrush(MatrizCandy,I,I,J+2,J+2);
While (MatrizCandy[I,J] = MatrizCandy[I+1,J]) and (MatrizCandy[I,J] = MatrizCandy[I+2,J]) do
CargarCrush(MatrizCandy,I+2,I+2,J,J);
end;
end;

Procedure CaidaHorizontal (Var MatrizCandy : CandyMat;Var Puntaje : Integer);
Var I,J,K,L,X,Q,Z : Integer;

begin
X := 0;
While ReconstruirHorizontal(MatrizCandy,MinFilVisible,MaxFil,MinCol,MaxCol) do
begin
For I := MinFilVisible to MaxFil do
begin
For J := MinCol to MaxCol do
begin
If CoincidenciaHorizontal(MatrizCandy,I,J) then
begin
X := X + 1;
If X = 1 then
begin
K := I;
L := J;
end;
end else
If X > 0 then
begin
Puntaje := Puntaje + PuntajeHorizontal(MatrizCandy,K,L,L+X+1);
For Z := L to L+X+1 do
For Q := K downto MinFilVisible do
MatrizCandy[Q,Z] := MatrizCandy[Q-1,Z];
CargarCrush(MatrizCandy,MinFilVisible,MinFilVisible,L,L+X+1);
Randomize;
Reemplazo(MatrizCandy,MinFilVisible,MinFilVisible,L,L+X+1);
X := 0;
MostrarCandyC(MatrizCandy);
end;

end;
end;
MostrarCandyC(MatrizCandy);
end;
end;

Procedure CaidaVertical (Var MatrizCandy : CandyMat;Var Puntaje : Integer);
Var I,J,K,L,X,Z : Integer;

begin
X := 0;
While ReconstruirVertical(MatrizCandy,MinFilVisible,MaxFil,MinCol,MaxCol) do
begin
For J := MinCol to MaxCol do
For I := MinFilVisible to MaxFil do
begin
If CoincidenciaVertical(MatrizCandy,I,J) then
begin
X := X + 1;
If X = 1 then
begin
K := I;
L := J;
end;
end else
If X > 0 then
begin
Puntaje := Puntaje + PuntajeVertical(MatrizCandy,L,K,K+X+1);
Randomize;
CargarCrush(MatrizCandy,MinFil,MinFilVisible-1,MinCol,MaxCol);
Reemplazo(MatrizCandy,MinFil,MinFilVisible-1,MinCol,MaxCol);
For Z := K+X+1 downto K do
MatrizCandy[Z,L] := MatrizCandy[Z-X-2,L];
X := 0;
MostrarCandyC(MatrizCandy);
end;

end;
end;
MostrarCandyC(MatrizCandy);
end;
Procedure Intercambio (Var MatrizCandy : CandyMat; Fila,Columna:Integer);
Var Letra : Char; Var Aux : String;
begin
WriteLn('');
WriteLn('Seleccione la posición con la cual desea intercambiar el elemento - W (arriba) / S (abajo) / D (Derecha) / A (Izquierda)');
Letra := ReadKey;
While ((Letra <> Arriba1) and (Letra <> Arriba2) and (Letra <> Izquierda1) and (Letra <> Izquierda2) and (Letra <> Abajo1) and (Letra <> Abajo2) and (Letra <> Derecha1) and (Letra <> Derecha2)) or
(((Letra = Arriba1) and (Fila = 1)) or
((Letra = Arriba2) and (Fila = 1)) or
((Letra = Izquierda1) and (Columna = 1)) or
((Letra = Izquierda2) and (Columna = 1)) or
((Letra = Abajo1) and (Fila = MaxFil)) or
((Letra = Abajo2) and (Fila = MaxFil)) or
((Letra = Derecha1) and (Columna = MaxCol)) or
((Letra = Derecha2) and (Columna = MaxCol))) do
begin
WriteLn('Posición/Comando inválido, vuelva a intentar - W (Arriba) / A (Izquierda) / S (Abajo) / D (Derecha)');
Letra := ReadKey;
end;

If (Letra = Arriba1) or (Letra = Arriba2) then
begin
Aux := MatrizCandy [Fila-1,Columna];
MatrizCandy[Fila-1,Columna] := MatrizCandy [Fila,Columna];
MatrizCandy[Fila,Columna] := Aux;
end;
If (Letra = Abajo1) or (Letra = Abajo2) then
begin
Aux := MatrizCandy [Fila+1,Columna];
MatrizCandy[Fila+1,Columna] := MatrizCandy [Fila,Columna];
MatrizCandy[Fila,Columna] := Aux;
end;
If (Letra = Izquierda1) or (Letra = Izquierda2) then
begin
Aux := MatrizCandy [Fila,Columna-1];
MatrizCandy[Fila,Columna-1] := MatrizCandy [Fila,Columna];
MatrizCandy[Fila,Columna] := Aux;
end;
If (Letra = Derecha1) or (Letra = Derecha2) then
begin
Aux := MatrizCandy [Fila,Columna+1];
MatrizCandy[Fila,Columna+1] := MatrizCandy [Fila,Columna];
MatrizCandy[Fila,Columna] := Aux;
end;
end;

Procedure InicPunt (Var ArrPunt : ArregloPunt);
Var J : Integer;

begin
For J := 1 to 10 do
ArrPunt[J] := 0;
end;

Procedure InicNicks (Var ArrNicks : ArregloNick);
Var J : Integer;

begin
For J := 1 to 10 do
ArrNicks[J] := '0';
end;

Function CalcPosPuntaje(Puntaje : Integer;ArrPunt : ArregloPunt) : Integer;
Var J,I : Integer;

begin
I := 1;
For J := 1 to 10 do
If Puntaje < ArrPunt[J] then
I := I + 1;
CalcPosPuntaje := I;
end;

Procedure CargarPuntaje(Var Puntaje : Integer; Var ArrPunt : ArregloPunt);
Var J,I : Integer;

begin
I := CalcPosPuntaje(Puntaje,ArrPunt);
For J := 10 downto I do
ArrPunt[J+1] := ArrPunt[J];
ArrPunt[I] := Puntaje;
end;

Procedure CargarNicks(Nick : String; Var ArrNicks : ArregloNick;ArrPunt : ArregloPunt;Puntaje : Integer);
Var J,I : Integer;

begin
I := CalcPosPuntaje(Puntaje,ArrPunt);
For J := 10 downto I do
ArrNicks[J+1] := ArrNicks[J];
ArrNicks[I] := Nick;
end;

Procedure MostrarRanking (ArrNicks : ArregloNick; ArrPunt : ArregloPunt);
Var I : Integer;

begin
clrscr;
If ArrNicks[1] = '0' then
begin
WriteLn('');
WriteLn('Nadie ha jugador en esta sesión, ninguna puntuación ha sido cargada.');
WriteLn('');
end else
For I := 1 to 10 do
If ArrNicks[I] <> '0' then
WriteLn(I,'. ',ArrNicks[I],' - ',ArrPunt[I],' puntos');
end;

Procedure JuegoNuevo (Var Puntaje : Integer; Var TablaNicks : ArregloNick; Var TablaPuntaje : ArregloPunt);
Var MatrizCandy : CandyMat; Fila,Columna,Movimientos : Integer; Nick,Aux : String;

begin
Puntaje := 0;
InicCrush(MatrizCandy);
While Reconstruir (MatrizCandy,MinFil,MaxFil,MinCol,MaxCol) do
Reemplazo(MatrizCandy,MinFil,MaxFil,MinCol,MaxCol);
Movimientos := Moves;
MostrarCandyC(MatrizCandy);
While (Movimientos <> 0) do
begin
WriteLn('Movimientos restantes: ', Movimientos);
WriteLn('Seleccionar fila del elemento');
Read(Fila);
While (Fila+5 < MinFilVisible) or (Fila > MaxFil) do
begin
WriteLn('Ingrese una fila válida');
Read(Fila);
end;
WriteLn('Seleccionar columnna del elemento');
Read(Columna);
While (Columna < MinCol) or (Columna > MaxCol) do
begin
WriteLn('Ingrese una columna válida');
Read(Columna);
end;
Intercambio(MatrizCandy,Fila+5,Columna);
MostrarCandyC(MatrizCandy);
While Reconstruir(MatrizCandy,MinFilVisible,MaxFil,MinCol,MaxCol) do
begin
CaidaVertical(MatrizCandy,Puntaje);
CaidaHorizontal(MatrizCandy,Puntaje);
end;
WriteLn('Puntuación: ',Puntaje);
Movimientos := Movimientos - 1;
end;
If CalcPosPuntaje(Puntaje,TablaPuntaje) <= 10 then
begin
WriteLn('¡Felicidades, su puntuación está entre las mejores 10! Ingrese su nombre.');
ReadLn(Aux);
ReadLn(Nick);
CargarPuntaje(Puntaje,TablaPuntaje);
CargarNicks(Nick,TablaNicks,TablaPuntaje,Puntaje);
end else
WriteLn('Ha terminado la partida, se volverá al menú principal.');
Delay(1000);
end;


Var Puntaje : Integer; Var Opcion : Char; Var TablaPuntuacion : ArregloPunt; Var TablaNombres : ArregloNick;

begin
clrscr;
InicNicks(TablaNombres);
InicPunt(TablaPuntuacion);
Puntaje := 0;
Opcion := ' ';
While (Opcion <> 'S') and (Opcion <> 's') do
begin
WriteLn('Por favor ingrese una opción: [J]uego Nuevo - [R]anking - [S]alir');
Opcion := ReadKey;
Case Opcion of
'J','j': JuegoNuevo(Puntaje,TablaNombres,TablaPuntuacion);
'R','r': MostrarRanking(TablaNombres,TablaPuntuacion);
end;
end;
end.
« Last Edit: June 14, 2014, 10:39:50 pm by chipnikz »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Runtime error 201 only when running compiled program on Windows
« Reply #1 on: June 14, 2014, 08:24:03 pm »
Do you use the exact same option on both platforms? 201 is a range check error and it's not enabled by default in the compiler. However, IDEs may provide different default options. You can compile with -gl to get runtime backtrace where exactly the 201 RTE occurs.

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Runtime error 201 only when running compiled program on Windows
« Reply #2 on: June 14, 2014, 08:49:46 pm »
Quote
I don't understand why it works perfectly in Linux/where the problem could be.
Not true.

Code: [Select]
Exitcode = 216
Runtime error 216 at $0000000000403A55
  $0000000000403A55
  $0000000000402626 line 423 of project1.lpr

--------------------------------------------------
Press enter
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

chipnikz

  • Newbie
  • Posts: 5
Re: Runtime error 201 only when running compiled program on Windows
« Reply #3 on: June 14, 2014, 08:59:56 pm »
Do you use the exact same option on both platforms? 201 is a range check error and it's not enabled by default in the compiler. However, IDEs may provide different default options. You can compile with -gl to get runtime backtrace where exactly the 201 RTE occurs.

We've been told not to use any IDE's, so I'm compiling both on Windows and Linux with "fpc ColorCrush.pas".

Quote
I don't understand why it works perfectly in Linux/where the problem could be.
Not true.

Code: [Select]
Exitcode = 216
Runtime error 216 at $0000000000403A55
  $0000000000403A55
  $0000000000402626 line 423 of project1.lpr

--------------------------------------------------
Press enter

Hmm... never got that error before. Mind telling me how that happened? I know you get a runtime error (can't remember the code) if you enter a non-integer as a row/column value, but I've been told I don't have to worry about that.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Runtime error 201 only when running compiled program on Windows
« Reply #4 on: June 14, 2014, 09:41:42 pm »
You should always compile with the command-line switch -Cr when accessing arrays as you do here. The compiler-inserted range checking code would then take you immediately to the place(s) where you access memory outside the array(s) you set up, as happened for Blaazen.
For instance in your Reemplazo routine

Procedure Reemplazo (Var MatrizCandy : CandyMat; InicioF,FinF,InicioC,FinC : Integer);
Var I,J : Integer;

begin
For I := InicioF to FinF do
   For J := InicioC to FinC - 2 do begin

      While (MatrizCandy[I,J] = MatrizCandy[I,J+1]) and (MatrizCandy[I,J] = MatrizCandy[I,J+2]) do
         CargarCrush(MatrizCandy,I,I,J+2,J+2);
      While (MatrizCandy[I,J] = MatrizCandy[I+1,J]) and (MatrizCandy[I,J] = MatrizCandy[I+2,J]) do
         CargarCrush(MatrizCandy,I+2,I+2,J,J);
      end;
end;

you need to limit the J variable by two (see code in red) to prevent illegal access by CargarCrush which takes parameters of J+2.
It was only luck that the illegal memory accesses on Linux did not happen to crash your program or raise errors for the test you made. On another linux computer at another time, something unpredicatable may well happen with the same faulty code.
« Last Edit: June 14, 2014, 09:45:09 pm by howardpc »

chipnikz

  • Newbie
  • Posts: 5
Re: Runtime error 201 only when running compiled program on Windows
« Reply #5 on: June 14, 2014, 09:55:06 pm »
Wow, can't believe I didn't see that. Thanks a lot! I'm guessing I'd also have to limit the variable I by 2, right?
Is there any way to check where else I may need to define a limit? Compiling with -Cr didn't tell me much, AFAIK.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Runtime error 201 only when running compiled program on Windows
« Reply #6 on: June 14, 2014, 10:03:55 pm »
You're right, I hadn't noticed that I+2 parameter: I also needs to be held within its proper bounds.
You're more familiar with your code than anyone else - just check each array access carefully, if range-checking does not pin-point the offending line of code.
If it is not working for you, make sure debugging is enabled, and line number information is included in runtime error backtraces (command-line switch -gl).

chipnikz

  • Newbie
  • Posts: 5
Re: Runtime error 201 only when running compiled program on Windows
« Reply #7 on: June 14, 2014, 10:13:56 pm »
You're right, I hadn't noticed that I+2 parameter: I also needs to be held within its proper bounds.
You're more familiar with your code than anyone else - just check each array access carefully, if range-checking does not pin-point the offending line of code.
If it is not working for you, make sure debugging is enabled, and line number information is included in runtime error backtraces (command-line switch -gl).

OK, I'm pretty sure all limits are now set. Now I just have to figure out a way to implement a new Replacement procedure, so that the board does not start with any combinations.

Edit: And it's done! Just had to use an existing procedure to reload the off-limits rows/columns as long as there were any vertical/horizontal combinations!
« Last Edit: June 14, 2014, 10:21:17 pm by chipnikz »

 

TinyPortal © 2005-2018