Draw a ruler by writing a recursive program (Ada) - ada

By using recursion, I need to write a program that allows the user to write how many sections and how long each section of the ruler should be. And then, based on that information, the program should be able to display the ruler that the user wants. In my code, I have managed to display the size of the ruler. However, I have some difficulty, writing a recursion that displays the length of each section. It seems like my second function (function Count) is somehow invisible because it does not affect the code, whether it exists or not.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
Procedure Ruler is
section, length,Y: Positive;
function Factorial(value, value1: Natural) return Natural is --length of
begin --the ruler
Put("|");
if value > 1 then
return Factorial((value * value1)-1,1);
end if;
end Factorial;
function Count(value,value1: Natural) return natural is --Length of each
Calc: Natural; --section
begin
Calc:= (value*value1)/value;
Set_Col(Positive_Count(Calc));
Put("|");
return Count(1, calc+value1);
end Count;
begin
Put("The number of sections and the length of each section: ");
Get(section); Get(length);
Y:= Factorial(section, length);
Y:= Count(section, length);
end Ruler;
Here is a picture of a ruler with 4 sections and each section is 10 cm long:

So, I'm not sure why recursion is required, but below is an example that does the job. I must admit that it's not the most simple piece of code. The recursion is only a small portion of the code (see the Put_Rec function).
rulers.ads
package Rulers is
procedure Put_Ruler (Length, Minor_Tick, Major_Tick : Positive);
-- Draws a ruler of a given length.
end Rulers;
rulers.adb
with Ada.Strings.Fixed;
with Ada.Text_IO;
with Ada.Integer_Text_IO;
package body Rulers is
type On_Step_Fcn is access procedure (Buffer : out String;
Count : Natural);
--------------------
-- Put_Ruler_Part --
--------------------
procedure Put_Ruler_Part
(Step : Integer;
Last : Integer;
On_First : String;
On_Step : On_Step_Fcn;
On_Last : String)
is
use Ada.Text_IO;
procedure Put_Rec (Count : Natural) is
Buffer : String (1 .. Step);
begin
if Count <= Last then -- Check continuation predicate.
On_Step (Buffer, Count);
Put (Buffer);
Put_Rec (Count + Step); -- Recurse.
end if;
end Put_Rec;
begin
Put (On_First);
Put_Rec (Step); -- Initiate recursion.
Put (On_Last);
New_Line;
end Put_Ruler_Part;
---------------------
-- Step functions --
---------------------
-- Functions that will be called on each recursion. The size of the
-- buffer is dictated by the (step-size known by the) calling function.
use Ada.Strings;
use Ada.Strings.Fixed;
procedure Image_Minor_Tick (Buffer : out String; Count : Natural) is
pragma Unreferenced (Count);
begin
Move ("|", Buffer, Justify => Right);
end Image_Minor_Tick;
procedure Image_Major_Tick (Buffer : out String; Count : Natural) is
pragma Unreferenced (Count);
begin
Move ("|", Buffer, Justify => Right);
end Image_Major_Tick;
procedure Image_Number (Buffer : out String; Count : Natural) is
begin
Move (Count'Image, Buffer, Justify => Right, Drop => Left);
end Image_Number;
---------------
-- Put_Ruler --
---------------
procedure Put_Ruler (Length, Minor_Tick, Major_Tick : Positive) is
begin
-- Minor scale.
Put_Ruler_Part
(Step => Minor_Tick,
Last => Length,
On_First => "|",
On_Step => Image_Minor_Tick'Access,
On_Last => "");
-- Major scale.
Put_Ruler_Part
(Step => Major_Tick,
Last => Length,
On_First => "|",
On_Step => Image_Major_Tick'Access,
On_Last => "");
-- Numbers.
Put_Ruler_Part
(Step => Major_Tick,
Last => Length,
On_First => "0",
On_Step => Image_Number'Access,
On_Last => " cm");
end Put_Ruler;
end Rulers;
main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Rulers; use Rulers;
procedure Main is
begin
Rulers.Put_Ruler
(Length => 40,
Minor_Tick => 1,
Major_Tick => 10);
New_Line;
Rulers.Put_Ruler
(Length => 40,
Minor_Tick => 2,
Major_Tick => 5);
New_Line;
Rulers.Put_Ruler
(Length => 40,
Minor_Tick => 1,
Major_Tick => 1);
New_Line;
end Main;
output
|||||||||||||||||||||||||||||||||||||||||
| | | | |
0 10 20 30 40 cm
| | | | | | | | | | | | | | | | | | | | |
| | | | | | | | |
0 5 10 15 20 25 30 35 40 cm
|||||||||||||||||||||||||||||||||||||||||
|||||||||||||||||||||||||||||||||||||||||
01234567890123456789012345678901234567890 cm

Related

How do I rectify this switch case error in Ada?

with Ada.Text_IO; use Ada.Text_IO;
procedure factor is
rate: Integer;
begin
Put("Enter rate: ");
Get(rate);
case rate is
when 1 | 2 =>
Put("Factor =", factor = 2 * rate - 1);
when 3 | 5 =>
Put("Factor =", factor = 3 * rate + 1);
when 4 =>
Put("Factor =", factor = 4 * rate - 1);
when 6 | 7 | 8 =>
Put("Factor =", factor = rate - 2);
when others =>
Put("Factor =", rate);
end case;
end factor;
I am new to ada and im not able to resolve this error. please help me with this code
this is a simple switch case in ada.. this should return factor and rate is the input from user
Here is a comparison of your program and one that compiles and works correctly:
---------------------------------------------------------------
-- Original program:
--
-- with Ada.Text_IO; use Ada.Text_IO;
-- procedure factor is
-- rate: Integer;
-- begin
-- Put("Enter rate: ");
-- Get(rate);
-- case rate is
-- when 1 | 2 =>
-- Put("Factor =", factor = 2 * rate - 1);
-- when 3 | 5 =>
-- Put("Factor =", factor = 3 * rate + 1);
-- when 4 =>
-- Put("Factor =", factor = 4 * rate - 1);
-- when 6 | 7 | 8 =>
-- Put("Factor =", factor = rate - 2);
-- when others =>
-- Put("Factor =", rate);
-- end case;
-- end factor;
------------------------------------------------------------------
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
rate : Integer;
factor : Integer;
begin
Put ("Enter rate: ");
Get (rate);
case rate is
when 1 | 2 =>
factor := 2 * rate - 1;
when 3 | 5 =>
factor := 3 * rate + 1;
when 4 =>
factor := 4 * rate - 1;
when 6 | 7 | 8 =>
factor := rate - 2;
when others =>
factor := rate;
end case;
Put_Line ("Factor =" & factor'Image);
end Main;
In Ada I/O procedures and functions are tied to the types being read or written. Therefore, reading an Integer requires an instance of Ada.TextIO.Integer_IO. The predefined package Ada.Integer_Text_IO is just such a package. The Get procedure from that package is used to input the value for the rate variable.
In Ada variables must be declared before they are used and they are only declared in the declarative part of a procedure or function; that is, the part of the procedure or function before the reserved word begin. The variable named factor is declared in the declarative part of the procedure main.
The case statement calculates the value of factor based upon the rate input. After the end of the case statement the variable factor has been assigned a value according to the logic in the case statement. It is then output with a trailing newline character using the Put_Line procedure.
The Put_Line procedure requires a single string for its argument. That string is created by concatenating a literal string "Factor =", with the string representation of the value in factor. The 'Image attribute converts the integer value in factor to its corresponding string representation. That string value is concatenated with the literal string forming a single string argument for the Put_Line procedure.
First of all, you did not mention the error you got.
I think you got this first
factor.adb:8:05: no candidate interpretations match the actuals:
factor.adb:8:05: missing argument for parameter "Item" in call to "get" declared at a-textio.ads:239
factor.adb:8:05: missing argument for parameter "Item" in call to "get" declared at a-textio.ads:205
factor.adb:8:09: expected type "Standard.String"
factor.adb:8:09: found type "Standard.Integer"
If you carefully read, you'll see that the compiler complains about the types. It expected Standard.String and got Standard.Integer.
In fact, you used Ada.Text_io which is for text only (cf. ARM).
As you want to get an integer, you must use the integer version for IO i.e. Integer_IO.
For displaying, there are several ways but you can use Integer'Image(my_int)
to convert your integer to a string.
Then check where the variable factor is declared. In fact, you never declared it but don't even have to do so.
Finally check how you can concatenate two strings, you will be able to join the "Factor =" with the integer converted to string.
When you like to get rate from the user it is good to know what rate is.
From the case statement it looks like a rate type could be declared as -
1) type Rate_Type is 1 .. 8;
2) type Rate_Type is new Integer range 1 .. 8;
3) subtype Rate_Type is Integer range 1 .. 8;
Rate : Rate_Type;
In this case (new to Ada) option 3 would be the best option. So now Rate is an Integer in the range from (including) 1 to (including) 8.
To get Rate from the user
package Rate_IO is new Ada.Text_IO.Integer_IO (Rate_Type);
The package Rate_IO is like Ada.Integer_Text_IO but for Rate_Type instead of Integer and Rate is input from the user
Rate_IO.Get (Rate);
The advantage of Rate_IO is that if the user enters a value not in the range of Rate_Type an exception (Data_Error) is raised.
This will cause the program to stop with some message.
It is often a better choice to stop the program than to let it run with a value out of range. At least it makes the program much simpler.
So now that Rate is in range, the case statement looks like
case rate is
when 1 | 2 => factor := 2 * rate - 1;
when 3 | 5 => factor := 3 * rate + 1;
when 4 => factor := 4 * rate - 1;
when 6 | 7 | 8 => factor := 1 * rate - 2;
end case;
Below is a program with an exception handler. And uncommented is an example with a default value for rate.
with ada.text_io; use ada.text_io;
with ada.integer_text_io;
procedure program_2 is
subtype rate_t is integer range 1 .. 8;
package rate_io is new ada.text_io.integer_io (rate_t);
rate : rate_t;
factor : integer;
begin
-- Input
put ("Enter rate: ");
rate_io.get (rate); -- May raise data_error exception
-- Calculate
case rate is
when 1 | 2 => factor := 2 * rate - 1;
when 3 | 5 => factor := 3 * rate + 1;
when 6 | 7 | 8 => factor := 1 * rate - 2;
when 4 => factor := 1 * rate + 0;
end case;
-- Output
put ("factor =");
ada.integer_text_io.put (factor);
new_line;
-- Error handling
exception when data_error =>
put_line ("rate out of range");
end program_2;
-- Put begin/exception/end block around rate_io.get to
-- provide ie a default value:
--
-- begin
-- rate_io.get (rate);
-- exception when data_error =>
-- rate := rate_t'first; -- A default value
-- end;

Get output from array in Ada

I want to print array data user input.
But it give me error. I need to get input from user and store in the array. After this i want to print it also count each duplicate word.
with Ada.Text_IO;
use Ada.Text_IO;
procedure Main is
type String_Val is array (1 .. 100) of Character;
type Int_Val is array (1 .. 100) of Integer;
Data : String_Val;
begin
Put_Line ("Please enter values (use space as seperator)");
for I in 1..String_Val'Length loop
Data(I) := Character'Value(Get_Line);
end loop;
for I in String_Val'Range loop
Put (String_Val (Data));
end loop;
end Main;
The following program reads a string as input, tallies the occurrences of characters in the string and outputs both the input string and the occurrences of each character in the input string.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
type Character_Counts is array (Character) of Natural;
Input : String (1 .. 100); -- String is an array of Character;
Counts : Character_Counts := (Others => 0);
Length : Natural;
begin
Put_Line("Enter a string:");
Get_Line(Item => Input,
Last => Length);
Put_Line ("You entered:");
-- output the data entered by the user
Put_Line(Input(1..Length));
-- Count character occurrences in the string
for I in 1 .. Length loop
Counts(Input(I)) := Counts(Input(I)) + 1;
end loop;
-- output counts of characters in the string
for C in Counts'Range loop
if Counts(C) > 0 then
Put_Line(Character'Image(C) & " : " & Counts(C)'Image);
end if;
end loop;
end Main;
Type Character_Counts is an array of Natural indexed by all the values of type Character. Natural is a pre-defined subtype of integer with a minimum value of 0. The variable Counts is an instance of Character_Counts with all its elements initialized to 0.
The Get_Line procedure returns the string you passed in, filled with characters up to the length of the string or the number of characters entered. The variable Length contains the number of characters entered by the user.
When counting the occurrences of the characters in the string the each character of the string is used as an index into the variable Counts, and the corresponding element in Counts is incremented.
A sample execution of this program is:
Enter a string:
This is a test.
You entered:
This is a test.
' ' : 3
'.' : 1
'T' : 1
'a' : 1
'e' : 1
'h' : 1
'i' : 2
's' : 3
't' : 2

Not able to get get output

declare
num number(5);
rev number(5);
temp number(5);
begin
num:=&num;
while num>0
loop
temp:=mod(num,10);
rev:=(rev*10)+temp;
num:=trunc(num/10);
end loop;
dbms_output.put_line('reversed no:' || rev);
end;
OUTPUT:
Enter value for num: 456
old 6: num:=&num;
new 6: num:=456;
reversed no:
PL/SQL procedure successfully completed.
if have used set serveroutput on;
i am using oracle 11g.
i tried every thing i can think of still having this problem.
The issue lies in the line:
rev := (rev * 10) + temp;
At the point that line is called, rev is null. When you apply mathematical operators to a null value in Oracle, the result is always null.
You can get around this by assigning a value when you declare the variable, i.e.:
DECLARE
num NUMBER(5);
rev NUMBER(5) := 0;
temp NUMBER(5);
BEGIN
num := &num;
WHILE num > 0
LOOP
temp := MOD(num, 10);
rev := (rev * 10) + temp;
num := trunc(num / 10);
END LOOP;
dbms_output.put_line('reversed no: ' || rev);
END;
/
reversed no: 654

Pipe nested object type

I am just trying to achieve pipe row nested type. There are tons of examples around but none that I am able to apply.
My types are:
create type t1_row as object ( a1 number, a2 varchar2(10) );
create type t1_tab as table of t1_row;
create type t2_row as object ( b1 number, b2 varchar2(10), b3 t1_tab );
create type t2_tab as table of t2_row;
I've tried to create a function in so many ways, but none of them are able to compile successfully.
One example:
create or replace function fn (r in number) return t2_row pipelined is
l_row1 t1_tab;
l_row2 t2_tab;
begin
for i in 1..r loop
for j in 1..r loop
l_row1(j).a1 := j;
l_row1(j).a2 := 'a2 ' || j;
end loop;
l_row2(i) := (i,l_row1);
PIPE ROW (l_row2);
end loop;
return;
end;
This code produces the following errors:
[Error] PLS-00630 (1: 12): PLS-00630: pipelined functions must have a supported collection return type
[Error] PLS-00382 (10: 22): PLS-00382: expression is of wrong type
Any help advice or any similar example can be useful.
Version: Oracle 11g Release 11.2.0.1.0
Your construction for t2_row was missing the 2nd parameter, and you are
returning the wrong type. Try this:
create or replace function fn (r in number) return t2_tab pipelined is
l_row1 t1_tab := t1_tab();
l_row2 t2_tab := t2_tab();
begin
for i in 1..r loop
for j in 1..r loop
l_row1.extend(1);
l_row1(j) := t1_row(j,'a2 ' || j);
end loop;
l_row2.extend(1);
l_row2(i) := t2_row(i,'TEST',l_row1);
PIPE ROW (l_row2(i));
end loop;
return;
end;
Also, read this tutorial on how to use pl/sql object collections.
Your code has two syntax errors and a logic error.
The first syntax error is that the function's return type should be a collection not a row type, so
return t2_tab pipelined
The second syntax error is that you need to include the type when instantiating an object, and the number of arguments must match the signature of the type. So the outer loop assignment should be:
l_row2(i) := t2_row(i, 'T2', l_row1);
The logic error is that we don't need to maintain a collection variable for the output. We just need a row variable.
Also the indexed counts seem a bit confused, so my code may differ from your intention.
create or replace function fn (r in number)
return t2_tab pipelined
is
l_tab1 t1_tab;
l_row2 t2_row;
begin
for i in 1..r loop
l_tab1 := new t1_tab();
l_tab1.extend(r);
for j in 1..r loop
l_tab1(j) := t1_row(j*i, 'a2 ' || j);
end loop;
l_row2 := t2_row(i, 'T2', l_tab1);
PIPE ROW (l_row2);
end loop;
return;
end;
/
Here is the run:
SQL> select * from table(fn(3));
B1 B2 B3(A1, A2)
----- --- ---------------------------------------------------------------
1 T2 T1_TAB(T1_ROW(1, 'a2 1'), T1_ROW(2, 'a2 2'), T1_ROW(3, 'a2 3'))
2 T2 T1_TAB(T1_ROW(2, 'a2 1'), T1_ROW(4, 'a2 2'), T1_ROW(6, 'a2 3'))
3 T2 T1_TAB(T1_ROW(3, 'a2 1'), T1_ROW(6, 'a2 2'), T1_ROW(9, 'a2 3'))
SQL>

Bulding a fix length string with values passed using the length/position in pl/sql

I am writing a function which would build a fix a length empty string with value in a fix length string. for e.g.
I have a string of length 1000. When I pass string 'ABC' of length 5 with position 50, the function puts 'ABC' at 50th position of that fixed length string and pads 2 char with ' '.
I have managed to write it using regexp_replace. However I need it which doesnt use regexp_replace as it seems very slow in processing.
This function will be called in batch processing to build message string to be passed to other interface.
create or replace function insert_string(i_value varchar2, i_length number, i_position number) return varchar2
is
fix_string varchar2(1000) := ' ';
begin
fix_string := rpad(fix_string,1000,' ');
fix_string := regexp_replace(fix_string,'.{'||i_length ||'}',rpad(i_value,i_length,' '),i_position,1);
return fix_string;
end;
Something like this:
CREATE OR REPLACE FUNCTION insert_string(i_value VARCHAR2, i_length NUMBER, i_position NUMBER) RETURN VARCHAR2 IS
BEGIN
RETURN RPAD(LPAD(i_value, i_position + LENGTH(i_value) - 1), i_length);
END;
I dont know if this is what youve been trying to do/say but in case it is, ive added another parameter which will contain the source string. Without the string inside the function, its hard to manipulate values.
CREATE OR REPLACE FUNCTION INSERT_STRING(source_string VARCHAR2,
input_string VARCHAR2,
start_position NUMBER,
input_len NUMBER)
RETURN VARCHAR2 AS
TYPE char_arr IS TABLE OF CHAR(1) INDEX BY pls_integer;
TYPE char_arr2 IS TABLE OF CHAR(1);
source_array char_arr2:= char_arr2();
input_array char_arr;
X NUMBER:=1;
new_string VARCHAR2(2000);
BEGIN
FOR i IN 1..LENGTH(source_string) -- converts the source string to array
LOOP
source_array.extend;
source_array(i) := substr( source_string, i, 1 );
END LOOP;
-------------------------------------------------------------------
FOR j IN 1 .. input_len -- converts the input string to array with size input_len
LOOP
input_array(j) := substr( input_string, j, 1 );
END LOOP;
-------------------------------------------------------------------
--dbms_output.put_line(input_array(1));
FOR k IN 1..LENGTH(source_string) -- loop to insert the input_string to the source string
LOOP
IF k >= start_position THEN
source_array.extend;
source_array(k) := input_array(X) ;
x := x+1;
IF x > input_array.count THEN
exit;
end if;
END IF;
END LOOP;
FOR m IN 1 .. LENGTH(source_string) --loop to convert array back to string
LOOP
IF source_array(m) is null THEN
source_array(m) := ' ';
END IF;
new_string := new_string||source_array(m);
END LOOP;
RETURN new_string;
END;
Sample:
select insert_string('**********', 'ABC', 3, 5) from dual;
Output:
INSERT_STRING('**********','ABC',3,5)
**ABC ***
take note.
Source string should not be empty.
the size of the source string should be greater than the size of the input_string else the excess character from the input will not be inserted in the source string

Resources