DEV Community

Cover image for It's time for war. Code. War
Jeremy Ward 😎🤓
Jeremy Ward 😎🤓

Posted on

It's time for war. Code. War

Round 1. Day 4

Now equiped with the knowledge of elixir basics from ElixirSchool, I figure it is time I start practicing, and building my first elixir app. I started of today's practice with a code challenge from CodeWars. The Instructions were as follows:

Consider an array/list of sheep where some sheep may be missing from their place. We need a function that counts the number of sheep present in the array (true means present).
For example,

[true,  true,  true,  false,
  true,  true,  true,  true ,
  true,  false, true,  false,
  true,  false, false, true ,
  true,  true,  true,  true ,
  false, false, true,  true]
Enter fullscreen mode Exit fullscreen mode

The correct answer would be 17.



The boilerplate code for this challenge was:

defmodule Shepherd do
  def count_sheeps(sheeps) do
    # TODO: for Elixir only true/false values can be presented the in sheeps list
  end
end
Enter fullscreen mode Exit fullscreen mode

This challenge didn't seem too hard and it also felt a little familiar. I quickly went through my elixir school notes, and found a recursive counting function that would be a good template for solving this challenge. In the elixir school functions there was a function that counted the length of an array.

defmodule Length do
  def of([]), do: 0
  def of([_ | tail]), do: 1 + of(tail)
end
Enter fullscreen mode Exit fullscreen mode

If we combine this logic with a little bit of pattern matching it should do the trick. And it did!

Spoiler Alert

WARNING: if you would like to try to solve the same codewar challenge, don't scroll any further.

Solution

defmodule Shepherd do
  # This form of the function was taken directly from the example at elixir
  # school.
  def count_sheeps([]), do: 0
  # Next, we write a form of the function that pattern matches the first
  # element to see if it is "true". If it is, we add 1.
  def count_sheeps([true | tail]), do: 1 + count_sheeps(tail)
  # All other elements will count as 0.
  def count_sheeps([_ | tail]), do: 0 + count_sheeps(tail)
end
Enter fullscreen mode Exit fullscreen mode

My First Elixir App

When I first learned ruby over 6 years ago, my first ruby app was a cli blackjack game. If it was good enough to start learning ruby, it should be good practice for elixir as well.

The app is still a work in progress, but here is what I've done so far. I started by creating a new mix project which was probably a bit over kill. /shrug The first thing black jack needs is cards. So, I started by creating a Card Struct.
lib/card.ex

defmodule Card do
  defstruct suit: "", value: ""
end
Enter fullscreen mode Exit fullscreen mode

And each card will be part of a Deck, so let's go ahead and create a Deck struct too. It was at this point, I felt like my Object Oriented Programming mindset was having an affect on the way I was writing elixir, but I kept going.

lib/deck.ex

defmodule Deck do
  # I used Module constants to specify the different suits and the card values.
  @suits [:heart, :diamond, :club, :spade]
  @values ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]

  # To generate the deck, we flat_map the @suits List using the shorthand
  # function syntax to pass the suit into the `Deck.build_suit/1` function.
  # Then, the List returned from the flat_map is shuffled using `Enum.shuffle`
  def generate do
    @suits
    |> Enum.flat_map(&(build_suit(&1)))
    |> Enum.shuffle()
  end

  # the `Deck.build_suit/1` function maps over the @values List and creates
  # %Card structs using the given suit and card value.
  defp build_suit(suit) do
    @values |> Enum.map(fn (value) -> %Card{ suit: suit, value: value } end)
  end
end
Enter fullscreen mode Exit fullscreen mode

Not a bad start. However, I spun my wheels trying to figure out how I would store the state of the game, and handle the initial deal. I was finally able to scrap together something that worked, but it's definitely subject to change.

defmodule Game do
  # I figured I could use a %Game struct to store the players and the current game's cards.
  # This will allow me to keep up with what a player's hand is as well as what
  # cards are still in play.
  defstruct players: [%Player{name: "player_one"}, %Player{name: "dealer"}], cards: Deck.generate()

  # With recursion on my mind from the earlier CodeWar Challenge, I created a
  # recursive deal function that would deal cards from the deck until each play
  # had their initial 2 cards.
  def deal(game) do
    cond do
      # The first conditional checks to see if all players have 2 cards
      Game.cards_dealt(game.players) -> game
      # The catch all conditional will deal a card to the first player in the
      # %Game struct then call deal again.
      true -> game |> deal_card(hd(game.players)) |> deal
    end
  end

  # deal_card/2 handles a couple of things.
  # 1. We pattern match the first `card` from the %Game.cards and the rest of
  # the cards. This essentially pulls a card from the deck.
  # 2. We update the %Game.players by giving the first `card` to the given player.
  # 3. Finally, we update the %Game struct cards to the `tail` from the original game argument.
  def deal_card(%{cards: [card | cards]} = game, player) do
    game
    |> update_players(Player.add_cards(player, card))
    |> case do
      game -> %{ game | cards: cards}
    end
  end

  def cards_dealt(players) do
    Enum.reduce(players, 0, fn player, acc -> acc + length(player.hand) end) == length(players) * 2
  end

  defp update_players(game, player) do
    players = game.players |> Enum.filter(fn (p) -> p.name != player.name end)

    # ++/2 is slower, but it makes it easier to deal the cards
    %{ game | players: players ++ [player]}
  end
end
Enter fullscreen mode Exit fullscreen mode

I'd love to hear any thoughts about how to handle this better. You can drop a comment down below, or open up a pull request at https://github.com/basicBrogrammer/blackjack_cli. Thanks for tuning in and I'll see ya tomorrow.

Follow Me @

Twitter | Instagram

Top comments (1)

Collapse
 
mr_rob0t profile image
Mark Eliot

Now this seems like an interesting language. Can you tell me what elixir is usually used for? Like web dev back end stuff or maybe you could use it for both or something else entirely! Please let me know; take it easy, man!