2022-02-16 22:48:04 +01:00
|
|
|
import { operators } from './globals'
|
|
|
|
import { Operation, OperatorType } from './types'
|
2022-02-18 12:24:25 +01:00
|
|
|
import { shuffle } from './utils'
|
2022-02-07 22:14:31 +01:00
|
|
|
|
|
|
|
type HistoryType = { a: number; b: number; op: OperatorType }[]
|
|
|
|
|
2022-02-10 22:32:41 +01:00
|
|
|
export function isOperationResultValid(op: Operation): boolean {
|
2022-02-09 21:27:26 +01:00
|
|
|
return (
|
|
|
|
!!op.operator &&
|
|
|
|
!!op.left &&
|
|
|
|
!!op.right &&
|
|
|
|
Number.isInteger(operate(op.operator, op.left?.value, op.right?.value))
|
|
|
|
)
|
|
|
|
}
|
2022-02-10 22:32:41 +01:00
|
|
|
|
|
|
|
export function isOperationInvalid(op: Operation): boolean {
|
|
|
|
if (!isOperationReady(op)) return false
|
|
|
|
return !isOperationResultValid(op)
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isOperationReady(op: Operation): boolean {
|
2022-02-12 14:12:55 +01:00
|
|
|
return !!op.operator && !!op.left && !!op.right
|
2022-02-10 22:32:41 +01:00
|
|
|
}
|
|
|
|
|
2022-02-11 22:57:04 +01:00
|
|
|
export function getEmptyOperation(): Operation {
|
|
|
|
return {
|
2022-02-10 22:32:41 +01:00
|
|
|
left: null,
|
|
|
|
right: null,
|
|
|
|
operator: null,
|
2022-02-11 22:57:04 +01:00
|
|
|
result: null,
|
|
|
|
}
|
2022-02-10 22:32:41 +01:00
|
|
|
}
|
|
|
|
|
2022-02-09 21:27:26 +01:00
|
|
|
export function operate(
|
|
|
|
operator: OperatorType,
|
|
|
|
valA: number,
|
|
|
|
valB: number,
|
|
|
|
): number {
|
2022-02-07 22:14:31 +01:00
|
|
|
switch (operator) {
|
|
|
|
case '+':
|
|
|
|
return valA + valB
|
|
|
|
case '-':
|
|
|
|
return valA - valB
|
2022-02-18 12:19:59 +01:00
|
|
|
case '*':
|
2022-02-07 22:14:31 +01:00
|
|
|
return valA * valB
|
|
|
|
case '/':
|
|
|
|
return valA / valB
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isSolvable(result: number, plaquettes: number[]): boolean {
|
2022-02-18 12:24:25 +01:00
|
|
|
console.log('---')
|
|
|
|
console.log('Solving ' + result)
|
|
|
|
|
|
|
|
// Bigger numbers have more time to solve themselves
|
|
|
|
const maxIterations = result * 100
|
|
|
|
|
2022-02-07 22:14:31 +01:00
|
|
|
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]
|
2022-02-18 12:24:25 +01:00
|
|
|
const ops = shuffle([...operators])
|
|
|
|
for (const op of ops) {
|
2022-02-07 22:14:31 +01:00
|
|
|
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
|
2022-02-18 12:24:25 +01:00
|
|
|
if (++numberOfIterations > maxIterations) return
|
2022-02-07 22:14:31 +01:00
|
|
|
|
|
|
|
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
|
2022-02-18 12:24:25 +01:00
|
|
|
console.log(`1e solution trouvée en ${Date.now() - start}ms`)
|
2022-02-07 22:14:31 +01:00
|
|
|
}
|
|
|
|
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
|
2022-02-18 12:24:25 +01:00
|
|
|
let numberOfIterations = 0
|
2022-02-07 22:14:31 +01:00
|
|
|
loopOperations(plaquettes, [])
|
2022-02-18 12:24:25 +01:00
|
|
|
if (found) {
|
|
|
|
console.log(
|
|
|
|
`Réussite : ${Date.now() - start}ms et ${numberOfIterations} iterations`,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log(
|
|
|
|
`Echec : ${Date.now() - start}ms et ${numberOfIterations} iterations`,
|
|
|
|
)
|
|
|
|
}
|
2022-02-07 22:14:31 +01:00
|
|
|
|
|
|
|
if (histories.length) {
|
2022-02-18 12:24:25 +01:00
|
|
|
// printHistory(histories[0])
|
2022-02-07 22:14:31 +01:00
|
|
|
}
|
|
|
|
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])
|
|
|
|
// }
|
|
|
|
}
|