-
Notifications
You must be signed in to change notification settings - Fork 45
/
06_game.ts
75 lines (64 loc) · 1.91 KB
/
06_game.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// ====================
// GUESS THE NUMBER
// ====================
import { pipe } from 'fp-ts/function'
import * as N from 'fp-ts/number'
import * as O from 'fp-ts/Option'
import { between } from 'fp-ts/Ord'
import { randomInt } from 'fp-ts/Random'
import * as T from 'fp-ts/Task'
import { getLine, putStrLn } from './Console'
// il numero da indovinare
export const secret: T.Task<number> = T.fromIO(randomInt(1, 100))
// combinatore: stampa un messaggio prima di una azione
const withMessage = (message: string) => <A>(next: T.Task<A>): T.Task<A> =>
pipe(
putStrLn(message),
T.chain(() => next)
)
// l'input è una stringa perciò dobbiamo validarlo
const isValidGuess = between(N.Ord)(1, 100)
const parseGuess = (s: string): O.Option<number> => {
const n = parseInt(s, 10)
return isNaN(n) || !isValidGuess(n) ? O.none : O.some(n)
}
const question: T.Task<string> = pipe(
getLine,
withMessage('Indovina il numero')
)
const answer: T.Task<number> = pipe(
question,
T.chain((s) =>
pipe(
s,
parseGuess,
O.match(
() => pipe(answer, withMessage('Devi inserire un intero da 1 a 100')),
(n) => T.of(n)
)
)
)
)
const check = <A>(
secret: number, // il numero segreto da indovinare
guess: number, // tentativo dell'utente
ok: T.Task<A>, // cosa fare se l'utente ha indovinato
ko: T.Task<A> // cosa fare se l'utente NON ha indovinato
): T.Task<A> => {
if (guess > secret) {
return pipe(ko, withMessage('Troppo alto'))
} else if (guess < secret) {
return pipe(ko, withMessage('Troppo basso'))
} else {
return ok
}
}
const end: T.Task<void> = putStrLn('Hai indovinato!')
// mantengo lo stato (secret) come argomento della funzione (alla Erlang)
const loop = (secret: number): T.Task<void> =>
pipe(
answer,
T.chain((guess) => check(secret, guess, end, loop(secret)))
)
const program: T.Task<void> = pipe(secret, T.chain(loop))
program()