Untitled

Run Settings
LanguageTypeScript
Language Version
Run Command
function grid(w, h) { const arr = new Array(w); for(let i = 0; i < w; i++) { arr[i] = new Array(h); } return arr; } function canCoerce(param: string, arg: string) { return param === arg; } function checkParameters( params: string[], args: string[] ) { const compatibility: boolean[][] = grid(args.length, params.length); let allCompatible: boolean = params.length === args.length; // Make sure our happy path is fast for(let i = 0; i < Math.min(params.length, args.length); i++) { let paramCompatible = canCoerce(params[i], args[i]); allCompatible = allCompatible && paramCompatible; compatibility[i][i] = paramCompatible; } if(allCompatible) { console.log("Function call allowed!"); return; } // We had some kind of incompatibility. Either some params didn't match, or the lengths didn't match // To provide good heuristics, probe to see if adjacent arguments can line up // Start by filling in a compatibility grid for(let i = 0; i < args.length; i++) { for(let j = 0; j < params.length; j++) { if(i === j) continue; // We've already computed these compatibility[i][j] = canCoerce(args[i], params[j]); } } function directly_invalid(i) { if(i >= args.length || i >= params.length) { return false; } // Check if the input is completely unsatisfied for(let j = 0; j < args.length; j++) { if(compatibility[j][i]) { return false; } } // Check if the parameter is useless for(let j = 0; j < params.length; j++) { if(compatibility[i][j]) { return false; } } return true; } function argument_extra(i) { if(i >= compatibility.length) { return false; } if(compatibility[i].length == 0) { return true; } if(!compatibility[i].some(x => x)) { return true; } return false; } function param_missing(i) { if(i >= params.length) { return false; } if(!compatibility.some(r => r[i])) { return true; } return false; } function permuted() { // Find the rows that might be part of a permutation let possible_rows = []; for(let i = 0; i < args.length; i++) { if(compatibility[i].filter(j => j).length === 1) { possible_rows.push(i); } } let possible_cols = possible_rows.filter(i => { let j = compatibility[i].indexOf(true); let mr = possible_rows.filter(r => compatibility[r][j]); return mr.length === 1; }); let permuted_cols = possible_cols.filter(c => !compatibility[c][c]); return permuted_cols; } function swapped(i) { if(i >= args.length || i >= params.length) { return false; } if(compatibility[i][i]) { return false; } for(let j = 0; j < Math.min(args.length, params.length); j++) { if(i == j) continue; if(compatibility[j][j]) { continue; } if(compatibility[i][j] && compatibility[j][i]) { return j; } } return false; } function removeArg(i) { args.splice(i, 1); compatibility.splice(i, 1); } function removeParam(i) { params.splice(i, 1); compatibility.forEach(r => r.splice(i, 1)); } let limit = 10; while((params.length || args.length) && limit > 0) { let issueFound = false; for(let i = 0; i < Math.max(args.length, params.length); i++) { if (directly_invalid(i)) { console.log(`Expected ${params[i]}, got ${args[i]}`); removeArg(i); removeParam(i); issueFound = true; break; } if (argument_extra(i)) { console.log(`${args[i]} is extra!`); removeArg(i); issueFound = true; break; } if (param_missing(i)) { console.log(`${params[i]} is missing!`); removeParam(i); issueFound = true; break; } } let permutable = permuted(); if(permutable.length > 1) { if(permutable.length == 2) { console.log(`${args[permutable[0]]} and ${args[permutable[1]]} are swapped!`); } else { console.log(`The following arguments are in the wrong order: ${permutable.map(p => args[p]).join(', ')}`); } permutable.sort().reverse().forEach(p => { removeArg(p); removeParam(p); }); issueFound = true; continue; } if(!issueFound) { // Now that there are no obvious issues, eliminate one correctly mapped parameter for(let i = 0; i < Math.min(args.length, params.length); i++) { if(compatibility[i][i]) { removeArg(i); removeParam(i); break; } } } limit--; } if(limit <= 0) { console.log("Diverged!!"); } } type TestCase = [string, string[], string[]] const testCases: TestCase[] = [ /**/ ['Valid', [], []], ['Valid', ['A'], ['A']], ['Valid', ['A','B'], ['A','B']], ['Valid', ['A', 'A'], ['A', 'A']], ['Invalid', ['A'], ['B']], ['Invalid', ['A', 'B'], ['A', 'C']], ['Invalid', ['A', 'B', 'C'], ['A', 'D', 'C']], ['Invalid', ['A', 'A', 'B'], ['A', 'A', 'C']], ['Invalid', ['A', 'A'], ['B', 'B']], ['Extra', [], ['A']], ['Extra', ['A'], ['A', 'B']], ['Extra', ['A'], ['A', 'B', 'C']], ['Extra', ['A', 'C'], ['A', 'B', 'C']], ['Extra', ['A', 'C'], ['B', 'A', 'C']], /**/ ['Extra', ['A'], ['A', 'A']], /**/ ['Extra', ['A', 'A'], ['A','A','A']], ['Extra', ['A', 'B'], ['A', 'A', 'B']], ['Extra', ['A', 'B'], ['A', 'B', 'B']], ['Extra', ['A', 'B'], ['A', 'A', 'B', 'B']], ['Extra and Invalid', ['A', 'B'], ['A', 'C', 'D']], ['Extra and Invalid', ['A', 'B', 'C'], ['A', 'C', 'F', 'C']], ['Missing', ['A'], []], ['Missing', ['A', 'B'], ['A']], ['Missing', ['A', 'B'], ['B']], ['Missing', ['A', 'A'], ['A']], ['Missing', ['A', 'A', 'A'], ['A']], ['Missing', ['A', 'B', 'C'], ['A', 'C']], ['Missing', ['A', 'B', 'C'], ['A', 'C']], ['Missing', ['A', 'B', 'B', 'C'], ['A', 'C']], ['Missing', ['A', 'B', 'A', 'B', 'C'], ['A', 'C']], ['Missing and Invalid', ['A', 'B', 'C'], ['A', 'D']], ['Missing and Extra', ['A', 'B', 'C'], ['A', 'C', 'F']], ['Swapped', ['A', 'B'], ['B', 'A']], ['Swapped', ['A', 'B', 'C'], ['B', 'A', 'C']], ['Swapped', ['A', 'B', 'C'], ['A', 'C', 'B']], ['Swapped', ['A', 'B', 'C'], ['C', 'B', 'A']], ['Permuted', ['A', 'B', 'C', 'D', 'E'], ['D', 'E', 'C', 'A', 'B']], ['Permuted', ['A', 'B', 'C'], ['B', 'C', 'A']], ['Swapped and Invalid', ['A', 'B', 'C'], ['C', 'F', 'A']], ['Swapped and Missing', ['A', 'B', 'C'], ['C', 'A']],/**/ ['Missing, Extra, Invalid, Swapped', ["A", "B", "C", "D", "E", "F"], ["A", "C", "X", "G", "F", "E"]], ]; for(const c of testCases) { console.log(`fn MyFunc(${c[1].join(', ')}) { ... }`); console.log(` MyFunc(${c[2].join(', ')});`); checkParameters(c[1], c[2]); console.log('----------------------'); }
Editor Settings
Theme
Key bindings
Full width
Lines