Task: Develop C_Artist, a modular C program.

C_Artist improves on the Random Painter graphical application already seen as a lecture example program. "Random Painter" uses an array to store a collection of randomly coloured shapes, either squares or circles as filled shapes or outlines. Using an array imposes severe limitations on the user interface: The number of shapes to draw has to be entered by the user on a Windows console prior to drawing. Control of the shapes composition and of the final output is very limited.

C_Artist instead uses a linked list to store the shapes. This enables much more sophisticated control of the screen composition and of final output. A console screen is not needed. The number of shapes is not set once and for ever. The user will interactively control the number and mix of screen shapes. Two new types of shapes, "box" and "ellipse" will be provided. Box replaces "square". It is a rectangle with horizontal and vertical sides. Ellipse is an additional shape. The user now has the choice between 3 different shapes. The user is offered the possibility of displaying all shapes in the list, or only the ellipses, or only the boxes, or only the circles.

  • Students are to re-use, extend and modify the provided "Random Painter" and "Linked List" code to provide the described improved functionality for a new application called C_Artist.
  • Students are to re-use, extend and modify the provided "Random Painter" and "Linked List" code to provide the described improved functionality for a new application called C_Artist.
  • It is essential that the design and implementation extensions do not violate essential principles of structured programming (small single-purpose functions, narrow scope of identifiers, independence of modules) and that they do not breach the requirements given below.

C_Artist: Functional Requirements

The extended functionality of C_Artist is described in the todo list on the main page of the doxygen documentation of Random Painter available in the startup zip and online at http://codefair.net/hit3181/assign2/randomPainter

Todo List

  • Replace the array of shapes by a linked list of shapes
  • Add a couple of possible new shapes: "ellipse" and "box". Ellipse has vertical and horizontal short and long axes, box is a rectangle with horizontal and vertical sides. Remove the "square" shape, too hard to distinguish from a box.
  • Add missing constructor shp_new(...) to allocate memory dynamically to a shape and destructor shp_delete() to release memory previously allocated by shp_new().
  • Modify the user interface to remove the console screen. Take keyboard input from the graphics screen using WinBGIm I/O functions.
  • Enable users to add to the linked list a new shape of a type they select by pressing a lowercase key (say 'c' for circle, 'b' box, or 'e' for ellipse). Keeping the key pressed will allow adding many shapes of that type in rapid succession.
  • Enable users to draw all shapes belonging to one of the types of shapes in the list by pressing an uppercase key (say capital 'C' for circles, 'B' boxes, or 'E' for ellipses).
  • Enable the user to draw all the shapes in the list by pressing 'D' (case insensitive).
  • Enable the user to wipe the screen clear of shapes and empty the list of shapes by pressing 'W' (case insensitive). Memory previously allocated dynamically to the shapes must be freed.
  • Enable the user to quit the application by pressing 'Q' (case insensitive) or the escape [ESC] key.

User interface:

The user interface provides the following functionality:

Opening Screen:

On start-up the screen is black, showing the following prompt on the top line: | [B]ox | | [C]ircle | | [E]llipse | | [D]raw Shapes | | [W]ipe Shapes | | [Q]uit |

New Shape:

Pressing on a lowercase letter 'b' for box, 'c' for circle, or 'e' for ellipse at any time will create a new shape of the relevant type, will append the new shape to the linked list of shapes, will clear the current drawing and draw the requested shape alone. See image.

Draw shapes:

Pressing on letter 'D' or 'd' will clear the current drawing, then draw all the shapes currently in the list onto the viewport. Shapes are drawn on top of each other in the order they were inserted into the list. See image.

Pressing on uppercase 'B' for Box, 'C' for Circle, or 'E' for Ellipse clears the current drawing, then draws only all shapes of the requested type currently in the list onto the viewport. See image.

Wipe shapes:

Pressing on letter 'W' or 'w' empties the current linked list and releases the memory allocated to shapes. The viewport is cleared of all shapes. The screen returns to the same black screen with only a prompt on the top line as the opening screen. See image.

Exiting:

Pressing on letter 'Q' or 'q' or the escape [ESC] key on any screen exits the application.

C_Artist: Technical Requirements

  • The C_Artist application will be developed using the C language (C99 standards) and will be able to compile without warnings and link and run in the Swinburne computer laboratories using a Code::Blocks EDU-Portable WinBGIm project (without a console).
  • Finding all shapes of a specific type in order to draw them (part of the Drawing shapes functionality) will be implemented by extending the Linked List ADT to include lst_findFirst() and lst_findNext() operations to the ADT. The combination of these operations will enable iterating through the list and finding all the data corresponding to specific criteria.
  • The C_Artist application will be modular, using modules based on abstract data structures (ADT) representing a Shape and a Linked List.
  • The application code will be easily maintainable. It will conform to good programming practice and comply with the standards published at http:standards.codecutter.org. In particular:
    • Indentation is consistent and follows the standards. (If you are unable to type according to standards, periodically activate the Source code formatter CodeBlocks plugin (Alt-A)).
    • Identifiers are meaningful (not too abbreviated).
    • Every program file has a basic header comment showing main purpose, @author, @version.
    • Function prototypes have a banner comment in the file header indicating their purpose (@brief), the purpose of individual parameters (@param) and when meaningful, the purpose of the return value (@return). Important pre/post conditions of functions (if any) are also described in their function banner comment (@note).
    • The DoxyBlocks plugin (with the @ flag -please load DoxyBlocks settings from template) can be used in CodeBlocks EP v1.1.x to produce frameworks for function banners.
    • Inline comments are placed in front of any block of code that does something not obvious (Do not overdo inline comments; e.g. do not comment normal language usage. Assume that these comments are aimed at proficient C programmers).
  • Functions will be short and single-purpose (a number of 15-20 lines of code should be taken as a guide for a maximum length).
  • The application will not leak memory. It will always free dynamically allocated memory that is no longer used.
  • The graphic representation will use the simple 2D graphics library WinBGIm provided with Code::Blocks EP. A WinBGIm project must be used and the .cbp file submitted.
  • "Magic number" (unexplained numbers) should be avoided -except for counters like "for(int i = 0;...". Named constants should be used instead (constants may be global, but should be preferably restricted to file scope when necessary. Note that this is done in C by using the "static" modifier.). Exceptions to the "magic number" rule will be made for location values used once only and rarely changed on graphical screens.
  • Except for closely related and very simple entities, each ADT will be declared in a separate interface (C header) file and defined in a separate implementation (xxx.c) file. For the linked list, two separated ADTs (Node & list) are used.
  • Guards are included on all header files to prevent multiple compilations.

C_Artist: Hints and Tips

Provided Startup code:

The provided Random Painter program and the Linked List ADT available on the assignment page make up the start-up code. They can be re-used and extended in your C_Artist implementation.

Incremental Development:

Rather than building everything at once and risk not being able to get anything working if caught by the deadline, it is preferable to proceed in stages, building up and testing part of the new functionality at each stage (this is called incremental development). The marking scheme is designed to support the suggested stages described below.

Suggested Stages:

  • Replace the Random Painter array of shapes by a linked list, but keep the existing user interface. Add the Shape constructor and destructor as described in the todo list. Shapes must now be dynamically allocated when added, and freed when the linked list destructor is called or the list is emptied.
  • Change the user interface to support adding an individual random shape to the list (shape displayed to screen), add support for Box and Ellipse, remove Square, enable drawing all shapes ('D' option), enable removing all shapes from the list and freeing their allocated memory when wiping all shapes off the screen.
  • Add the possibility of displaying only shapes of one type currently in the list by pressing uppercase 'B' for boxes, 'C' for circles, or 'E' for ellipses. This implies traversing the list and drawing only shapes of the selected type. The best way to do this involves an extension of the linked List capabilities by adding lst_findFirst() and lst_findNext() functions (see below).

Design issues:

  • Having more than 2 different shapes requires changing the Shape design. A boolean (circle in this case) can only define 2 different states. Here we need 3, one for each shape type. It is recommended to use an enumeration, say ShapeType with 3 different values, say CIRCLE, BOX and ELLIPSE. The Shape struct will be given one ShapeType data member to replace the circle boolean. Having an enumeration makes for easier maintenance as adding a new shape type (say Hexagon) would be implemented by adding a new value to the enumeration.
  • A shape needs another dimension in order to accommodate both its width and height. A size data member for the shape dimension is no longer sufficient.
  • In order to keep functions small and single-purpose (an essential requirement), the Shape drawing function shp_draw() should call separate drawing subfunctions for different shape types. However you may note that a circle is really an ellipse with the long and short axes of the same length, so a single shp_drawEllipse() function may do the job for both circle and ellipse. You would need only 2 subfunctions, shp_drawEllipse() and shp_drawBox().
  • Note that several functions are available in the generic linked list to empty, clean, or destroy a linked list. Please read the function banner comments carefully to decide which one to use to do a proper job of emptying the list of shapes and to avoid a memory leak.
  • To display only the shapes of one type in the list you will need to traverse the list, find all the shapes of that specific type and draw them. This can be done in several manners.

The superior way to do it and a way to enhance maintainability of the code, is to extend the Linked List ADT in order to enable finding all nodes in a list that conform to specific criteria and obtaining their data -the shape in this case (This is listed as Technical Requirement 2).

These functions can be easily implemented by using a function pointer in a manner similar to the lst_findData() function, but using the lst_first() and lst_next() functions to traverse the list and find all the nodes containing data with specific characteristics.

The Module 6 RobotList example code seen in lectures illustrates the use of function pointers in functions cullOddOnes() and cullEvenOnes(). These functions pass function pointers to lst_findData().

WinBGIm issues:

WinBGIm functions reference and examples are available on the CodeBlocks-EP menu:

[Help]‐>[Programmer& Guides& (HTML)].& On& the& browser& page,& select& 6.& WinBGIm& Library.

Most WinBGIm functions needed are already used in the Random Painter startup code. The functions likely to be needed are:

initwindow() getch() fillellipse() ellipse() setfillstyle() rectangle() fillpoly() delay() clearviewport() setviewport() settextstyle() setcolor() outtextxy()

Note that Box is more complex to draw than ellipse and circle. You will have to define a polygon with 4 vertices as an array of 8 integers and call fillpoly() to draw a box as a filled rectangle. Function rectangle() is easier to use and is called to draw a box as an outline.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.