Case statement with logic operators (< > =, etc) in Pascal - case

I'm having trouble making this work. Apparently, i can't use > or < in the case sentence, is there a workaround for this? Thanks!
case num of
0:
begin
cont_0 := cont_0 + 1;
end;
> 0:
begin
cont_pos := cont_pos + 1;
sum_pos := sum_pos + num;
end;
< 0:
begin
sum_neg := sum_neg + num;
end;
else;
end;

case Sign(num) of
-1: ...
0: ...
1: ...
end;
More readable than if ... else if ... else? You decide.

Don't use case then, why not use if?
if num = 0 then
cont_0 := cont_0 + 1;
if num > 0 then
BEGIN
cont_pos := cont_pos + 1;
sum_pos := sum_pos + num;
END
if num < 0 then
sum_neg := sum_neg + num;

Related

pascal scale of notation

I'm doing a procedure that reads numbers character by character.
procedure ReadLongint (var success : boolean; var result : longin);
var
c : char;
res : longint;
pos : integer;
begin
res := 0;
pos := 0;
repeat
read(c);
pos := pos + 1
until (c <> ' ') and (c <> #10);
while (c <> ' ') and (c <> #10) do
begin
if (c < '0') or (c > '9') then
begin
writeln('Unexpected ''', c, ''''' in pos: ', pos);
readln;
success := false;
exit
end;
res := res*10 + ord(c) - ord('0');
read(c);
pos := pos + 1
end;
result := res;
success := true
end;
I'm trying to make it with the ability to select any number systems up to 36.
procedure ReadLongint (var success : boolean; var result : longint; var notation : char);
var
c : char;
res : longint;
pos : integer;
begin
res := 0;
pos := 0;
repeat
read(c);
pos := pos + 1
until (c <> ' ') and (c <> #10);
while (c <> ' ') and (c <> #10) do
begin
if (notation > #48) and (notation < #58) then
begin
res := res*10 + ord(c) - ord('0');
end;
if (notation > #64) and (notation < #91) then
begin
res := res*10 + ord(c) - ord('0');?????????
end;
read(c);
pos := pos + 1;
end;
result := res;
success := true
end;
I'm trying to make it with the ability to select any number systems up to 36.
When choosing from 2 to 10, the reading algorithm is the same res := res*10 + ord(c) - ord('0');
But how to correctly read the number of systems of calculation, from A to Z?
Tell me, please.

First two counters are never increased in dice rolling application

I am writing a program that rolls two dice and uses an array of counters to show how many times each total is shown. My code compiles fine and does run but for some reason the first two counters are never increased, and seems to print in numeric ascending order - which to me sounds like a problem with my random number function. But I cannot quite see where I have gone wrong. It also never iterates the correct amount of times, about half in fact. Here is my code.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Numerics.Discrete_Random;
-- procedure main - begins program execution
procedure main is
dice1, dice2, diceTotal : Integer;
type Count_Array is array(1 .. 11) of Integer;
intArray : Count_Array;
-- function returnRand - produces a random number and returns it
function returnRand return Integer is
type magicNumber is new Integer range 2 .. 12;
package Rand_Number is new Ada.Numerics.Discrete_Random(magicNumber);
use Rand_Number;
theNumber : magicNumber;
g : Generator;
begin
Reset(g);
theNumber := Random(g);
return Integer(theNumber);
end returnRand;
-- procedure rollDice - rolls two dice 36000 times and tallys the totals
procedure rollDice(dice1 : out Integer; dice2 : out Integer;
diceTotal : out Integer; intArray : in out Count_Array) is
begin
for I in 1 .. 36000 loop
dice1 := returnRand;
dice2 := returnRand;
diceTotal := dice1 + dice2;
if diceTotal = 2 then
intArray(1) := intArray(1) + 1;
elsif diceTotal = 3 then
intArray(2) := intArray(2) + 1;
elsif diceTotal = 4 then
intArray(3) := intArray(3) + 1;
elsif diceTotal = 5 then
intArray(4) := intArray(4) + 1;
elsif diceTotal = 6 then
intArray(5) := intArray(5) + 1;
elsif diceTotal = 7 then
intArray(6) := intArray(6) + 1;
elsif diceTotal = 8 then
intArray(7) := intArray(7) + 1;
elsif diceTotal = 9 then
intArray(8) := intArray(8) + 1;
elsif diceTotal = 10 then
intArray(9) := intArray(9) + 1;
elsif diceTotal = 11 then
intArray(10) := intArray(10) + 1;
elsif diceTotal = 12 then
intArray(11) := intArray(11) + 1;
end if;
end loop;
end rollDice;
-- procedure printResults - prints out the totals of each dice throw
procedure printResults(intArray : in Count_Array) is
begin
Put_Line("Dice Total Tally");
for I in Count_Array'Range loop
-- Set_Col(2);
-- Put(integer'image(I));
-- Set_Col(23);
Put(integer'image(intArray(I)));
New_Line;
end loop;
end printResults;
begin
New_Line;
intArray := (0,0,0,0,0,0,0,0,0,0,0);
rollDice(dice1, dice2, diceTotal, intArray);
printResults(intArray);
New_Line;
end main;
You roll two D11s (range 2..12), not D6s, so when you add them together, you get a range of 4..24 instead of the expected 2..12.
If you used the type system to model the problem, this would have been detected:
type Count_Array is array(2 .. 12) of Integer;
and then your if..elsif construct could be just:
intArray(diceTotal) := intArray(diceTotal) + 1;
Change your magicNumber to a 1..6 range to roll a D6 instead.
Also, there's no need to reset the Generator every time you roll a die. Once is sufficient.
Edit:
You could also go much further with the type system, and do something like this:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
procedure Main is
Number_Of_Dice : constant := 2;
type Die_Range is new Positive range 1 .. 6;
subtype Sums_Range is Die_Range'Base
range Number_Of_Dice*Die_Range'First..Number_Of_Dice*Die_Range'Last;
type Count_Array is array(Sums_Range) of Natural;
package Random_Die is new Ada.Numerics.Discrete_Random(Die_Range);
Die : Random_Die.Generator;
function Roll(Die : Random_Die.Generator) return Die_Range
renames Random_Die.Random;
procedure Roll_Dice(Sums : in out Count_Array) is
Dice_Total : Sums_Range'Base;
begin
for I in 1 .. 36_000 loop
Dice_Total := Roll(Die);
for I in 1..Number_Of_Dice-1 loop
Dice_Total := Dice_Total + Roll(Die);
end loop;
Sums(Dice_Total) := Sums(Dice_Total) + 1;
end loop;
end Roll_Dice;
procedure Print_Results(Sums : in Count_Array) is
begin
Put_Line("Dice Total Tally");
for I in Sums'Range loop
Put(Sums(I)'Image);
New_Line;
end loop;
end Print_Results;
Sums : Count_Array;
begin
Random_Die.Reset(Die);
New_Line;
Sums := (others => 0);
Roll_Dice(Sums);
Print_Results(Sums);
New_Line;
end Main;
Notice how easy this code will be to maintain when the requirements change, for example the number of dice cast per roll, or the type of dice (D4, D6, D8, D12, etc)

Error on running a pl/sql program to find sum of first 10 prime numbers

DECLARE
COUNT NUMBER;
prime NUMBER;
SUM NUMBER;
i NUMBER;
j NUMBER;
BEGIN
SUM := 2;
COUNT := 0;
prime := 1;
i := 3;
WHILE COUNT < 10
LOOP
j := i / 2;
FOR k IN 2 .. j
LOOP
IF i MOD j = 0
THEN
prime := 0;
END IF;
IF prime = 1
THEN
SUM := SUM + i;
COUNT := COUNT + 1;
END IF;
END LOOP;
i := i + 1;
END LOOP;
DBMS_OUTPUT.put_line (SUM);
END;
/
I'm trying to calculate the sum first 10 prime numbers. I wrote the above code but when I try to execute it, it throws an error:
ORA-06550: line 29, column 12: PLS-00103: Encountered the symbol
"+" when expecting one of the following: ( This error corresponds
to the line where I'm incrementing the value of sum.
COUNT and SUM are reserved keywords and must not be choosen as variable-names.
Add a prefix "v":
DECLARE
vCOUNT NUMBER;
prime NUMBER;
vSUM NUMBER;
i NUMBER;
j NUMBER;
BEGIN
vSUM := 2;
vCOUNT := 0;
prime := 1;
i := 3;
WHILE vCOUNT < 10
LOOP
j := i / 2;
FOR k IN 2 .. j
LOOP
IF i MOD j = 0
THEN
prime := 0;
END IF;
IF prime = 1
THEN
vSUM := vSUM + i;
vCOUNT := vCOUNT + 1;
END IF;
END LOOP;
i := i + 1;
END LOOP;
DBMS_OUTPUT.put_line (vSUM);
END;
/
Here a good article about naming-conventions in plsql:
https://www.guru99.com/pl-sql-identifiers.html
The error-message "expecting '('" shows that your db wants something like "SUM(someValue)".
An example would be something like this:
SELECT SUM(col1) FROM mytable

Pascal pointers not behaving as expected

For CodinGame I'm building a referee for a card game called War. Rules described here). TL;DR: the persons with the highest drawn card adds both cards to the bottom of his/her card stack.
I've build a linked-list in Pascal to hold the card stacks. But pascal pointers are not behaving as I expect:
For example, I give the program the following input (slightly modified):
9
8C
KD
AH
QH
3D
KD
AH
QH
6D
9
8D
2D
3H
4D
4S
2D
3H
4D
7H
The example output is:
nrCards: 5
Player1: 13 14 12 6
Player2: 2 3 4 7
Player1: 14 12 6
Player2: 3 4 7
Player1: 12 6
Player2: 4 7
Player1: 6
Player2: 7
Player1:
Player2: 6 7
2 5
I.e., the nextNode pointer of the last element is mostly not updated properly...
Code:
program Answer;
{$H+}
uses sysutils, math, strutils;
type
TNode = record
val : Int32;
nextNode : ^TNode;
end;
TNodePtr = ^TNode;
TNodePtrPtr = ^TNodePtr;
var
size1 : Int32;
size2 : Int32;
cards : Array of TNode;
player1first : TNodePtr = nil;
player1last : TNodePtr = nil;
player2first : TNodePtr = nil;
player2last : TNodePtr = nil;
winnerLast : TNodePtrPtr = nil;
i : Int32;
Line: String;
turns : Int32 = 0;
nrCards : Int32 = 1;
cardIt : TNodePtr = nil;
function ParseIn(i : Int32) : String;
begin
ParseIn := ExtractWord(i, Line, [' ']);
end;
function War(pl1it, pl2it : TNodePtr) : Int32;
var
nrCards : Int32 = 5;
i :Int32; // not reuse?
begin
for i := 0 to 3 do begin
pl1it := pl1it^.nextNode;
pl2it := pl2it^.nextNode;
if (pl1it = nil) or (pl2it = nil) then
exit(0);
end;
while (pl1it^.val = pl2it^.val) do begin
nrCards := nrCards + 4;
for i := 0 to 3 do begin
pl1it := pl1it^.nextNode;
pl2it := pl2it^.nextNode;
if (pl1it = nil) or (pl2it = nil) then
exit(0);
end;
end;
if pl1it^.val > pl2it^.val then
// player 1 wins
War := nrCards
else
// player 2 wins
War := -nrCards;
end;
begin
readln(Line);
size1 := StrToInt(ParseIn(1));
Setlength(cards, size1);
for i := 0 to size1-1 do begin
readln(Line);
//writeln(StdErr, Line);
case Line[1] of
'1' : cards[i].val := 10;
'J' : cards[i].val := 11;
'Q' : cards[i].val := 12;
'K' : cards[i].val := 13;
'A' : cards[i].val := 14;
else cards[i].val := Integer(Line[1])-48;
end;
if i = size1-1 then
cards[i].nextNode := nil
else
cards[i].nextNode := #cards[i+1];
end;
readln(Line);
size2 := StrToInt(ParseIn(1));
Setlength(cards, size1+size2);
for i := size1 to size1+size2-1 do begin
readln(Line);
//writeln(StdErr, Line);
case Line[1] of
'1' : cards[i].val := 10;
'J' : cards[i].val := 11;
'Q' : cards[i].val := 12;
'K' : cards[i].val := 13;
'A' : cards[i].val := 14;
else cards[i].val := Integer(Line[1])-48;
end;
if i = size1+size2-1 then
cards[i].nextNode := nil
else
cards[i].nextNode := #cards[i+1];
end;
player1first := #cards[0];
player1last := #cards[size1-1];
player2first := #cards[size1];
player2last := #cards[size1+size2-1];
// now for the game
while (player1first <> nil) and (player2first <> nil) do begin
if player1first^.val <> player2first^.val then begin
if player1first^.val > player2first^.val then begin
// player 1 wins
writeln(StdErr, 'Player1 wins');
winnerLast := #player1last;
end else begin
// player 2 wins
writeln(StdErr, 'Player2 wins');
winnerLast := #player2last;
end;
winnerLast^^.nextNode := player1first;
winnerLast^ := player1first;
player1first := player1first^.nextNode;
winnerLast^^.nextNode := player2first;
winnerLast^ := player2first;
player2first := player2first^.nextNode;
winnerLast^^.nextNode := nil;
end else begin
// war
nrCards := War(player1first, player2first);
writeln(StdErr, 'nrCards: ', nrCards);
if nrCards = 0 then
break;
if nrCards > 0 then begin
writeln(StdErr, 'Player1 wins');
winnerLast := #player1last;
end else begin
writeln(StdErr, 'Player2 wins');
winnerLast := #player2last;
nrCards := -nrCards;
end;
for i := 0 to nrCards-1 do begin
winnerLast^^.nextNode := player1first;
winnerLast^ := player1first;
player1first := player1first^.nextNode;
end;
for i := 0 to nrCards-1 do begin
winnerLast^^.nextNode := player2first;
winnerLast^ := player2first;
player2first := player2first^.nextNode;
end;
winnerLast^^.nextNode := nil;
end;
turns := turns + 1;
write(StdErr, 'Player1: ');
cardIt := player1first;
while cardIt <> nil do begin
write(StdErr, cardIt^.val, ' ');
cardIt := cardIt^.nextNode;
end;
writeln(StdErr, ' ');
write(StdErr, 'Player2: ');
cardIt := player2first;
while cardIt <> nil do begin
write(StdErr, cardIt^.val, ' ');
cardIt := cardIt^.nextNode;
end;
writeln(StdErr, ' ');
end;
// end game
if nrCards = 0 then
// equal
writeln('PAT')
else if player2first = nil then
// player 2 won
writeln('1 ',turns)
else
// player 2 won
writeln('2 ',turns);
flush(StdErr); flush(output); // DO NOT REMOVE
end.
I have a background in C/C++/C#, which could explain my coding style. The same program in C works correctly. IMHO I've literally translated it...
C code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct TNode {
int val;
struct TNode* nextNode;
};
int War(struct TNode* pl1It, struct TNode* pl2It) {
int nrCards = 5;
for (int i = 0; i < 4; ++i) {
pl1It = pl1It->nextNode;
pl2It = pl2It->nextNode;
if (pl1It == NULL || pl2It == NULL) {
return 0;
}
}
while (pl1It->val == pl2It->val) {
nrCards += 4;
for (int i = 0; i < 4; ++i) {
pl1It = pl1It->nextNode;
pl2It = pl2It->nextNode;
if (pl1It == NULL || pl2It == NULL) {
return 0;
}
}
}
if (pl1It->val > pl2It->val) {
// player 1 wins
return nrCards;
} else {
// player 2 wins
return -nrCards;
}
}
int main()
{
struct TNode cards[52];
int size1;
scanf("%d", &size1);
for (int i = 0; i < size1; ++i) {
char Line[4];
scanf("%s", Line);
if (Line[0] == '1') cards[i].val = 10;
else if (Line[0] == 'J') cards[i].val = 11;
else if (Line[0] == 'Q') cards[i].val = 12;
else if (Line[0] == 'K') cards[i].val = 13;
else if (Line[0] == 'A') cards[i].val = 14;
else cards[i].val = (int)Line[0] - 48;
if (i == size1 - 1) cards[i].nextNode = NULL;
else cards[i].nextNode = &cards[i + 1];
}
int size2;
scanf("%d", &size2);
for (int i = size1; i < size1 + size2; ++i) {
char Line[4];
scanf("%s", Line);
if (Line[0] == '1') cards[i].val = 10;
else if (Line[0] == 'J') cards[i].val = 11;
else if (Line[0] == 'Q') cards[i].val = 12;
else if (Line[0] == 'K') cards[i].val = 13;
else if (Line[0] == 'A') cards[i].val = 14;
else cards[i].val = (int)Line[0] - 48;
if (i == size1 + size2 - 1) cards[i].nextNode = NULL;
else cards[i].nextNode = &cards[i + 1];
}
struct TNode* player1first = &cards[0];
struct TNode* player1last = &cards[size1 - 1];
struct TNode* player2first = &cards[size1];
struct TNode* player2last = &cards[size1 + size2 - 1];
int nrOfCards = 1; // has to do with check
int turns = 0;
// now for the game
while (player1first != NULL && player2first != NULL) {
if (player1first->val != player2first->val) {
struct TNode** winnerLast = NULL;
if (player1first->val > player2first->val) {
// player 1 wins
fprintf(stderr, "Player 1 wins.\n");
winnerLast = &player1last;
} else {
// player 2 wins
fprintf(stderr, "Player 2 wins.\n");
winnerLast = &player2last;
}
(*winnerLast)->nextNode = player1first;
(*winnerLast) = player1first;
player1first = player1first->nextNode;
(*winnerLast)->nextNode = player2first;
(*winnerLast) = player2first;
player2first = player2first->nextNode;
(*winnerLast)->nextNode = NULL;
} else {
// war
fprintf(stderr, "War: ");
nrOfCards = War(player1first, player2first);
if (nrOfCards == 0) break;
struct TNode** winnerLast;
if (nrOfCards > 0) {
// Player 1 wins
fprintf(stderr, "Player 1 wins.\n");
winnerLast = &player1last;
} else {
// Player 2 wins
fprintf(stderr, "Player 2 wins.\n");
nrOfCards = -nrOfCards;
winnerLast = &player2last;
}
for (int i = 0; i < nrOfCards; ++i) {
(*winnerLast)->nextNode = player1first;
(*winnerLast) = player1first;
player1first = player1first->nextNode;
}
for (int i = 0; i < nrOfCards; ++i) {
(*winnerLast)->nextNode = player2first;
(*winnerLast) = player2first;
player2first = player2first->nextNode;
}
(*winnerLast)->nextNode = NULL;
}
turns = turns + 1;
}
// end game
if (nrOfCards == 0) {
// equal
printf("PAT\n");
} else if (player2first == NULL) {
// player 2 won
printf("1 %d\n", turns);
} else {
// player 2 won
printf("2 %d\n", turns);
}
// Write an action using printf(). DON'T FORGET THE TRAILING \n
// To debug: fprintf(stderr, "Debug messages...\n");
return 0;
}
Can somebody explain why pascal pointers are behaving so differently, or what I am doing wrong?
I found the problem, which I do not fully understand yet.
The problem is caused by de use of dynamic array cards. That's also the big difference between the C code and the pascal code. I'm was doing
readln(Line);
size1 := StrToInt(ParseIn(1));
Setlength(cards, size1);
for i := 0 to size1-1 do begin
readln(Line);
[...]
end;
readln(Line);
size2 := StrToInt(ParseIn(1));
Setlength(cards, size1+size2);
for i := size1 to size1+size2-1 do begin
That second Setlength seems to have invalidated the last element of my initial array.. It seems player1last^.nextNode and cards[size-1].nextNode were no longer connected. I don't exactly understand what happened underwater... I can only guess that Setlength reallocates the memory and copies the contents thereby invalidating all existing pointers! If this is the case, this was not properly explained in the tutorials I found.
I could luckily fix this as there are a maximum of 52 cards, so by choosing a fixed-length array I could fix this.
cards : Array[0..51] of TNode;
EDIT:
OK I found a source giving me the answer Dynamic array - Free Pascal wiki
Although writing to elements of dynamic arrays does not create a new instance of the array (no copy-on-write as it exists for Ansistrings) using SetLength on such arrays does create a copy! So if 2 dynamic array variables point to the same array (one has been assigned to the other) they do not do so after using SetLength on one (or both) of them. After the SetLength() call the two variables are distinct arrays whose elements are independent from each other.

Simple Loop getting stuck

I am trying to run this pl/sql code but apparently it is getting stuck in the loop. I think the logic is correct.
DECLARE
v_num1 NUMBER := 1;
v_num2 NUMBER := 1;
v_total NUMBER := 0;
BEGIN
WHILE v_num2 < 6 LOOP
v_total := v_num1 + v_num2;
DBMS_OUTPUT.PUT_LINE(v_num1 || ' + ' || v_num2 || ' = ' || v_total);
IF v_num2 = 5 THEN
v_num2 := 1;
v_num1 := v_num1 + 1;
ELSE
v_num2 := v_num2 + 1;
END IF;
END LOOP;
END;
Well, you keep resetting v_num2 to 1 every time it gets to 5, so v_num2 will always be less than 6 and the loop will run forever.
IF v_num2 = 5 THEN
v_num2 := 1;
v_num1 := v_num1 + 1;
ELSE
v_num2 := v_num2 + 1;
END IF;
You're looping WHILE v_num2 < 6 LOOP
but when v_num2 is 5, then you assign it 1
v_num2 := 1;
so it's never equalling 6 and hence will loop forever.

Resources