Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
pp:2024:l10 [2024/05/09 00:58] mihai.udubasa created |
pp:2024:l10 [2024/05/13 16:12] (current) mihai.udubasa |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Lab 9. Algebraic Data Types ====== | + | ====== Lab 10. Algebraic Data Types ====== |
- | Types are an essential component in haskell. They start with capital letters, like ''Int''. We have multiple ways of customizing data types. | + | Types are an essential component in Haskell. They start with capital letters, like ''Int''. We have multiple ways of customizing data types. |
===== Type Aliases ===== | ===== Type Aliases ===== | ||
Line 11: | Line 11: | ||
type Name = String | type Name = String | ||
type PhoneNumber = String | type PhoneNumber = String | ||
- | PhoneBook = Map Name PhoneNumber | + | type PhoneBook = Map Name PhoneNumber |
</code> | </code> | ||
Line 129: | Line 129: | ||
- | After the lab, you can take a look at some more cool stuff related to data types in haskell and functional types in general: | + | After the lab, you can take a look at some more cool stuff related to data types in Haskell and functional types in general: |
[[https://wiki.haskell.org/Unboxed_type|Unboxed types]] | [[https://wiki.haskell.org/Unboxed_type|Unboxed types]] | ||
Line 135: | Line 135: | ||
[[https://www.fpcomplete.com/haskell/tutorial/lens/|Lenses]] | [[https://www.fpcomplete.com/haskell/tutorial/lens/|Lenses]] | ||
- | ===== 9.1. Tournament ===== | + | ===== 10.1. Tournament ===== |
We wish to model a tournament scoring system for 1v1 games such as chess (we will not be referring to the logic of the game itself, only the scorekeeping system). The tournament will have two stages: | We wish to model a tournament scoring system for 1v1 games such as chess (we will not be referring to the logic of the game itself, only the scorekeeping system). The tournament will have two stages: | ||
- | * Group stage: Players are placed into $math[2^n] groups. Each player plays against all other players in the same group. The top 2 players will advance to the elimination stage. | + | * Group stage: Players are placed into $math[2^n] groups. Each player plays against all other players in the same group. The top m players will advance to the elimination stage. |
* Elimination stage: Players are paired up to play against each other. For each matchup, the loser gets eliminated, the winner remains. The process is repeated until a single player remains. | * Elimination stage: Players are paired up to play against each other. For each matchup, the loser gets eliminated, the winner remains. The process is repeated until a single player remains. | ||
- | **9.1.1.** Define the datatypes we will need: | + | **10.1.1.** Define the datatypes we will need: |
<code haskell> | <code haskell> | ||
data MatchResult = ??? -- the result of a match could be a Win, Loss or Draw | data MatchResult = ??? -- the result of a match could be a Win, Loss or Draw | ||
- | data Player = Player {???} -- we care about 3 things: the player's name, elo (floating point which measures the player's strength), and a list of games played (more specifically, their results) | + | data Player = Player {???} -- we care about 3 things: the player's name, elo (floating point which measures the player's strength), and a list of results of past games (call it matchHistory) |
data Tree a = ??? deriving Show -- A binary tree we will use to represent the elimination stage of the tournament | data Tree a = ??? deriving Show -- A binary tree we will use to represent the elimination stage of the tournament | ||
- | type Tournament = Tree Player | ||
</code> | </code> | ||
- | **9.1.2.** We want to be able to show a MatchResult. For this, we could do deriving Show to let GHC derive the implementation, but let's do it ourselves. | + | **10.1.2.** We want to be able to show a MatchResult and a Player. For this, we could do deriving Show to let GHC derive the implementations, but let's do it ourselves. |
<code haskell> | <code haskell> | ||
instance Show MatchResult where | instance Show MatchResult where | ||
+ | ??? | ||
+ | | ||
+ | instance Show Player where | ||
??? | ??? | ||
</code> | </code> | ||
- | **9.1.3.** We will want to update player match history after each match. | + | **10.1.3.** We will want to update player match history after each match. |
<code haskell> | <code haskell> | ||
addResult :: MatchResult -> Player -> Player | addResult :: MatchResult -> Player -> Player | ||
Line 161: | Line 163: | ||
</code> | </code> | ||
- | **9.1.4.** During the group stage of the tournament, we will require a point-based scoring system. A loss is worth 0 points, a win is worth 1, and a draw 0.5. | + | **10.1.4.** During the group stage of the tournament, we will require a point-based scoring system. A loss is worth 0 points, a win is worth 1, and a draw 0.5. |
<code haskell> | <code haskell> | ||
points :: MatchResult -> Float | points :: MatchResult -> Float | ||
Line 167: | Line 169: | ||
</code> | </code> | ||
- | **9.1.5.** To determine the best players from each group, we will need to determine how many points each player scored. | + | **10.1.5.** To determine the best players from each group, we will need to determine how many points each player scored. |
<code haskell> | <code haskell> | ||
score :: Player -> Float | score :: Player -> Float | ||
Line 173: | Line 175: | ||
</code> | </code> | ||
- | **9.1.6.** Finally, for the group stage we will need to sort the players to establish a ranking. The easiest way to do this is to define a order relationship for players, based solely on score (2 players are equal if their scores are equal, similar for greater than and less than relationships) | + | **10.1.6.** For the group stage we will need to sort the players to establish a ranking. The easiest way to do this is to define a order relationship for players, based solely on score (2 players are equal if their scores are equal, similar for greater than and less than relationships) |
<code haskell> | <code haskell> | ||
instance Eq Player where | instance Eq Player where | ||
Line 180: | Line 182: | ||
instance Ord Player where | instance Ord Player where | ||
(<=) = ??? | (<=) = ??? | ||
- | -- haskell can infer implementations for all other operations if the implementation for (<=) is given. | + | -- Haskell can infer implementations for all other operations if the implementation for (<=) is given. |
</code> | </code> | ||
- | **9.1.7.** For simplicity, we will 'simulate' matches between players by looking at their elo. The player with more elo always wins. | + | **10.1.7.** For simplicity, we will 'simulate' matches between players by looking at their elo. The player with more elo always wins. |
<code haskell> | <code haskell> | ||
+ | -- return the players, updated (used for group stages) | ||
playGame :: Player -> Player -> (Player, Player) | playGame :: Player -> Player -> (Player, Player) | ||
- | playGame player1 player2 = ??? | + | playGame = ??? |
+ | -- ex : playGame (Player "A" 1 []) (Player "B" 2 []) == (Player "A" 1 [Loss], Player "B" 2 [Win]) | ||
+ | |||
+ | |||
+ | -- return the winner, and the players, all updated (used for elimination stage). In case of a draw, return any of the players instead of the winner. | ||
+ | playGameWithWinner :: Player -> Player -> (Player, (Player, Player)) | ||
+ | playGameWithWinner = ??? | ||
+ | -- ex : playGameWithWinner (Player "A" 1 []) (Player "B" 2 []) == ((Player "A" 1 [Loss], Player "B" 2 [Win])) | ||
</code> | </code> | ||
- | TODO: | + | **10.1.8.** You are given a player and a list of players, simulate a match between the player and each of the other ones. Return the player and the list of players updated with the results of the matches. |
+ | <code haskell> | ||
+ | playAll :: Player -> [Player] -> (Player, [Player]) | ||
+ | playAll = ??? | ||
+ | </code> | ||
- | Simulate the groups and elimination phases. | + | **10.1.9.** Now, to simulate the group stage: |
- | Code skeleton ? | + | <code haskell> |
- | Sample players (so they can test things faster). | + | {- |
+ | Simulate a single group. Each player will play against all other players exactly once. | ||
+ | Return a list of all players, updated to reflect the results of the matches. Hint: use playAll | ||
+ | -} | ||
+ | playGroup :: [Player] -> [Player] | ||
+ | playGroup players = ??? | ||
+ | {- | ||
+ | Select the best 'm' players from the given group. (Assume the players already have their match history updated). | ||
+ | Return 2 lists: one containing the players which were selected and the other containing all other players. | ||
+ | |||
+ | hint: sort | ||
+ | -} | ||
+ | selectPlayers :: [Player] -> Int -> ([Player], [Player]) | ||
+ | selectPlayers players m = ??? | ||
+ | |||
+ | {- | ||
+ | Given a list of groups, simulate their matches and select the best 'm' players from each, and return 2 lists: the selected players and the rest. | ||
+ | -} | ||
+ | playGroups :: [[Player]] -> Int -> ([Player], [Player]) | ||
+ | playGroups groups m = ??? | ||
+ | </code> | ||
+ | |||
+ | **10.1.10.** Now, we play the elimination phase (you can assume that the number of players is a power of two, so we have a full binary tree): | ||
+ | |||
+ | Given a list of players, turn each of them into a binary tree node. Then, until the list contains a single node, group all nodes in the list in pairs, simulate a match between the players at their roots, and replace each pair with a binary tree containing the winning player in the root and the two original trees as children. Only the top (closest to the root) appearence of each player is required to have up-to-date match history. | ||
+ | |||
+ | <code haskell> | ||
+ | playElimination :: [Player] -> Tree Player | ||
+ | playElimination = ??? | ||
+ | </code> | ||
+ | |||
+ | **10.1.11.** While the ''Tree'' representation may be useful, we will require the final ranking to be in a list format. For each player, keep only the top entry (which will be up-to date in terms of match history). (you can consider all player names to be unique). | ||
+ | |||
+ | <code haskell> | ||
+ | eliminationResults :: Tree Player -> [Player] | ||
+ | eliminationResults = ??? | ||
+ | </code> | ||
+ | |||
+ | **10.1.12.** Finally, it's time to put everything together: | ||
+ | * split the players into ''m'' groups (you choose how this is done) | ||
+ | * simulate the group stage, selecting ''n'' players from each group | ||
+ | * simulate the elimination stage | ||
+ | * return a ranking of all players, sorted in order of descending scores | ||
+ | |||
+ | note: ''n'' and ''m'' should be powers of 2 to properly create the elimination phase. | ||
+ | <code haskell> | ||
+ | runTournament :: [Player] -> Int -> Int -> [Player] | ||
+ | runTournament players n m = ??? | ||
+ | </code> | ||
+ | |||
+ | ===== Example Players ===== | ||
+ | |||
+ | To help you in testing, here is a list of randomly-generated players: | ||
+ | <code haskell> | ||
+ | players :: [Player] | ||
+ | players = [ | ||
+ | Player {name = "Jill Todd", elo = 69.32222, matchHistory = []}, | ||
+ | Player {name = "Cara Wong", elo = 68.451675, matchHistory = []}, | ||
+ | Player {name = "Travis Dunlap", elo = 49.667397, matchHistory = []}, | ||
+ | Player {name = "Adam Mills", elo = 65.36233, matchHistory = []}, | ||
+ | Player {name = "Josephine Barton", elo = 14.974056, matchHistory = []}, | ||
+ | Player {name = "Erica Mendez", elo = 27.466717, matchHistory = []}, | ||
+ | Player {name = "Derrick Simmons", elo = 11.790775, matchHistory = []}, | ||
+ | Player {name = "Paula Hatch", elo = 80.039635, matchHistory = []}, | ||
+ | Player {name = "Patricia Powers", elo = 61.08892, matchHistory = []}, | ||
+ | Player {name = "Luke Neal", elo = 65.933014, matchHistory = []}, | ||
+ | Player {name = "Jackie Stephenson", elo = 86.00121, matchHistory = []}, | ||
+ | Player {name = "Bernice Nixon", elo = 2.8692048, matchHistory = []}, | ||
+ | Player {name = "Brent Cobb", elo = 39.80139, matchHistory = []}, | ||
+ | Player {name = "Bobbie Sanderson", elo = 81.07552, matchHistory = []}, | ||
+ | Player {name = "Zachary Conner", elo = 63.88572, matchHistory = []}, | ||
+ | Player {name = "Shawn Landry", elo = 7.68082, matchHistory = []}, | ||
+ | Player {name = "Mabel Gentry", elo = 88.13421, matchHistory = []}, | ||
+ | Player {name = "Enrique Ali", elo = 9.568502, matchHistory = []}, | ||
+ | Player {name = "Clara McLaughlin", elo = 60.83427, matchHistory = []}, | ||
+ | Player {name = "Jacqueline Connell", elo = 60.091232, matchHistory = []}, | ||
+ | Player {name = "Jared Morgan", elo = 49.84152, matchHistory = []}, | ||
+ | Player {name = "Lorraine Castaneda", elo = 34.701054, matchHistory = []}, | ||
+ | Player {name = "Robin Hurd", elo = 78.33226, matchHistory = []}, | ||
+ | Player {name = "Vince Dunlap", elo = 63.634525, matchHistory = []}, | ||
+ | Player {name = "Elaine Winter", elo = 34.86934, matchHistory = []}, | ||
+ | Player {name = "Bennie Godfrey", elo = 73.81608, matchHistory = []}, | ||
+ | Player {name = "Gale Britton", elo = 16.05768, matchHistory = []}, | ||
+ | Player {name = "Jeanne Mathis", elo = 34.603416, matchHistory = []}, | ||
+ | Player {name = "Aida Greenwood", elo = 8.308169, matchHistory = []}, | ||
+ | Player {name = "Christian Witt", elo = 80.397675, matchHistory = []}, | ||
+ | Player {name = "Cecelia Dyer", elo = 80.657974, matchHistory = []}, | ||
+ | Player {name = "Edwin Gallagher", elo = 14.976497, matchHistory = []}] | ||
+ | |||
+ | </code> | ||