n0mbers/src/algo.ts

157 lines
3.8 KiB
TypeScript

import { operators } from './globals'
import { Operation, OperatorType } from './types'
import { shuffle } from './utils'
type HistoryType = { a: number; b: number; op: OperatorType }[]
export function isOperationResultValid(op: Operation): boolean {
return (
!!op.operator &&
!!op.left &&
!!op.right &&
Number.isInteger(operate(op.operator, op.left?.value, op.right?.value))
)
}
export function isOperationInvalid(op: Operation): boolean {
if (!isOperationReady(op)) return false
return !isOperationResultValid(op)
}
export function isOperationReady(op: Operation): boolean {
return !!op.operator && !!op.left && !!op.right
}
export function getEmptyOperation(): Operation {
return {
left: null,
right: null,
operator: null,
result: null,
}
}
export function operate(
operator: OperatorType,
valA: number,
valB: number,
): number {
switch (operator) {
case '+':
return valA + valB
case '-':
return valA - valB
case '*':
return valA * valB
case '/':
return valA / valB
}
}
export function isSolvable(result: number, plaquettes: number[]): boolean {
console.log('---')
console.log('Solving ' + result)
// Bigger numbers have more time to solve themselves
const maxIterations = result * 100
function printHistory(history: HistoryType): void {
for (const item of history) {
if (item.a < item.b) [item.a, item.b] = [item.b, item.a]
console.log(
`${item.a} ${item.op} ${item.b} = ${operate(item.op, item.a, item.b)}`,
)
}
}
function loopOperations(plaquettes: number[], history: HistoryType): void {
for (let i = 0; i < plaquettes.length - 1; ++i) {
for (let j = i + 1; j < plaquettes.length; ++j) {
let a = plaquettes[i]
let b = plaquettes[j]
if (a < b) [a, b] = [b, a]
const ops = shuffle([...operators])
for (const op of ops) {
if (op === '/' && a % b !== 0) continue
recursOperation(op, a, b, plaquettes, history)
}
}
}
}
function recursOperation(
operator: OperatorType,
valA: number,
valB: number,
oldPlaquettes: number[],
oldHistory: HistoryType,
): void {
if (found) return
if (++numberOfIterations > maxIterations) return
const plaquettes = [...oldPlaquettes]
const history = [...oldHistory]
// remove values from plaquettes
const idxA = plaquettes.findIndex(p => p === valA)
plaquettes.splice(idxA, 1)
const idxB = plaquettes.findIndex(p => p === valB)
plaquettes.splice(idxB, 1)
// calculate result and push it into plaquettes
const r = operate(operator, valA, valB)
plaquettes.push(r)
// Save step
history.push({ a: valA, b: valB, op: operator })
// Found the solution
if (plaquettes.indexOf(result) > -1) {
histories.push(history)
if (!found) {
found = true
console.log(`1e solution trouvée en ${Date.now() - start}ms`)
}
return
}
// Exhausted all plaquettes
else if (plaquettes.length === 1) {
return
}
loopOperations(plaquettes, history)
}
const histories: HistoryType[] = []
// Start calculations
const start = Date.now()
let found = false
let numberOfIterations = 0
loopOperations(plaquettes, [])
if (found) {
console.log(
`Réussite : ${Date.now() - start}ms et ${numberOfIterations} iterations`,
)
}
else {
console.log(
`Echec : ${Date.now() - start}ms et ${numberOfIterations} iterations`,
)
}
if (histories.length) {
// printHistory(histories[0])
}
return found
// histories.sort((a, b) => a.length - b.length)
// console.log(
// `${histories.length} combinaisons trouvées en ${Date.now() - start}ms`,
// ) // Entre 18 et 1410
// if (histories.length) {
// console.log()
// printHistory(histories[0])
// }
}