Skip to content

Instantly share code, notes, and snippets.

@pocarist
Last active January 1, 2024 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pocarist/622a27fb8597b829b812f561ed3a9841 to your computer and use it in GitHub Desktop.
Save pocarist/622a27fb8597b829b812f561ed3a9841 to your computer and use it in GitHub Desktop.
// https://twitter.com/e869120/status/1741475801026204116#
(*
(20 + (((23 + 12) - 31) * ((20 * (24 + 1)) + 1)))
(((20 * 23) + (((12 + 31) - 20) * 24)) * (1 + 1))
*)
let rec gcd a (b: int) = if b = 0 then a else gcd b (a % b)
let lcm a b = (a * b) / gcd a b
type Rational =
{ numerator: int
denominator: int }
static member Create(p, q) =
let p, q =
if q = 0 then
raise (System.DivideByZeroException())
let g = gcd q p in
p / g, q / g
let p, q = if q > 0 then p, q else -p, -q
{ numerator = p; denominator = q }
static member (+)(m, n) =
Rational.Create(m.numerator * n.denominator + n.numerator * m.denominator, m.denominator * n.denominator)
static member (-)(m, n) =
Rational.Create(m.numerator * n.denominator - n.numerator * m.denominator, m.denominator * n.denominator)
static member (~-) m =
Rational.Create(-m.numerator, m.denominator)
static member ( * )(m, n) =
Rational.Create(m.numerator * n.numerator, m.denominator * n.denominator)
static member (/)(m, n) =
Rational.Create(m.numerator * n.denominator, m.denominator * n.numerator)
static member Abs(m) =
Rational.Create(abs m.numerator, m.denominator)
static member of_int n = Rational.Create(n, 1)
static member Zero = Rational.of_int 0
static member One = Rational.of_int 1
override this.ToString() =
if this.denominator = 1 then
this.numerator.ToString()
else
sprintf "[%A/%A]" this.numerator this.denominator
type t =
| Num of Rational
| Add of t * t
| Sub of t * t
| Mul of t * t
| Div of t * t
override this.ToString() =
match this with
| Num n -> n.ToString()
| Add(a, b) -> sprintf "(%s + %s)" (a.ToString()) (b.ToString())
| Sub(a, b) -> sprintf "(%s - %s)" (a.ToString()) (b.ToString())
| Mul(a, b) -> sprintf "(%s * %s)" (a.ToString()) (b.ToString())
| Div(a, b) -> sprintf "(%s / %s)" (a.ToString()) (b.ToString())
let rec eval =
function
| Num n -> Some n
| Add(a, b) ->
match eval b with
| None -> None
| x -> (eval a, x) ||> Option.map2 (+)
| Sub(a, b) ->
match eval b with
| None -> None
| x -> (eval a, x) ||> Option.map2 (-)
| Mul(a, b) ->
match eval b with
| None -> None
| x -> (eval a, x) ||> Option.map2 ( * )
| Div(a, b) ->
match eval b with
| None -> None
| Some({ numerator = 0; denominator = _ }) -> None
| x -> (eval a, x) ||> Option.map2 (/)
let nums = [ 20; 23; 12; 31; 20; 24; 1; 1 ]
// let ops = [ Add; Sub; Mul; Div ]
let ops = [ Add; Sub; Mul ]
let solve target nums =
let target' = Rational.of_int target
let rec traverse stack nums =
let ans =
match stack, nums with
| x :: [], [] -> if eval x = Some target' then [ x ] else []
| _, n :: ns ->
let expr = n |> Rational.of_int |> Num
traverse (expr :: stack) ns
| _ -> []
match stack with
| x :: y :: zs ->
ops
|> List.fold
(fun acc op ->
let tmp = traverse (op (y, x) :: zs) nums
acc @ tmp)
ans
| _ -> ans
traverse [] nums
let rec normalize = function
| Num n -> Num n
| Add(a, Sub(b, c)) -> (Sub(Add(normalize a, normalize b), normalize c))
| Add(a, b) -> Add(normalize a, normalize b)
| Sub(a, b) -> Sub(normalize a, normalize b)
| Mul(a, b) -> Mul(normalize a, normalize b)
| Div(a, b) -> Div(normalize a, normalize b)
let () =
let ans = solve 2024 nums
ans
|> List.map normalize
|> Set.ofList
|> Seq.map (fun x -> x.ToString())
|> Seq.iter (printfn "%s")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment