Not sure when to use ':' or '=' - pascal

I am getting this error when compiling my code: "cars2.pp(3,8) Fatal: Syntax error, "=" expected but ":" found"
Here's my code:
program vehInfo;
type
wheels: array [1 .. 6] of integer;
purchaseYear: array [1919 .. 2051] of integer;
style = (sports, SUV, minivan, motorcycle, sedan, exotic);
pwrSrc = (electric, hybrid, gas, diesel);
vehicle = record
wheel : wheels;
buyDate : purchaseYear;
styles : style;
source : pwrSrc;
end;
var
myVehicle: vehicle;
listOfCars: file of vehicle;
begin
assign(listOfCars, 'hwkcarsfile.txt');
reset(listOfCars);
read(listOfCars, myVehicle);
writeln('wheel type: ' , myVehicle.wheel);
writeln('year purchased: ' , myVehicle.buyDate);
writeln('style: ' , myVehicle.styles);
writeln('power source: ' , myVehicle.source)
close(listOfCars);
end.
I am new to Pascal, any help would be appreciated, thank you.

It is quite simple: type uses =, while variable declarations use :.
So:
type
wheels = 1..6; // not an array, but a subrange type!
purchaseYear = 1919..2051; // not an array, but a subrange type!
style = (sports, SUV, minivan, motorcycle, sedan, exotic);
pwrSrc = (electric, hybrid, gas, diesel);
vehicle = record
wheel: wheels; { a field of a record is a variable }
buyDate: purchaseYear;
styles: style;
source: pwrSrc;
end;
...
var
myVehicle: vehicle;
listOfCars: file of vehicle;
Subrange types are ordinal types (in this case, both are integers), but within the given range. Any value outside the range is illegal. You don't want to have arrays of numbers, you only want the number of wheels and the year (a number too) the vehicle was purchased. You don't need 133 different dates, do you?

Related

How to convert global enum values to string in Godot?

The "GlobalScope" class defines many fundamental enums like the Error enum.
I'm trying to produce meaningful logs when an error occurs. However printing a value of type Error only prints the integer, which is not very helpful.
The Godot documentation on enums indicates that looking up the value should work in a dictionary like fashion. However, trying to access Error[error_value] errors with:
The identifier "Error" isn't declared in the current scope.
How can I convert such enum values to string?
In the documentation you referenced, it explains that enums basically just create a bunch of constants:
enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}
# Is the same as:
const TILE_BRICK = 0
const TILE_FLOOR = 1
const TILE_SPIKE = 2
const TILE_TELEPORT = 3
However, the names of the identifiers of these constants only exist to make it easier for humans to read the code. They are replaced on runtime with something the machine can use, and are inaccessible later. If I want to print an identifier's name, I have to do so manually:
# Manually print TILE_FLOOR's name as a string, then its value.
print("The value of TILE_FLOOR is ", TILE_FLOOR)
So if your goal is to have descriptive error output, you should do so in a similar way, perhaps like so:
if unexpected_bug_found:
# Manually print the error description, then actually return the value.
print("ERR_BUG: There was a unexpected bug!")
return ERR_BUG
Now the relationship with dictionaries is that dictionaries can be made to act like enumerations, not the other way around. Enumerations are limited to be a list of identifiers with integer assignments, which dictionaries can do too. But they can also do other cool things, like have identifiers that are strings, which I believe you may have been thinking of:
const MyDict = {
NORMAL_KEY = 0,
'STRING_KEY' : 1, # uses a colon instead of equals sign
}
func _ready():
print("MyDict.NORMAL_KEY is ", MyDict.NORMAL_KEY) # valid
print("MyDict.STRING_KEY is ", MyDict.STRING_KEY) # valid
print("MyDict[NORMAL_KEY] is ", MyDict[NORMAL_KEY]) # INVALID
print("MyDict['STRING_KEY'] is ", MyDict['STRING_KEY']) # valid
# Dictionary['KEY'] only works if the key is a string.
This is useful in its own way, but even in this scenario, we assume to already have the string matching the identifier name explicitly in hand, meaning we may as well print that string manually as in the first example.
The naive approach I done for me, in a Singleton (in fact in a file that contain a lot of static funcs, referenced by a class_name)
static func get_error(global_error_constant:int) -> String:
var info := Engine.get_version_info()
var version := "%s.%s" % [info.major, info.minor]
var default := ["OK","FAILED","ERR_UNAVAILABLE","ERR_UNCONFIGURED","ERR_UNAUTHORIZED","ERR_PARAMETER_RANGE_ERROR","ERR_OUT_OF_MEMORY","ERR_FILE_NOT_FOUND","ERR_FILE_BAD_DRIVE","ERR_FILE_BAD_PATH","ERR_FILE_NO_PERMISSION","ERR_FILE_ALREADY_IN_USE","ERR_FILE_CANT_OPEN","ERR_FILE_CANT_WRITE","ERR_FILE_CANT_READ","ERR_FILE_UNRECOGNIZED","ERR_FILE_CORRUPT","ERR_FILE_MISSING_DEPENDENCIES","ERR_FILE_EOF","ERR_CANT_OPEN","ERR_CANT_CREATE","ERR_QUERY_FAILED","ERR_ALREADY_IN_USE","ERR_LOCKED","ERR_TIMEOUT","ERR_CANT_CONNECT","ERR_CANT_RESOLVE","ERR_CONNECTION_ERROR","ERR_CANT_ACQUIRE_RESOURCE","ERR_CANT_FORK","ERR_INVALID_DATA","ERR_INVALID_PARAMETER","ERR_ALREADY_EXISTS","ERR_DOES_NOT_EXIST","ERR_DATABASE_CANT_READ","ERR_DATABASE_CANT_WRITE","ERR_COMPILATION_FAILED","ERR_METHOD_NOT_FOUND","ERR_LINK_FAILED","ERR_SCRIPT_FAILED","ERR_CYCLIC_LINK","ERR_INVALID_DECLARATION","ERR_DUPLICATE_SYMBOL","ERR_PARSE_ERROR","ERR_BUSY","ERR_SKIP","ERR_HELP","ERR_BUG","ERR_PRINTER_ON_FIR"]
match version:
"3.4":
return default[global_error_constant]
# Regexp to use on #GlobalScope documentation
# \s+=\s+.+ replace by nothing
# (\w+)\s+ replace by "$1", (with quotes and comma)
printerr("you must check and add %s version in get_error()" % version)
return default[global_error_constant]
So print(MyClass.get_error(err)), or assert(!err, MyClass.get_error(err)) is handy
For non globals I made this, though it was not your question, it is highly related.
It would be useful to be able to access to #GlobalScope and #GDScript, maybe due a memory cost ?
static func get_enum_flags(_class:String, _enum:String, flags:int) -> PoolStringArray:
var ret := PoolStringArray()
var enum_flags := ClassDB.class_get_enum_constants(_class, _enum)
for i in enum_flags.size():
if (1 << i) & flags:
ret.append(enum_flags[i])
return ret
static func get_constant_or_enum(_class:String, number:int, _enum:="") -> String:
if _enum:
return ClassDB.class_get_enum_constants(_class, _enum)[number]
return ClassDB.class_get_integer_constant_list(_class)[number]

How can I merge multiple overlapping date ranges and create new ones?

I have multiple date ranges each with a start and end date/time, containing a single value from which I want to create new ranges, where the overlapping range values are appended to a slice.
Date/time Ranges are the following:
[10:00, 10:15] = 7
[10:10, 10:20] = 9
[10:05, 10:25] = 2
[11:00, now] = 3
To illustrate it better please see the following image (I used only times here, to simplify it):
On the image a date range [10:00, 10:15] contains the value 7, [10:10, 10:20] = 9 and so on.
I would need to generate the following date ranges, where overlapping range values gets merged together:
[10:00, 10:05] = 7
[10:05, 10:10] = 7,2
[10:10, 10:15] = 7,2,9
[10:15, 10:20] = 2,9
[10:20, 10:25] = 2
[10:25, 11:00] = 2 <-- this was a gap, no overlap and not continuous.
[11:00, now] = 3
I used a struct to represent a range
type Range struct {
Start time.Time
End time.Time
Values []int
}
Is there an easy and efficient way of doing this?
Here's a sketch of an algorithm to do this:
The data struct would be:
type Boundary struct {
Time time.Time
AddRemove int
Value int
}
A Boundary would represent a Value added or removed from the list of values at a given time. For a range:
[from,to]=number
you create two Boundary objects:
b1:=Boundary{Time:from,AddRemove: 1, Value: number}
b2:=Boundary{Time:to,AddRemove:-1,Value:number}
You can then sort all boundary objects by time and AddRemove. If times are equal, you should process adds first, then removes. Once this is done, you can process the boundary objects, and create your ranges:
last:=time.Time{}
values:=map[int]struct{}{}
for _,b:=range boundaries {
if last.IsZero() {
last=b.Time
values[b.Value]=struct{}{}
} else {
// Create a new range here with [last,b.Time] with values given in `values`
if b.AddRemove==1 {
values[b.Value]=struct{}{}
} else {
delete(values,b.Value)
}
last=b.Time
}
}

Reading a text file and constructing a matrix from it

I need to construct a matrix; a number of columns and rows are also in the first row of the matrix, I'll make an example so its more clearer.
4 3
1 2 3
5 6 7
9 10 8
1 11 13
Where m=4 (number of rows) and n=3 (number of columns)
This is an example of a text file. Is something like this even possible?
Program Feb;
const
max=100;
type
Matrix=array[1..max,1..max] of integer;
var datoteka:text;
m,n:integer;
counter:integer;
begin
assign(datoteka,'datoteka.txt');
reset(datoteka);
while not eoln(datoteka) do
begin
read(datoteka, m);
read(datoteka, n);
end;
repeat
read eoln(n)
until eof(datoteka)
write (m,n);
end.
My code isn't a big help, cause I don't know how to write it.
First, have a look at the code I wrote to do the task, and then look at my explanation below.
program Matrixtest;
uses
sysutils;
var
NoOfCols,
NoOfRows : Integer;
Source : TextFile;
Matrix : array of array of integer;
FileName : String;
Row,
Col : Integer; // for-loop iterators to access a single cell of the matrix
Value : Integer;
begin
// First, construct the name of the file defining the matrix
// This assumes that the file is in the same folder as this app
FileName := ExtractFilePath(ParamStr(0)) + 'MatrixDef.Txt';
writeln(FileName); // echo it back to the screen so we can see it
// Next, open the file
Assign(Source, FileName);
Reset(Source);
read(Source, NoOfRows, NoOfCols);
writeln('Cols: ', NoOfCols, 'Rows: ', NoOfRows);
SetLength(Matrix, NoOfCols, NoOfRows);
readln(source); // move to next line in file
// Next, read the array data
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
read(Source, Value);
Matrix[Col - 1, Row - 1] := Value;
end;
end;
// Display the array contents
for Row := 1 to NoOfRows do begin
for Col := 1 to NoOfCols do begin
writeln('Row: ', Row, ' contents', Matrix[Col - 1, Row - 1]);
end;
end;
Close(Source); // We're done with the file, so close it to release OS resources
readln; // this waits until you press a key, so you can read what's been displayed
end.
In your program, you can use a two-dimensional array to represent your matrix. Free Pascal supports multi-dimensional arrays; see https://wiki.lazarus.freepascal.org/Multidimensional_arrays for more information.
This is a complex task, so it helps to know how to do more basic things like reading an array of a size known at compile-time from a text file.
The wrinkle in this task is that you are supposed to read the dimensions (numbers of rows and columns) of the matrix at run-time from the file which contains the matrix's contents.
One inefficient way to do this would be to declare the matrix array with huge dimensions, larger than anything you would expect in practice, using the type of array declaration in the Wiki page linked above.
A better way is to use dynamic arrays, whose dimensions you can set at run-time. To use this, you need to know:
How to declare a dynamic array in Free Pascal
How to set the dimensions of the array at run-time, once you've picked them up from your matrix-definition file (hint: SetLength is the way to do this)
The fact that a Free Pascal dynamic array is zero-based
The easiest way of managing zero-based arrays is to write your code (in terms of Row and Column variables) as if the matrix were declared as array[1..NoOfRows, 1..NoOfColumns] and subtract one from the array indexes only when you actually access the array, as in:
Row := 3;
Column := 4;
Value := Matrix[Row - 1, Column - 1];

Transpose a string in Pascal

I'm very new to Pascal and still learning much. I have to write a code that :
Takes input of a string
Split the string into two characters each (Snippet)
Use the Snippet to get an index from an array
Transpose the Snippet to a certain value
If Index + Transpose is larger than the length of the Array, return nothing
If not, append the transposed Snippet to a result string
Return the transposed string
I can only write 1 through 3, the rest is still a blur for me. Helps are appreciated.
(And I also want to improve it without many for loops. Any thoughts?)
program TransposeString;
var
melody : Array[1..24] of String[2] = ('c.', 'c#', 'd.', 'd#', 'e.', 'f.', 'f#', 'g.', 'g#', 'a.', 'a#', 'b.', 'C.', 'C#', 'D.', 'D#', 'E.', 'F.', 'F#', 'G.', 'G#', 'A.', 'A#', 'B.');
songstring, transposedstring : String;
transposevalue : byte;
function Transpose(song : String; transposevalue : byte): String;
var
songsnippet : String[2];
iter_song, iter_index, index : byte;
begin
for iter_song := 1 to length(song) do
begin
if iter_song mod 2 = 0 then continue;
songsnippet := song[iter_song] + song[iter_song + 1]; //Split the string into 2 characters each
for iter_index := 1 to 24 do
begin
if melody[iter_index] = songsnippet then
begin
index := iter_index; //Get Index
break;
end;
end;
//Check Transpose + Index
//Transpose Snippet
//Append Snippet to Result String
end;
end;
begin
readln(songstring);
readln(transposevalue);
transposedstring := transpose(songstring, transposevalue);
writeln(transposedstring);
end.
As a starter for you to work from, rather than just spoon-feeding an answer:
You have the index of the snippet (note) in index. Assuming the notes are in order you need to return the note from the array positions above it, so
result := result + melody[iter_index + transposevalue];
You need to check the length of the array before trying to read from it, otherwise it'll crash (step 5). This is just an if statement.
I wouldn't worry too much about for loops - 2 deep nesting isn't that bad. If you wanted to split it out a bit then GetTransposedNote(const note:string): string; could be split out as a new function.
Things you may want to think about are:
What if you can't find the note in the array?
Do you want to be case-sensitive
What if the input string has an odd number of characters?
You are most of the way there already, though.

How to find all characters in a string whose appearance is greater than 2

I have a question about algorithm:
How to find all characters in a string whose appearance is greater than a specific number, say 2 for example efficiently?
Regards.
Counting sort will be extremely efficient for one-byte encodings, border case is two-byte encodings. For wider encodings it is not so efficient, but counting array may be replaced with hash table.
EDIT: By the way, that is too general solution, doing only counting phase and outputting results on the fly will be more than enough.
s= #your string
h=Hash.new(0)
s.each_char {|c| h[c]+=1 }
h.select {|char,count| count>2}
var word = "......";
var chars = word.GroupBy(w => w).Where(g => g.Count > 2).Select(g => new { character = g.Key, count = g.Count });
Couldn't resist to try this out.
Keep an internal array of 256 elements for each (ASCII) character.
Loop once over the input string.
Increment the count for given character using the ordinal value of the character as a direct access into the internal array.
Delphi implementation
Type
TCharCounter = class(TObject)
private
FCounts: array[0..255] of byte;
public
constructor Create(const Value: string);
function Count(const AChar: Char): Integer;
end;
{ TCharCounter }
constructor TCharCounter.Create(const Value: string);
var
I: Integer;
begin
inherited Create;
for I := 1 to Length(Value) do
Inc(FCounts[Ord(Value[I])]);
end;
function TCharCounter.Count(const AChar: Char): Integer;
begin
Result := FCounts[Ord(AChar)];
end;
I would sort the string, then just walk through it and keep a running tally for each letter. The last is just O(n) so it'll be as efficient as your sort.
the easier way is to use an array: occurrence[256], initialize them all with 0's
and for every char in string, occurrence[(int)char]++.
And then you just scan the occurrence to find the occurrence of characters satisfying your criterion.

Resources