Search for question
Question

COM2108 FUNCTIONAL PROGRAMMING GRADING ASSIGNMENT This is a grading assignment, hence worth 60% of your overall mark if you pass the threshold assessment. The flip side is that if you pass the threshold assessment, you get 40% for the module even if you get 0 on this assignment. The grading assignment deadline is before the later threshold assessment attempt sittings, so you should aim to attempt this assignment even if you have not yet passed the threshold assessment. The work you do on this assignment should improve your understanding of threshold concepts and so help you perform better on the threshold assessment. INTRODUCTION This programming assignment is based around the game of dominos. The first thing to do, if you are not already familiar with the game, is to learn about it. Wikipedia can help you here: http://en.wikipedia.org/wiki/Dominos Here is an example of a dominos board part-way through a game left end right end Board1 . • If the next player has in her hand the following: Hand1 at the left end or Then she may play at the right end of the above board. The other dominos may not be played. Some dominos games allow plays up and down as well as left and right from a double, otherwise known as a "spinner", but we will not allow such moves. A standard set of dominos contains all the permutations from to, 28 in all. There are many variations on the games of dominos and how it is scored. In this assignment you will implement fives-and-threes dominos players (details to follow) and test them against each other by playing simulated matches. Some hints are provided about good play. You should experiment with your dominos players to see if implementing each hint does indeed improve the player's game. You are not expected to program all the hints and you may try other tactics. PLAYING A ROUND OF FIVES-AND-THREES DOMINOS To play a round of fives-and-threes dominos, you proceed as follows: • • • Each player starts with a hand of N dominos. The remaining dominos take no part in this round – they are 'sleeping'. N is usually 7, but a variation of the rules uses 9 dominos if there are only two players. Players add a domino to the board ('dropping' a domino) in turn and accumulate the fives-and-threes scores of their 'drops'. See below for details of how the score is calculated after each drop. The player who drops the first domino gets the fives-and-threes score of its total spots (e.g. if the first drop is which we will represent by (4,5), the player who dropped it scores 3 - full details of how to calculate the score are provided below). If a player does not have a domino that they can play on the current board, they 'knock' to indicate that they are skipping their turn. They cannot knock if they have a domino that they can play. Play continues until neither player can play (either because each player has run out of dominos or is knocking). If a player 'chips out' (plays a domino so that they have no dominos left in their hand) they score one point for this (on top of whatever they score for playing the tile). SCORING FOR Fives-and-THREES DOMINOS After a player has added a domino to the layout, the pips (number of dots) on the two open ends are added up. Points are awarded as follows: Pip total Score Justification 3 1 One 3 5 1 One 5 6 2 Two 3s 9 3 Three 3s 10 2 12 4 15 8 Two 5s Four 3s Five 3s and Three 5s 18 6 Six 3s 20 4 Four 5s Other values 0 Not a multiple of 5 or 3 PLAYING A MATCH OF FIVES-AND-THREES DOMINOS A 2-player fives-and-threes dominos match is organised as follows: A match consists of N games, typically 3 in a real-life setting. The winner is the player who has won most games. With our tireless computer players, N can be much greater than 3. • Each game involves a sequence of rounds (as defined above). The two players take it in turns to drop first in each round. COM2108: Functional Programming - Autumn 2023 2 • A game terminates when one player or the other wins by achieving an accumulated score, over the rounds, of exactly V, where V is the target value. V is typically 61, but a different value can be chosen, such as 31 or 121. At the end of a round, if neither player has reached V, a new round starts, and the scores obtained within this round are added on to the scores after the last round. You must finish exactly, for example if your target is 61 and your score is 59, you need to play a domino which scores 2 to win the game... but if that domino is your last domino, you need to score just 1 from the domino that you play, because you also get a point for “chipping out." If you score more than the target ('going bust'), your score remains the same (e.g. if the target is 61, your score is 59 and you play a domino which scores 4, your score remains at 59). WHAT IS BEING ASSESSED In this assignment, we are not looking at who can write code to produce the best fives-and-threes dominos player. If you would like to try that challenge, you will have that opportunity at the end of semester, but that will not impact upon your mark for this module. What we are assessing here is: 1. The design of your solution, demonstrating that you have given some thought to the design of your player. It should be clear that you have given thought to the functional decomposition, and that you have experimented with the suggested strategies. (20%) 2. The testing of your solution, evidencing that you have tested your code thoroughly. You should not provide a random set of test data and output. You should give a rationale for the test cases that you have chosen. You may illustrate you testing with a carefully selected set of examples demonstrating that a function is working as intended, but make sure that it is clear to the reader why this set has been chosen. (30%) 3. The implementation of your solution, for both correctness and clarity. Your code should do what it is intended to do, but it should also be well-presented and understandable by others. This means sensible layout, code presented in a logical order, good choice of function and parameter names, consistency in style, clear comments (header documentation, function documentation, inline documentation where it is needed). (40%) 4. Your critical reflection about what you have learned when studying functional programming. (10%) More detail on each of these points is provided towards the end of this document. DOMSMATCH.HS You should take a copy of DomsMatch.hs from Blackboard and add your code to the bottom of this file. Note that near the top of this file there is the line "import System.Random”. System.Random is a library which is not installed by default, but it is essential in this project. You need to install it outside of ghci, at the command/terminal prompt, using the command: cabal install --lib random Once you have done this, start ghci, then type import System.Random COM2108: Functional Programming - Autumn 2023 3 at the Haskell prompt. If you don't get an error, you have successfully installed the library. This is the only library that you should install this way. If you try to use any other libraries that you have installed this way, your code will not run when it is submitted. This will result in a score of 0 for the implementation. DATATYPES The key datatypes are provided for you in the file DomsMatch.hs. You should not change these datatypes. These are: • Domino - representing a domino tile. • DominoBoard - which contains a current board state - - either the initial (that is, empty) board, or the current state, represented by: the left-most domino (with left-most pips in the first position in the tuple), the right-most domino (with right-most pips in the second position in the tuple), and the history of the game. • History - the layout of the board from left at the start of the list to right at the end of the list, where each domino is combined with which player played it and which turn at which it was played. • Player - essentially two labels to identify the individual players. • End indicating the end at which a tile is placed. • Scores - a tuple of scores representing (player 1's score, player 2's score) MoveNum to keep track of what was played when. • • Hand a set of dominos • DomsPlayer - this is the type of a function. A function of this type will return the move that it will make given the current Hand, Board, and Scores (Player is also an argument, indicating which player this player is, which may be useful if you wish to refer to the History when deciding on your move.) You can add extra datatypes if you wish. SCAFFOLDING FUNCTIONS A number of scaffolding functions are provided for you in DomsMatch.hs. The top-level function is domsMatch which as the name implies, plays a dominos match. It takes six arguments: the number of games to play in a match, the initial number of dominos in a hand, the target score, the two player functions, and a seed for the random number generator. Lower-level functions play a dominos game and a dominos round. Right now, these functions don't work properly, because they depend upon scoreBoard, blocked and playDom which are currently incorrectly implemented. The first thing you need to do is implement these functions. SCORING A BOARD The first function you must implement is scoreBoard. scoreBoard takes a Board and a Bool as arguments, where the Bool is True if the domino just played was the last domino from the hand, and False otherwise, and returns the score that would be received by creating this board state. For example, if the first player played (4,5), the board would contain just this domino, and so would score 3 (three threes - unless for some weird reason you were playing with an initial hand size of 1, in which case the score would be 2). If the next domino played was a (5,1) (which could only be played to the right end), the score on this board ([(4,5)(5,1)]) would be 1 (4+1 = 5; one five – again, unless you were playing with an initial hand size of 2...). COM2108: Functional Programming - Autumn 2023 4 Currently this function simply returns 0 for every input. CHECKING IF A PLAYER IS BLOCKED The next function to implement is blocked. blocked takes a Hand and a Board and is meant to return True only if there is no domino in the hand that can be played on the board. Currently this function always returns True. PLAYING A DOMINO Now you need to implement playDom, which given a Domino, a Board and an End, should play the domino at the given end if it is possible to play it there. The return type should be a Maybe Board. (See Errors and Uncertainty recording.) Currently this function always returns Nothing, but it should only return Nothing if it is not possible to play that domino at that end on the board. OTHER POSSIBLE BASIC FUNCTIONS Some other functions that might be useful include: • canPlay: a predicate (function that returns True or False) given a Domino, an End and a Board, returns True if the domino can be played at the given end the board. • played: a predicate returning True if a given Domino has already been played on a given Board. • • possPlays: given a Hand and a Board, return all the Dominos which may be played at the left End and all those that may be played at the right End. The return type should be a pair, where each item in the pair is a list of dominos. doms2scoreN: given a Board and an Int n, return all the Dominos not already played which could be played to give a fives-and-threes score of n and the End at which to play each one. You do not have to implement these functions; and before you even think about implementing them, you should complete your design and identify where (if anywhere) they will be used. You are certainly going to need to implement other functions than these as well. CREATING A SIMPLE PLAYER In DomsMatch.hs, you are provided with a data type for a DomsPlayer. This type is for a function that, given a particular Hand, Board, Player and Scores it returns a tuple (Domino, End) indicating the domino to be played and the end at which to play it. You must implement a function that will play a valid move when called. You should not attempt to implement any sophisticated reasoning at this stage. Your function must be called simplePlayer and it must be of type DomsPlayer. You do not have to check is it is possible to play a domino; you can assume that this function will only be called if the player has at least one domino in their hand that can be played on the current board. Remember, just one simple opponent is all that is needed at this stage. CREATING A "Smart” PlayER COM2108: Functional Programming - Autumn 2023 5