Skip to content

Commit 5408b8b

Browse files
Article: R1.D4
1 parent e8f6340 commit 5408b8b

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

content/articles/round-1-day-4.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
title: It's time for war. Code. War
3+
published: true
4+
description: Day 4 of my first round of 100DaysOfCode. Time for practice.
5+
tags: 100daysofcode, elixir
6+
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1613441788636/o9mexGvaa.jpeg?auto=compress
7+
datePosted: '2021-02-15'
8+
devToId: 605183
9+
---
10+
11+
# Round 1. Day 4
12+
13+
Now equiped with the knowledge of elixir basics from [ElixirSchool](https://elixirschool.com/en/lessons/basics/basics/), 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](https://www.codewars.com/kata/54edbc7200b811e956000556/train/elixir). The Instructions were as follows:
14+
15+
<br>
16+
17+
> 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).
18+
> For example,
19+
20+
```elixir
21+
[true, true, true, false,
22+
true, true, true, true ,
23+
true, false, true, false,
24+
true, false, false, true ,
25+
true, true, true, true ,
26+
false, false, true, true]
27+
```
28+
29+
> The correct answer would be `17`.
30+
31+
<br>
32+
The boilerplate code for this challenge was:
33+
34+
```elixir
35+
defmodule Shepherd do
36+
def count_sheeps(sheeps) do
37+
# TODO: for Elixir only true/false values can be presented the in sheeps list
38+
end
39+
end
40+
```
41+
42+
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](https://elixirschool.com/en/lessons/basics/functions/) there was a function that counted the length of an array.
43+
44+
```elixir
45+
defmodule Length do
46+
def of([]), do: 0
47+
def of([_ | tail]), do: 1 + of(tail)
48+
end
49+
```
50+
51+
If we combine this logic with a little bit of pattern matching it should do the trick. And it did!
52+
53+
<br>
54+
55+
# Spoiler Alert
56+
57+
WARNING: if you would like to try to solve the same codewar challenge, don't scroll any further.
58+
59+
<br>
60+
61+
## Solution
62+
63+
```elixir
64+
defmodule Shepherd do
65+
# This form of the function was taken directly from the example at elixir
66+
# school.
67+
def count_sheeps([]), do: 0
68+
# Next, we write a form of the function that pattern matches the first
69+
# element to see if it is "true". If it is, we add 1.
70+
def count_sheeps([true | tail]), do: 1 + count_sheeps(tail)
71+
# All other elements will count as 0.
72+
def count_sheeps([_ | tail]), do: 0 + count_sheeps(tail)
73+
end
74+
```
75+
76+
## My First Elixir App
77+
78+
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.
79+
80+
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.
81+
`lib/card.ex`
82+
83+
```elixir
84+
defmodule Card do
85+
defstruct suit: "", value: ""
86+
end
87+
```
88+
89+
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.
90+
91+
`lib/deck.ex`
92+
93+
```elixir
94+
defmodule Deck do
95+
# I used Module constants to specify the different suits and the card values.
96+
@suits [:heart, :diamond, :club, :spade]
97+
@values ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
98+
99+
# To generate the deck, we flat_map the @suits List using the shorthand
100+
# function syntax to pass the suit into the `Deck.build_suit/1` function.
101+
# Then, the List returned from the flat_map is shuffled using `Enum.shuffle`
102+
def generate do
103+
@suits
104+
|> Enum.flat_map(&(build_suit(&1)))
105+
|> Enum.shuffle()
106+
end
107+
108+
# the `Deck.build_suit/1` function maps over the @values List and creates
109+
# %Card structs using the given suit and card value.
110+
defp build_suit(suit) do
111+
@values |> Enum.map(fn (value) -> %Card{ suit: suit, value: value } end)
112+
end
113+
end
114+
```
115+
116+
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.
117+
118+
```elixir
119+
defmodule Game do
120+
# I figured I could use a %Game struct to store the players and the current game's cards.
121+
# This will allow me to keep up with what a player's hand is as well as what
122+
# cards are still in play.
123+
defstruct players: [%Player{name: "player_one"}, %Player{name: "dealer"}], cards: Deck.generate()
124+
125+
# With recursion on my mind from the earlier CodeWar Challenge, I created a
126+
# recursive deal function that would deal cards from the deck until each play
127+
# had their initial 2 cards.
128+
def deal(game) do
129+
cond do
130+
# The first conditional checks to see if all players have 2 cards
131+
Game.cards_dealt(game.players) -> game
132+
# The catch all conditional will deal a card to the first player in the
133+
# %Game struct then call deal again.
134+
true -> game |> deal_card(hd(game.players)) |> deal
135+
end
136+
end
137+
138+
# deal_card/2 handles a couple of things.
139+
# 1. We pattern match the first `card` from the %Game.cards and the rest of
140+
# the cards. This essentially pulls a card from the deck.
141+
# 2. We update the %Game.players by giving the first `card` to the given player.
142+
# 3. Finally, we update the %Game struct cards to the `tail` from the original game argument.
143+
def deal_card(%{cards: [card | cards]} = game, player) do
144+
game
145+
|> update_players(Player.add_cards(player, card))
146+
|> case do
147+
game -> %{ game | cards: cards}
148+
end
149+
end
150+
151+
def cards_dealt(players) do
152+
Enum.reduce(players, 0, fn player, acc -> acc + length(player.hand) end) == length(players) * 2
153+
end
154+
155+
defp update_players(game, player) do
156+
players = game.players |> Enum.filter(fn (p) -> p.name != player.name end)
157+
158+
# ++/2 is slower, but it makes it easier to deal the cards
159+
%{ game | players: players ++ [player]}
160+
end
161+
end
162+
```
163+
164+
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.
165+
166+
<br>
167+
168+
## Follow Me @
169+
170+
[Twitter](https://twitter.com/basicbrogrammer) | [Instagram](https://instagram.com/basicbrogrammer)

0 commit comments

Comments
 (0)