やる気が出ない人のCodewars 2 @ 7kyu

# はじめに
7kyuの問題に手こずる稚魚プログラマです。
相変わらず書くことがなく、大掛かりなことをやる気もなく、
Codewarsにネタを求めてやってきました。
# 問題
とはいえ、よわよわプログラマの私にとっては、十分苦戦してちゃんと学べるんですよね。
ってことで[今回の問題](https://www.codewars.com/kata/566fc12495810954b1000030/train/haskell)
```
Take an integer `n (n >= 0)` and a digit `d (0 <= d <= 9)` as an integer.

Square all numbers `k (0 <= k <= n)` between 0 and n.

Count the numbers of digits `d` used in the writing of all the `k**2`.

Implement the function taking `n` and `d` as parameters and returning this count.

#### Examples:

n = 10, d = 1 
the k*k are 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
We are using the digit 1 in: 1, 16, 81, 100. The total count is then 4.

The function, when given n = 25 and d = 1 as argument, should return 11 since
the k*k that contain the digit 1 are:
1, 16, 81, 100, 121, 144, 169, 196, 361, 441.
So there are 11 digits 1 for the squares of numbers between 0 and 25.

Note that `121` has twice the digit 1.
```
Google翻訳
```
整数`n (n >= 0)`と数字を`d (0 <= d <= 9)`整数として受け取ります。

`k (0 <= k <= n)`0 から n までのすべての数値を二乗します。

`d`すべての の書き込みに使用される桁数を数えます`k**2`。

`n`と を`d`パラメータとして受け取り、このカウントを返す関数を実装します。

#### 例:


n = 10, d = 1 
the k*k are 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
We are using the digit 1 in: 1, 16, 81, 100. The total count is then 4.

The function, when given n = 25 and d = 1 as argument, should return 11 since
the k*k that contain the digit 1 are:
1, 16, 81, 100, 121, 144, 169, 196, 361, 441.
So there are 11 digits 1 for the squares of numbers between 0 and 25.


`121`には数字 1 が 2 倍あることに注意してください。
```
少しややこしいですが、
- 整数`n`と、0~9の数字`d`を与えるよ
- 0から`n`までの全ての数を二乗するよ
- そのなかで、`d`の数字が使われてる回数を返してね
- 例：`n = 10`, `d = 1`
二乗したもの：`0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100`
`d = 1`が使われている回数：`4`（`1, 16, 81, 100`）
- 注意！`121`は`1`を2回含むと考えてね！

ってことですね。

## ここからが真の問題
1時間くらいかけて、エラーに対処しながら、以下のコードを書きました。
```hs
module Codewars.G964.Countdig where

nbDig :: Int -> Int -> Int
nbDig n d = countDigits n 0
  where
    countDigits :: Int -> Int -> Int
    countDigits num cnt
      | num == 0 = cnt
      | num ^ 2 == d = countDigits (num - 1) (cnt + 1)
      | quot == d = if remainIsDigits then countDigits (num - 1) (cnt + 2) else countDigits (num - 1) (cnt + 1)
      | quot < 10 = if remainIsDigits then countDigits (num - 1) (cnt + 1) else countDigits (num - 1) cnt
      | otherwise = if remainIsDigits then countDigits quot (cnt + 1) else countDigits quot cnt
      where
        quot = (num ^ 2 - (num ^ 2) `mod` 10) `div` 10
        remainIsDigits = (num ^ 2) `mod` 10 == d
```
そしたら……
### Execution Timed Out (12000 ms)
### (´;ω;｀)(´;ω;｀)(´;ω;｀)

Codewarsでは、処理が長すぎるとそれだけで不正解になるんですよね。

……いや、わかってたよ？汚いコードだなって。絶対もっときれいに短く書けるなって。

でも、１時間、頑張ったんだけどなあ……

リファクタリングするかあ……（作り直し説もある）。
# 解決方法
ポイント
- Haskellの`div`は整数の除算を行い、**整数の商を返す**。
（勝手に小数点以下も返すかと……）
- アルゴリズムのミス
	- 例：`n = 121`, `d = 1`
	  `121 / 10 = 12...1`
	  `12 / 10 = 1...2`←ここで終了させてたため、"余りの数"と"商"の2種類判定が必要だった。
	  `1 / 10 = 0...1`←ここまでやれば、余りの数の判定だけで済む。

その結果がこちら
```hs
module Codewars.G964.Countdig where

nbDig :: Int -> Int -> Int
nbDig n d = countDigits n 0
  where
    countDigits :: Int -> Int -> Int
    countDigits 0 count = count 
    countDigits num count = countDigits (num - 1) (count + digitCount (num ^ 2))
      where
        digitCount 0 = 0
        digitCount num
          | num `mod` 10 == d = 1 + digitCount (num `div` 10)
          | otherwise = digitCount (num `div` 10)
```

これはいけるんじゃないか……！？
### 最後の敵！(0 * 0)
```
## Test Results:

Codewars.G964.Countdig

nbDig

should return nbDig for n: 5750 d: 0

expected: 4700 but got: 4699

Completed in 1.256ms

should return nbDig for n: 11011 d: 2

should return nbDig for n: 12224 d: 8

should return nbDig for n: 11549 d: 1
```
一つだけミスってる……
`4700`を返すべきところを`4699`で返してる……？
`d = 0`……？あっっっっ
#### (0 * 0)の時、カウントできてない！！
これは難問だぞ……
```hs
countDigits (-1) count = count -- countDigits 0 count = count から変更
countDigits num count = countDigits (num - 1) (count + digitCount (num ^ 2))
```
まずは、`countDigits`から`digitCount`に値が渡されるように変更。
ただ……
```hs
digitCount 0 -- digitCount 0 = 0 から変更
 | d == 0 = 1
 | ohterwise = 0
```
これだと、例えば`10 * 10`の時の`100`の、計算の搾りカスとしての`0`もカウントしてしまう……

よし、書きながら思いついた。
きれいじゃないけど、別枠で処理しよう。それが一番負荷なくできる気がする。

#### 最終形がこちら
```hs
module Codewars.G964.Countdig where

nbDig :: Int -> Int -> Int
nbDig n d
  | d == 0 = countDigits n 1
  | otherwise = countDigits n 0
  where
    countDigits 0 count = count 
    countDigits num count = countDigits (num - 1) (count + digitCount (num ^ 2))
      where
        digitCount 0 = 0
        digitCount num
          | num `mod` 10 == d = 1 + digitCount (num `div` 10)
          | otherwise = digitCount (num `div` 10)
```
ちゃっかり`countDigits :: Int -> Int -> Int`を消して短くしました。短さは正義！！
# 終わりに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/531c677a-f66e-c4ec-8533-6a14f4413164.png)

しっかりクリア！！長かったけど、今回も楽しかったです。
なお、他の回答を見ると
```hs
module Codewars.G964.Countdig where

import Data.Char (intToDigit)

nbDig :: Int -> Int -> Int
nbDig n d = sum [ length $ filter (==c) $ show (x*x) | x <- [0..n] ]
  where c = intToDigit d
```
とか、
```hs
module Codewars.G964.Countdig where

nbDig :: Int -> Int -> Int
nbDig n d = sum $ fmap (length . filter (== c) . show . (^ (2 :: Int))) [0 .. n]
  where
    c = head $ show d
```
とか、
めちゃくちゃ短く書かれててほげーって感じでした。ほげほげ。
今日はやり切った感あるので終わりますほげ。
（一生ないと思うけど）気が向いたらこの解答について考えてみますほげ。