Showing posts with label Quiz/Survey. Show all posts
Showing posts with label Quiz/Survey. Show all posts

Thursday, 1 December 2022

Scrimba's JavaScriptmas and Advent of Code 2022

Day 1

JavaScriptmas

const panic = str => `${str.toUpperCase().split(' ').join(' 😱 ')}!`
console.log(panic("I'm almost out of coffee"))
console.log(panic("winter is coming"))

Advent of Code

const elves = input.split('\n\n').map(e => Number(e.split('\n').reduce((a, c) => Number(a) + Number(c))))
console.log(Math.max(...elves))
elves.sort((a, b) => b - a)
console.log(elves.slice(0, 3).reduce((a, c) => a + c))

Day 2

JavaScriptmas

const transformData = d => d.map(e => ({
    fullName: `${e.name.first} ${e.name.last}`,
    birthday: new Date(e.dob.date).toDateString()
}))

Advent of Code

/**
 * Rock:     A, X. Worth: 1. Beats: Scissors
 * Paper:    B, Y. Worth: 2. Beats: Rock
 * Scissors: C, Z. Worth: 3. Beats: Paper
 * 0 if you lost,
 * 3 if the round was a draw
 * and 6 if you won
 */ 

console.log(input.split('\n').reduce((a, c) => {
  const [them, me] = c.split(' ')
  if(them === 'A'){
    if(me === 'X'){
      a += 3 + 1
    }
    if(me === 'Y'){
      a += 6 + 2
    }
    if(me === 'Z'){
      a += 0 + 3
    }
  }
  if(them === 'B'){
    if(me === 'X'){
      a += 0 + 1
    }
    if(me === 'Y'){
      a += 3 + 2
    }
    if(me === 'Z'){
      a += 6 + 3
    }
  }
  if(them === 'C'){
    if(me === 'X'){
      a += 6 + 1
    }
    if(me === 'Y'){
      a += 0 + 2
    }
    if(me === 'Z'){
      a += 3 + 3
    }
  }
  return a
}, 0))

/**
 * Rock:     A, X. Worth: 1. Beats: Scissors
 * Paper:    B, Y. Worth: 2. Beats: Rock
 * Scissors: C, Z. Worth: 3. Beats: Paper
 * 0 if you lost,
 * 3 if the round was a draw
 * and 6 if you won
 * X: Lose
 * Y: Draw
 * Z: Win
 */ 

console.log(input.split('\n').reduce((a, c) => {
  const [them, me] = c.split(' ')
  if(them === 'A'){ // They've played Rock
    if(me === 'X'){ // I need to lose
      a += 0 + 3    // I play Scissors
    }
    if(me === 'Y'){ // I need to draw
      a += 3 + 1    // I play Rock
    }
    if(me === 'Z'){ // I need to win
      a += 6 + 2    // I play Paper
    }
  }
  if(them === 'B'){ // They've played Paper
    if(me === 'X'){ // I need to lose
      a += 0 + 1    // I play Rock
    }
    if(me === 'Y'){ // I need to draw
      a += 3 + 2    // I play Paper
    }
    if(me === 'Z'){ // I need to win
      a += 6 + 3    // I play Scissors
    }
  }
  if(them === 'C'){ // They've played Scissors
    if(me === 'X'){ // I need to lose
      a += 0 + 2    // I play Paper  
    }
    if(me === 'Y'){ // I need to draw
      a += 3 + 3    // I play Scissors  
    }
    if(me === 'Z'){ // I need to win
      a += 6 + 1    // I play Rock  
    }
  }
  return a
}, 0))

Day 3

JavaScriptmas

const faveFoods = {
    breakfast: 'croissants',
    lunch: 'pasta',
    supper: 'pizza'
}

const {breakfast, lunch, supper} = faveFoods

document.getElementById('meals').innerHTML = `
For breakfast, I only like ${breakfast}. For lunch, I love ${lunch}, and for supper I want usually want ${supper}.`

Advent of Code

// drop 96 for lowercase
// drop 38 for uppercase

const getCodeValue = letter => letter === letter.toLowerCase() 
  ? letter.charCodeAt(0) - 96
  : letter.charCodeAt(0) - 38

const getIntersection = (a, b) => {
  for(let i in a){
    if(b.includes(a[i])){
      return a[i]
    }
  }
}

const getIntersectionThree = (a, b, c) => {
  for(let i in a){
    if(b.includes(a[i]) && c.includes(a[i])){
      return a[i]
    }
  }
}

console.log(input.split('\n').reduce((a, c) => a + getCodeValue(getIntersection(...[c.slice(0, Math.ceil(c.length / 2)).split(''), c.slice(Math.ceil(c.length / 2)).split('')]))
, 0))

let total = 0
const lines = input.split('\n')
for (let i = 0; i < lines.length; i += 3) {
  const chunk = lines.slice(i, i + 3);
  total += getCodeValue(getIntersectionThree(...chunk))
}
console.log(total)

console.log(input.split('\n').reduce((p, _, i, a) => !(i%3) 
  ? p + getCodeValue(getIntersectionThree(...a.slice(i, i + 3))) 
  : p, 0))

Day 4

JavaScriptmas

const whisper = s => `shh... ${s.endsWith('!') 
  ? s.toLowerCase().slice(0, -1) 
  : s.toLowerCase()}`

Advent of Code

const range = (start, stop) => Array.from({ length: stop - start + 1 }, (_, i) => start + i)
const contains = (a, b) => a.every(e => b.includes(e)) || b.every(e => a.includes(e))
const overlaps = (a, b) => a.some(e => b.includes(e))
                                                                  
console.log(input.split('\n').reduce((a, line) => {
  const [firstArea, secondArea] = line.split(',').map(elf => range(...elf.split('-').map(e => Number(e))))
  a.contains += contains(firstArea, secondArea) ? 1 : 0
  a.overlaps += overlaps(firstArea, secondArea) ? 1 : 0
  return a
}, {
  contains: 0,
  overlaps: 0
}))

// let containedWithin = 0
// let overlaps = 0

// input.split('\n').forEach(line => {
//   const [firstArea, secondArea] = line.split(',').map(elf => range(...elf.split('-').map(e => Number(e))))
//   if(secondArea.every(e => firstArea.includes(e)) || firstArea.every(e => secondArea.includes(e))){
//     containedWithin += 1
//   }
//   if(secondArea.some(e => firstArea.includes(e))){
//     overlaps += 1
//   }
// })
// console.log(containedWithin, overlaps)

Day 5

JavaScriptmas

const getSaleItems = d => d.filter(e => e.type === "sweet").map(e => ({item: e.item, price: e.price}))

Advent of Code

const chunk = (str, size) => {
  const numChunks = Math.ceil(str.length / size)
  const chunks = new Array(numChunks)
  for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
    chunks[i] = str.substr(o, size)
  }
  return chunks
}

const [initialState, instructions] = input.split('\n\n')
const initialStateLines = initialState.split('\n').reverse()
const positions = chunk(initialStateLines.shift(), 4).reduce((a, c) => {
  a[Number(c.trim())] = []
  return a
}, {})

initialStateLines.forEach(line => {
  chunk(line, 4).forEach((position, index) => {
    if (position.trim().length) {
      const { groups: { letter } } = /\s*\[(?<letter>[A-Z])\]\s*/.exec(position)
      positions[Object.keys(positions)[index]].push(letter)
    }
  })
})

/**
 * Part 1
 */
// instructions.split('\n').forEach(instruction => {
//   const {groups: {num, from, to}} = /move (?<num>[0-9]+) from (?<from>[0-9]+) to (?<to>[0-9]+)/.exec(instruction)
//   for(let i = 0; i < Number(num); i++){
//     positions[Number(to)].push(positions[Number(from)].pop())
//   }
// })

/**
 * Part 2
 */
instructions.split('\n').forEach(instruction => {
  const { groups: { num, from, to } } = /move (?<num>[0-9]+) from (?<from>[0-9]+) to (?<to>[0-9]+)/.exec(instruction)
  positions[Number(to)].push(...positions[Number(from)].slice(-Math.abs(Number(num))))
  positions[Number(from)].splice(positions[Number(from)].length - Number(num), Number(num) )
})

console.log(Object.keys(positions).reduce((a, c, i) => {
  return a + positions[c].at(-1)
}, ''))

Day 6

JavaScriptmas

const getRandomNumberOfTacos = () => new Array(Math.floor(Math.random() * (10 - 1) + 1)).fill('🌮')

Advent of Code

const test_input_1 = `mjqjpqmgbljsphdztnvjfqwrcgsmlb`
const test_input_2 = `bvwbjplbgvbhsrlpgdmjqwftvncz`
const test_input_3 = `nppdvjthqldpwncqszvftbrmjlhg`
const test_input_4 = `nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg`
const test_input_5 = `zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw`

const findPacket = stream => {
  for(let i = 3; i <= stream.length; i++){
    if(new Set(Array.from({length: 4}, (_, a) => stream.charAt(i - a))).size === 4){
      return i + 1
    }
  }
}

const findMessage = stream => {
  for(let i = 13; i <= stream.length; i++){
    if(new Set(Array.from({length: 14}, (_, a) => stream.charAt(i - a))).size === 14){
      return i + 1
    }
  }
}

console.log(findPacket(test_input_1))
console.log(findPacket(test_input_2))
console.log(findPacket(test_input_3))
console.log(findPacket(test_input_4))
console.log(findPacket(test_input_5))
console.log(findPacket(input))

console.log(findMessage(test_input_1))
console.log(findMessage(test_input_2))
console.log(findMessage(test_input_3))
console.log(findMessage(test_input_4))
console.log(findMessage(test_input_5))
console.log(findMessage(input))

Day 7

JavaScriptmas

const altCaps = str => str.split('').map((c, i) => i % 2 ? c : str.charCodeAt(i) > 96 || str.charCodeAt(i) < 123 ? c.toUpperCase() : c).join('')

Advent of Code

// import { Tree } from './Tree.js'
// import { TreeNode } from './TreeNode.js'

class TreeNode {
  constructor(key, value = key, parent = null) {
    this.key = key;
    this.value = value;
    this.parent = parent;
    this.children = [];
  }

  get isLeaf() {
    return this.children.length === 0;
  }

  get hasChildren() {
    return !this.isLeaf;
  }
}

class Tree {
  constructor(key, value = key) {
    this.root = new TreeNode(key, value);
  }

  *preOrderTraversal(node = this.root) {
    yield node;
    if (node.children.length) {
      for (let child of node.children) {
        yield* this.preOrderTraversal(child);
      }
    }
  }

  *postOrderTraversal(node = this.root) {
    if (node.children.length) {
      for (let child of node.children) {
        yield* this.postOrderTraversal(child);
      }
    }
    yield node;
  }

  insert(parentNodeKey, key, value = key) {
    for (let node of this.preOrderTraversal()) {
      if (node.key === parentNodeKey) {
        node.children.push(new TreeNode(key, value, node));
        return true;
      }
    }
    return false;
  }

  remove(key) {
    for (let node of this.preOrderTraversal()) {
      const filtered = node.children.filter(c => c.key !== key);
      if (filtered.length !== node.children.length) {
        node.children = filtered;
        return true;
      }
    }
    return false;
  }

  find(key) {
    for (let node of this.preOrderTraversal()) {
      if (node.key === key) return node;
    }
    return undefined;
  }
}

/*
 * https://www.30secondsofcode.org/articles/s/js-data-structures-tree
 */

addEventListener('DOMContentLoaded', async () => {
  //const res = await fetch("./test.txt")
  const res = await fetch("./input.txt")
  const text = await res.text()
  const input = text.split('\n')
  let target = null
  let tree = null
  let lineParts
  input.forEach((line, index) => {
    if (!index) {
      tree = new Tree('/', 0)
      target = tree.root
    } else {
      if (line.charAt(0) === '$') {
        lineParts = line.split(' ')
        if (lineParts.length === 3) {
          if (lineParts[2] === '..') {
            target = target.parent
          } else if (lineParts[2] === '/') {
            target = tree.root
          } else {
            target = target.children.find(ch => ch.key === lineParts[2])
          }
        }
      } else {
        lineParts = line.split(' ')
        if (lineParts[0] === 'dir') {
          target.children.push(new TreeNode(lineParts[1], 0, target))
        } else {
          const value = Number(lineParts[0])
          target.children.push(new TreeNode(lineParts[1], value, target))
          target.value += value
          let parent = target.parent
          while (parent) {
            parent.value += value
            parent = parent.parent
          }
        }
      }
    }
  })

  const dirs = [...tree.postOrderTraversal()].filter(x => x.hasChildren)
  console.log('Part 1:', dirs.reduce((a, c) => {
    if (c.value <= 100000) {
      a += c.value
    }
    return a
  }, 0))

  const spaceRequired = 30000000 - (70000000 - tree.root.value)
  console.log('Space required: ', spaceRequired)
  console.log('Part 2:', dirs.filter(dir => {
    if (dir.value >= spaceRequired) {
      console.log(dir.key, dir.value)
      return true
    }
    return false
  }).sort((a, b) => a.value - b.value)[0].value)
})

Day 8

JavaScriptmas

const validTime = str => {
  const [hours, minutes] = str.split(':').map(n => Number(n))
  return hours >= 1 && hours <= 24 && minutes >= 0 && minutes < 60
}

Day 9

JavaScriptmas

const capitalizeWord = w => `${w.charAt(0).toUpperCase()}${w.slice(1, w.length)}`

const toTitleCase = s => s.split(' ').map(w => capitalizeWord(w)).join(' ')

Day 10

JavaScriptmas

const sortByLength = s => s.sort((a, b) => a.length - b.length)

Day 11

JavaScriptmas

const reverseString = arr => arr.split('').reverse().join('')

const reverseStringsInArray = arr => arr.map(a => reverseString(a))

Day 12

JavaScriptmas

class MenuItem extends HTMLElement{
    static get observedAttributes() {
        return [
            'food'
        ]
    }
    constructor() {
        super()
    }
    render() {
        this.innerHTML = this.html
    }
    get html() {
        return `<div class="food">${this.food}</div>`
    }
    attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue !== newValue) {
            this.render()
        }
    }
    set food(v){
        this.setAttribute('food', v)
    }
    get food() {
        return this.getAttribute('food')
    }
}
window.customElements.define('menu-item', MenuItem)
const menu = document.getElementById('menu')
const dinnerFoods = ['🍝','🍔','🌮']
menu.innerHTML = dinnerFoods.map(food => `<menu-item food="${food}"/></menu-item>`).join('')

Day 13

JavaScriptmas

const emojifyWord = w => w.charAt(0) === ':' && w.charAt(w.length - 1) === ':' ? emojis[w.slice(1, -1)] ? emojis[w.slice(1, -1)] : w.slice(1, -1) : w

const emojifyPhrase = phrase => phrase.split(' ').map(word => emojifyWord(word)).join(' ')

Day 14

JavaScriptmas

const countVowelConsonant = str => str.split('').reduce((a, c) => a += ['a','e','i','o','u'].includes(c) ? 1 : 2, 0)

Day 15

JavaScriptmas

const isPalindrome = str => str === str.split('').reverse().join('')

Day 16

JavaScriptmas

const insertDashes = arr => arr.split(' ').map(w => w.split('').join('-')).join(' ')

Day 17

JavaScriptmas

const flatten = arr => arr.flat()
const flatten = arr => Array.prototype.concat.apply([], arr)
const flatten = arr => arr.toString().split(',')

Day 18

JavaScriptmas

const candies = (ch, ca) => Math.floor(ca/ch) * ch

Day 19

JavaScriptmas

const centuryFromYear = num => num % 100 === 0 ? num / 100 : Math.floor(num / 100) + 1

Day 20

JavaScriptmas

const getFreePodcasts = data => podcasts.filter(p => !p.paid).map(({title, rating, paid}) => ({title, rating, paid}))

Day 21

JavaScriptmas

const awardBonuses = num => Array.from({length: num}, (_, i) => i + 1).forEach(i => console.log(`${i} - ${!(i%3) && !(i%5) ? 'JACKPOT! 1 Million and a Yacht!' : !(i%3) ? 'Vacation!' : !(i%5) ? '$100,000 bonus!' : ':('}`))

awardBonuses(100)

Day 22

JavaScriptmas

function getReadyTables() {
  const readyTables = []
  for (let i = 0; i < 2; i++) {
    readyTables.push(Math.round(Math.random()*20) + 1)
  }
  return readyTables
}

const displayTables = () => getReadyTables().map(el => {
  const table =  document.createElement('div')
  table.classList.add('table')
  table.innerText = el
  return table
})

document.getElementById('tables').append(...displayTables())

Day 23

JavaScriptmas

const sortProducts = data => data.sort((a, b) => a.price - b.price)

Day 24

JavaScriptmas

const player = document.getElementById("player")
const playSong = id => player.src = `https://www.youtube.com/embed/${id}?autoplay=1`

Monday, 24 March 2014

Self Defined Ethnicity in an array of json (sde.json)

I needed this today so wondered if anyone else does...? The Self Defined Ethnicity is a set of codes so that people can record their ethnicity. That's cool, but there's no entry for Yorkshireman... ;-)

var SDE = [
    {
        "code": "A1",
        "value": "Indian"
    },
    {
        "code": "A2",
        "value": "Pakistani"
    },
    {
        "code": "A3",
        "value": "Bangladeshi"
    },
    {
        "code": "A9",
        "value": "Any other Asian background"
    },
    {
        "code": "B1",
        "value": "Caribbean"
    },
    {
        "code": "B2",
        "value": "African"
    },
    {
        "code": "B9",
        "value": "Any other black background"
    },
    {
        "code": "E1",
        "value": "Eastern European"
    },
    {
        "code": "M1",
        "value": "White and Black Caribbean"
    },
    {
        "code": "M2",
        "value": "White and Black African"
    },
    {
        "code": "M3",
        "value": "White and Asian"
    },
    {
        "code": "M9",
        "value": "Any other mixed background"
    },
    {
        "code": "O1",
        "value": "Chinese"
    },
    {
        "code": "O9",
        "value": "Any other ethnic group"
    },
    {
        "code": "W1",
        "value": "British"
    },
    {
        "code": "W2",
        "value": "Irish"
    },
    {
        "code": "W9",
        "value": "Any other white black ground"
    },
    {
        "code": "NS",
        "value": "Not stated"
    }
];

Saturday, 22 March 2014

jQuery Validate email is from a specific domain

I needed to validate that an email address provided via a form was from a user associated with a specific domain, I'll not repeat the domain and the example code I've included uses gmail.com but I'm pretty sure you'll be able to adapt it for your own purposes... and hopefully improve it. I found a number of possible solutions and enjoyed this idea from sectrean over on stackoverflow using Regular Expressions.

This was brilliant in terms of validation that the email address is/was an email address but didn't fulfil my requirement to check the domain of the the email address and didn't offer any more than the built in email method in the jQuery validation plugin. Then I clocked that Jacob Lauritzen had had a crack and that his work had been continued by Erik Woods with a nice little Fiddle.

Thus, on the backs of these giants I wrote this additional method for the Validation plugin, it needs some work and I'm thinking it may well have to accept and array of domains some time soon so I'm gonna have to have to do a wee bit more work on it, perhaps using the parems optional variable to addMethod. If you can think of improvements please don't hesitate to let me know.

jQuery.validator.addMethod("requireGmailEmail", function(value, element) {
    var re = /^\s*[\w\-\+_]+(\.[\w\-\+_]+)*\@[\w\-\+_]+\.[\w\-\+_]+(\.[\w\-\+_]+)*\s*$/;
    if (re.test(value)) {
        if (value.indexOf("@gmail.com", value.length - "@gmail.com".length) !== -1) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}, "Your email address is not valid.");

Wednesday, 26 February 2014

I won! I won! I won!

I've not won anything for ages, not since I won a tin of Mushy Peas at a pensioners raffle which I went to with my Nan when I were wee!

You can get your very own copy from Amazon: The Decapaphiliac: or love in the time of cappuccinos and read all about the author on Goodreads.

It's a brilliant read and I think I've bought it in every format so far... still, it's nice to win something!

In fact:

The DecapaphiliacThe Decapaphiliac by Alex Weinle
My rating: 5 of 5 stars

Not since I discovered an old collection of Tales of the Unexpected stories on my Grandad's bedside table have I enjoyed a short story collection as much as this one. Most especially as this collection didn't leave me feeling slightly seedy, steeped in the 1970's and full of ennui. Mr Weinle has a fine turn of phrase and a delicacy of style that left me feeling uplifted by all of his stories... even the slightly disturbing title story - which promised to be seedy but ended up leaving me feeling refreshed and hopeful - I think I'm slightly disappointed by not being more disgusted in all honesty.

I think The Disassociate was wonderful, especially as it held so very many resonances with my previous career as a psychiatric nurse and I'm pretty sure that I've met some of the management types in it. I thought that leaving my previous career would mean that I'd spend less time with psychopaths, not more!

The Glasses Adjuster is lovely too, a proper feeling of fairytale going on there and it left me feeling all warm of snuggly.

All of the stories were brilliant but these three stood out for me, and for this price you can't go wrong... after all Mr Weinle has to make enough to keep on feeding his cottage bulbs of unusual wattage.

View all my reviews

Tuesday, 31 December 2013

Who needs Jekyll for GitHub pages? Introducing Hyde!

I've been playing with various blogging/CMS engines since I started messing about with code. I even played with the fore-runner of WordPress for a long time before moving my own blog over to WordPress and now over to blogger. I created another one a little while ago that could be hosted on Google Drive but it didn't really peak my interest TBH, then along came a lovely article via Feedly (I love Feedly - I love it so much I've paid for it! Why don't you?) about GitHub pages. The article was lovely except that it wasn't really aimed at Windows users (what can I say? Windows works for me and seems to work a treat with most things I ask it to do... there's something about messing with Ruby though that leaves me feeling cold).

Anyway, the article talked about using Ruby to generate a static site using a combination of markdown and a Ruby gem by the name of Jekyll. This, after thrashing around trying to get the bloody thing to work on Windows 8 for a little while, got me thinking about my original GDB and about how cool it would be if I stored markdown rather than Base64 encoded HTML within my spreadsheet. So I got to work making that happen.

Thankfully all this happened during the Xmas and New Year break so I had some time to play (plus ample opportunity to play seeing as whenever I'm not playing/coding, driving, drinking or sleeping I'm an emotional mess) so I got to work and created a markdown powered dynamic blogging engine that seems to work a treat as a replacement for Jekyll on GitHub pages while using Google Sheets as a backend! Strangely enough I decided to call it Hyde. It's not likely to be fast but it does the job a treat and I'm going to write some instructions about it's use later on, in the meantime you can see it an action here.

Monday, 8 July 2013

Pub Quiz (02/07/2013)

Last Tuesday's pub quiz had the wrong answer. It asked about this historic tightrope walk and said the answer was The Grand Canyon, but it wasn't was it? Ohh no, it was the Gorge of the Little Colorado wasn't it?

Seems as though the quiz setter wasn't the only one wrong though as MSN got it wrong as well.

Thank you Mr Graham Haigh for getting the right answer! And He should know as he's been there! ;-)

Monday, 26 March 2012

Exam Prepration jQuery Tool

I do love 'er-indoors but she's not the most patient of people. Sure, she manages to actively listen for a while but ask her to do something that doesn't interest her and the result is obvious boredom. Which is a shame as I needed her help to revise for my DEV 401 exam.

I asked if I could borrow her for an hour or two on Saturday and Sunday. "Sure", says she in a nice surrendered wife type of way. My idea was to go through possible questions and give answers and ask her to say if I'd got it right or wrong. She agreed and we sat down but the delay of a few micro-seconds before I got a reply when I asked her a question was doing my nut in. I looked down to see her farming Smurfs or something. I really couldn't face putting her, or myself, through it all again the next day.

jQuery to the rescue!

I copied the questions I had into an array of JSON objects with the questions, the possible answers and the solution. This worked a treat as I could swap over questions easily enough and re-task it for other purposes.

I thought about trying to pluginify it but I don't really think it needs it as it takes a set of questions, answers and solutions and spits back a set of divs into the container of your choice. Props to David for the compare function.

(function(){
    prepareExam("chap1.json", "body");
    $("select#paper").on("change", function(){
        $val = $(this).val();
        $("div.question").empty().remove();
        $("div.score").empty().remove();
        prepareExam($val, "body");                    });
})();
jQuery.fn.compare = function(t) {
    if (this.length != t.length) {         return false;     }
    var a = this.sort(),
        b = t.sort();
    for (var i = 0; t[i]; i++) {
        if (a[i] !== b[i]) {             return false;
        }
    }
    return true;
};
function prepareExam(paper, target) {
    $.getJSON(paper, function(exam) {
        $.each(exam.exam, function(i, question){
            var d = $("<div></div>").addClass("question").appendTo(target);
            var q = $("<p></p>").html(i+1+". "+question.question).appendTo(d);
            var f = $("<fieldset></fieldset>").appendTo(d);
            $.each(question.answers, function(letter, possible){
                var labelID = letter+(i+1);
                $("<input></input>", {"type":"checkbox", "name":i+1,"value":letter, "id":labelID}).appendTo(f);
                $("<label></label>", {"for":labelID}).text(letter+". "+possible).appendTo(f);
                f.append('<br />');
            });
            d.data({"answer":question.solution});
            var c = $("<span></span>").addClass("check").text("Submit").button().appendTo(f).on("click", function(){
                var $parent = $(this).parent().parent();
                var allVals = [];
                $.each($parent.find("input:checked"), function(x, y){
                    allVals.push($(y).attr("value"));
                })
                if($(allVals).compare($parent.data("answer"))){
                    $parent.css("background-color","#ccffcc");
                    $parent.find("span.check").remove();
                    $parent.data({"success":true});
                }else{
                    $parent.css("background-color","#ffcccc");
                    $parent.find("span.check").remove();
                    $parent.data({"success":false});
                }
            });
            var leg = (question.solution.length !== 1) ? "answers" : "answer";
            $("<legend></legend>").text("Please choose "+question.solution.length+" "+leg+":").prependTo(f);
        });
        var s = $("<div></div>").addClass("score").appendTo(target);
        $("<p></p>").text("Ready to calculate your final score?").appendTo(s);
        $("<span></span>").addClass("final").text("Check").button().appendTo(s).on("click", function(){
            var total = 0, correct = 0;
            $.each($("div.question"), function(i, div){
                total++;
                if($(div).data("success")){
                    correct++;
                }
            });
            var l = $("<p></p>").text("Total Score = "+(((correct/total)*100).toFixed(2))+"%").appendTo($("div.score"));
            if(((correct/total)*100).toFixed(2) >= 68){
                l.css("color","green")
            }else{
                l.css("color","red")
            }
            $("span.final").remove();
        });
    });
};

As you can probably tell I used a lot of different sets of questions and I added them to a select input so I could load up a set of new questions when I'd done a paper and scored myself.

The format of the JSON should be:

{
    "exam": [
        {
            "question": "Jack and Jill went up the hill to fetch?",
            "answers": {
                "a": "A pail of water",
                "b": "Porridge",
                "c": "Vinegar"
            },
            "solution": [
                "a"
            ]
        },
        {
            "question": "What did the old woman who lived in a shoe do to her children?",
            "answers": {
                "a": "She gave them some broth without any bread.",
                "b": "She starved them.",
                "c": "She sent them to sweep chimneys.",
                "d": "She whipped them all soundly and put them to bed."
            },
            "solution": [
                "a",
                "d"
            ]
        }
    ]
}

Have fun!

I think it's lovely so by all means take it, use it and let me know if you improve it, let me see where you use it too ehh?

This is now on github.