Authors: Owain, Han, Gabriel
What is the problem?
Our goal is to implement the game high/low using Haskell. High/Low is a casino card game in which a single player attempts to guess if the next card dealt will be higher or lower than the previous one. The payout varies based on what the previous card is and what the player guesses the next one will be. For example, if the previous card is a 3, the payout would be much higher for correctly guessing low than for correctly guessing high.
What is the something extra?
Read the README.md on github to get full breakdown of feature functionality
- A card system (eg. Ace, 8, Jack, Queen, King)
- A shuffling algorithm
- A betting/payment system
- A Chip (eg. 10$, 25$, 100$ chips will be accrued and transacted with)
- A Search Algorithm to search for best chip conversion
- A Text based UI
- Previously, we intended a GUI (Gloss) to play the game
What did we learn from doing this?
Here we discuss our insights, grievances, and overall impressions on our journey throughout this project.
I do think that functional programming was suitable for this task, we were able to construct our game by building different functions for various use cases (Object creation, Getters, Chip calculation, number to name converter, shuffle, etc..)
However, I miss the capability of storing a global variable to keep track of our mutable data. Instead, we had to pass a State object through recursion to keep track of modified data. The difficult part about this approach is that if you wanted to construct an object with many properties, it will become hard to manage. For example, our state object has 9 properties, each time we wanted to modify a single property, we had to reconstruct the whole object and return it instead of modifying a single property of a global object.
For the scope of the application, functional programming was definitely suitable for this task. However, we start to dread the cumulative effect of the annoyances we encountered if we were to develop a larger application.
Initially, we set out to do a GUI using Gloss. In the process, we read and researched how Gloss functions are used and how to install it. However. we were having difficulty getting Gloss to work (be recognized as a import on Graphics.Gloss). In particular, we were having issues with another missing import freeGlut that Gloss requires (But apparently should be installed with the Haskell Platform). Scouring the internet, it seemed to require very manual and otherwise tricky fixes to resolve it. Ultimately, this led us to discard the idea of developing a GUI and instead opt to represent out UI through text.
From this experience, I gathered
Haskell doesn't seem to have much resources for GUI overall.
- This might just be Haskell in general as I feel its apparent lack of popularity makes it hard to find an abundance of troubleshooting solutions.
Package management in Haskell can be finicky.
- There are multiple dependencies and installation methods such that at times it feels very tedious and overwhelming to manage all the packages.
- Even using cabal's package management and trying to follow a guide to edit the file, my computer still cannot recognize Gloss
- This is further an ordeal with that fact that there are differences between OS's.
- I recall looking at the Piazza and seeing some people having no issues while others encountering similar issues to me.
- Likewise this applies to the instructions/commands/help given on forums too as they might be intended to help mac users.
- For instance, users would point out "install haskell-platform" when on windows it is "install haskell-dev". This fix for freeGlut didn't work for me.
Though I did learn,
When trying to install Gloss, I found there were other options that I didn't previously use (stack, cabal) to manage packages.
I figured out the usage of Stack and Stack ghci and now have a method to install some libraries.
- I used stack install for Random package and used stack ghci to load my modules correctly.
I did read up on Gloss and have a better gauge of Haskell's GUI capabilities
- My impression so far is that Haskell is not ideal for GUI development
In implementing the Chip conversion algorithm using BFS and memoization, I found it pleasantly surprising how much shorter and concise the code was compared to my previous exposure to memoization implementation.
- Initially, my pure BFS algorithm hanged the console for a long duration (not completing even) for values of about n = $100.
- In my case, the branching factor was 8 and so at depth 3, there would be about 8^3 computations at minimum with the naïve approach.
- After implementation, I could do much larger values and actually have it run to completion (ex. n = 10000 + worked)
- On the other hand, memoization should give about O(n) which is much better.
The simplicity and improved performance of my final implementation leads me to be convinced that Haskell was a fitting language and this notion would likely apply in implementation of other algorithms too.
I often found I was missing some of the conveniences of other languages.
I found that since everything has to have a value, I often needed to workaround making a "void" function or other control flow ideas I have.
- For instance, I needed to branch a lot of If-then-else instead of (in another language) doing a pure if-then to optionally perform some functionality
I've come to miss other conveniences I'm used to like
- The fact that branching or "do" is needed when doing multiple lines
- I also miss storing a local variable for multiple use in the function
I also disliked working with the custom types/data,
- Unless I use the pattern matching for every usage I couldn't get its properties like that I would in another language
- This would lead me to create getters for each property which is quite cumbersome
- Also, I felt polymorphism and sub-class functions for our Chips variations would have been really helpful and more organized
In terms of this rationalization implementations with other-language mindset, Haskell introduces tedium when returning from functions and passing variables or values to one another
- An example is an edit-arg-property function needs to "re-instantiate" the whole object when returning
This is simply a new way of thinking people will have to adapt to when using Haskell.
- It might interfere with how existing programmers rationalize how they will implement their algorithms, but the simplicity of the final implementation is very concise.
- Haskell is a good fit for algorithm implementations.
- I can easily imagine apply our algorithms to other use cases or applications beyond our project.
- A think part of why it felt so seamless to implement is due to the pattern matching of arguments
Haskell and functional programming is suitable for this task of building a card game.
In particular, we found its strengths lie in implementing algorithms
- Though the coding itself we find lacks a lot of quality of life we commonly use in other languages and can be tiresome
Haskell seems weaker in GUI development
- It is not necessarily the GUI's capabilities that are weak. Instead, it is the resources and package management that hinder it.
It can be difficult to apply thinking and class structures from other languages
- Though we imagine this might be due to our experience with the language