- June 8, 2020
Final ECE15 Spring 2020 Academic Integrity It is vital to be familiar with and follow the academic integrity standards for this class as laid out in the ECE15 Integrity of Scholarship Agreement. These apply to this take-home exam as well. This is a strictly individual exam. You are allowed to use the class materials, such as the lecture slides and recordings, your notes, book chapters, HW assignments, your own HW code, the HW solutions, piazza posts, any C/C++ textbooks, etc. Basically, all these materials you could have conceivably printed out and brought with you to an exam. What you cannot do is go online and search for specific solutions or code. You may search for explanations on concepts but nothing that is related to the specific assignment (e.g., you may try to find videos that help explain the concept of pointers, etc.). You cannot work with someone else, have someone help you or converse with anyone about the assignment, whether they are in the class or not. You may not discuss “ideas” or “strategies” with anyone. You may not ask people online for help. All the work has to be strictly yours, both in concept/ideas and implementation/code. If you have any doubts on what is allowed, ask us. Wrong assumptions are never an excuse. We will strictly enforce all academic integrity standards. Anyone violating them will be reported and will fail the class. Overview For this exam, you are asked to implement components of the game battleship. If you are unfamiliar with the game, you can read about the rules or play an online version. You will not implement a complete game but only some elements that are inspired by this game. Specifically, there is no opponent. Instead, you will place ships on a game board and then shoot at those same ships. Yes, this is not a very appealing game but our goal is to test you on your ability to implement the different core functionalities. The constraints of the general setup are illustrated below. Note that ships can touch, but not overlap. In this example, the board has 7 rows and 10 columns, with three ships (of length 2, 4 and 6) placed in valid positions. This is just an example; more details on what board and ship sizes you need to support are provided when we explain the specific tasks. Logistics We provide you with starter code. To get this code, go to your class accounts and execute the following command: getStarterFinal This will create the directory Final. You will find all the files you need there. We will explain the purpose of each file in the next section. Do not repeat his process; only get the starter code once! To compile your program, the following command creates the executable called run: gcc -std=c99 final.c bship.o -o run Depending on where you are developing your code (e.g., on the class accounts), you can also use the following, shorter command instead. It essentially is an alias for the full command. make You may develop your code on any platform. However, you need to make sure that it compiles and runs properly on the Linux servers. If it does not compile or run there, you will not receive any credit. Unlike the HW assignments, we are not strict on the formatting of the output. There are therefore no test scripts. However, there is a demo version of the program so you can see what a working version looks like. It also helps you answer questions like “what happens if …”; you can just try it out (so please, do this first before asking us). To turn in your final, go to your class account and in the directory with your code run the following command: submitFinal Read the feedback messages. You can submit multiple times and only your last submission is kept. We recommend submitting at various times just in case you lose your code (and we can then just send you your latest submission). To check if your submission was successful, you can run: checkSubmit It will show you a file with your account name followed by “.Final” if everything went well. Starter Code Header File: bship.h We have already implemented several functions for you and put them in a library. You can find the function declarations in the header file bship.h, together with a description of what each function does. You will call these functions in the program you are asked to create. We will refer to these functions as needed when detailing the deliverables for your program. The function implementations themselves are hidden from you; they are in the bship.o file, which is also part of your starter code but it is in a binary (i.e., non-readable) format. In that same bship.h header file, you also find the following constants: ROWS and COLUMNS they specify the dimensions of the board (for the example on page 2, ROWS was 7 and COLUMNS was 10) FLEETSIZE this gives the total number of ships (this will always be 3) When grading, we may change the board size constants (but always keep ROWS and COLUMNS >0 and <30). You may change these constants for testing purposes as well. However, do not change any other parts of the bship.h header file. Finally, in the header file, there is also the definition of the struct Ship. This data structure contains the following information for each ship: length the length of the ship name a string with the name of the ship Main C file: final.c All the code you write must go in the file final.c. It already contains all the header files you need. You cannot include any additional header files or libraries. You can (and should) write additional functions. You cannot use global variables (there is a 40 point penalty if you do use global variables). The code in main() already declares an array to hold all the ships you need to place. It also calls our function initialize_ships() to initialize that array. You should not modify these two lines of code. The function initialize_ships() reads the ship info from the file ships.txt. You can view/modify this file in your text editor. It has a line for each ship, containing the length (a positive integer) followed by the name (a valid string). You can modify this file for testing purposes (we will change this file for grading; i.e., we may change the sizes and names of the ships). There will alway be FLEETSIZE number of ships in this file. Demo: final_demo This executable is a demo of what a completed final should look like. It includes one extra functionality, showing the current state of the board, that you are not explicitly asked to implement. However, while optional, it is highly encouraged that you consider implementing something similar to help you with debugging (but it is not graded). If you do, it is fine if the code you submit also shows the board (similar to what we do in our demo). To execute the demo program, type the command: ./final_demo What to Implement Total: 100 pts In this section, we describe the various functionalities you are asked to implement, as well as how many points they are worth. Make sure that no matter how much you were able to implement, your code compiles. If it does not compile, you will not pass the exam.We highly recommend making regular copies of your code and submitting intermediate working versions (i.e., versions that compile). For each of the functionalities, the points are assigned based on correct execution. However, we may assign partial credit by looking at your code as well. Keep in mind that if your code is not organized clearly, we will not be able to understand it (and thus give partial credit). As such, writing easy to read code with proper comments is important. In addition to the points for the different functionalities (totalling 100 points), there is an additional 10 points of extra credit to be earned for overall coding style. This is to reward students who write well-structured code with appropriate comments. Note that when describing the functionalities to implement, two of them are labeled as “[core]”. We need both of them to work correctly in order to test and grade your code. These core functionalities, while stripped down to the bare minimum, are thus crucial and all others build on top of them. For other parts of the assignment, you can still implement later functionalities even if you didn’t complete earlier ones. Read through the entire assignment first before starting to code. Knowing what all the functionalities are will impact what data structures you use and how you organize your code. For example, we don’t tell you how to represent the board or keep track of any of the information. That is something you can decide. Take some time to plan your approach before you start! Functionality 1: Placing the Ships Part a: Placing the First Ship [core] 10 pts Ask the user where to place a single ship on the board by calling the function ask_input(). If the ship cannot be placed, you should call the function msg_place_failure(). This happens when any part of the ship would fall outside of the board. Otherwise, you should call the function msg_place_success(). You need to implement this functionality to proceed to the remainder of the exam. Together with functionality 2a, it allows us to have a foundation for testing. However, if you are unable to do this, you can instead place a ship of type 1 at coordinates (0,0) in the vertical position and print the following message to screen “Unable to implement 1a. Using default placement instead.\n”. Note that part b will expand on part a. When you implement part b, you will have automatically implemented part a as well, so you may want to consider both together. We have split them here because part a is a core functionality. Also consider combining with part c. The functions ask_input(), msg_place_failure() and msg_place_success() are part of the library we created for you. Their description in bship.h tells you how to call them. The function ask_input() provides the type (a number between 1 and FLEETSIZE), the orientation (the letter ‘V’ for vertical or ‘H’ for horizontal) and the (x,y) coordinates of the bottom left corner of the ship that the user wants to place (see also footnote ). For the example on page 1 2, the green ship corresponds to type 1 (using the example ships.txt), orientation ‘H’ and coordinates x equal to 8 and y equal to 1. The (x,y) for the other two ships are (5,2) and (1,6). The function ask_input() will return valid values for the ship type and orientation, but the x and y coordinates can be any integer. If the user enters * instead of any of the requested inputs, the function returns 0. In that case, your code should not call msg_place_failure() or msg_place_success() but simply proceed with the rest of your program. Part b: Placing Additional Ships 10 pts Place multiple ships on the board, again with the function ask_input(). Each time, call the functions msg_place_failure() and msg_place_success() accordingly. Note that placement also fails if ships overlap. Repeat until all FLEETSIZE ships have been placed. Each ship can be placed on the board only once. If the user entered * in response to any of the questions of ask_input() , the process finishes and the program should proceed to the next functionalities. In this case, only a subset of the 1 Just call the function ask_input() to see how it requests this information from the user. It first asks for the ship type followed by the letter ‘V’ or ‘H’, and then for the x and y coordinates separated by a comma. For the green ship in the example on page 2, the user would therefore need to type 1H in response to the first question and 8,1 in response to the second question. ships would have been placed on the board; all other upcoming tasks should still be supported as normal, just with fewer total ships on the board. Part c: Using a Function 10 pts Place all of functionality 1 inside a function by itself (separate from the other functionalities), which is called from within main() . This function can of course in turn call other functions. Basically, the idea is to use a separate function for your placing-the-ships functionality. Functionality 2: Detecting Hits Part a: Individual Hits [core] 15 pts Use the ask_shot() function to ask the user for (x,y) coordinates to shoot at, separated by a comma. If the user enters * instead, the function returns 0; otherwise it returns 1. Only call ask_shot() if at least one ship was placed successfully (as part of functionality 1). When a shot hits one of the ships on the board in a spot where it had not been hit before, call the function msg_hit_success(). Otherwise (which includes a shot being outside of the board), call the function msg_hit_failure(). Do this repeatedly until the user enters *, at which point the program should proceed to the next steps. Part b: Destroying a Ship 15 pts As part of the functionality of part a, whenever a ship gets completely destroyed (the last hit caused it to have been hit now in all its positions), call the function msg_ship_destroyed(). Pass the name of the ship that has been destroyed as the argument to this function. A ship can only be destroyed once. When all ships have been destroyed, stop calling ask_shot() and the program should proceed to the next steps. This therefore should happen when either the user has entered * or all ships have been destroyed. Part c: Using a Function 10 pts Place all of functionality 2 inside a function by itself (separate from the other functionalities), which is called from within main() . This function can of course in turn call other functions. Basically, the idea is to use a separate function for your detecting-hits functionality. Functionality 3: End of the Game Part a: Reporting the Score 10 pts At the end of the program, report how many total shots the user attempted (combination of successful and unsuccessful ones) by writing this value to a file named score.txt. This file should only contain this value (and nothing else). Part b: Individual Hits 15 pts At the end of the program, call the function msg_end(). As a function argument, pass it a string stored in a dynamic array. It needs to be a dynamic array; otherwise the function msg_end() will have a run-time error since it frees the dynamic memory inside this function. The content of the string should be “The last ship you sunk was of type: ", followed by the name of the last ship that was destroyed (the maximum length of the ship name string is 20). If no ship was destroyed yet, the function msg_end() should not be called. Remember that you cannot include any additional libraries. Functionality 4: Asking for User Input Part a: Implementing the Function 5 pts We gave you the function ask_shot(). Now we ask you to implement that functionality yourself and name the function ask_shot2(). You must use the same function prototype (i.e., the exact same function parameters) as ask_shot() . You may assume that the user enters data of the correct type and formatting, i.e., two integers separated by a comma, or *. You therefore do not need to implement the functionality where you ask the user repeatedly if the format doesn’t match. Your function is a simplified version of our ask_shot() . The input question should be somewhat similar to ours in ask_input() but we are not strict here (i.e., your formatting does not need to match exactly; there is no test script). If you implement ask_shot2() , you must use it in your code. This means you may need to modify your functionality 2 to use ask_shot2() instead of ask_shot() . If you did not implement ask_shot2() , you can just keep on using ask_shot() in your functionality 2.