Categories
About Me

Welcome

This blog’s tagline is adapted from the Emacs Org-Mode motto. It seemed appropriate, as I seem to have spent most of my life writing novels and short stories (of which you can find out more at tonyballantyne.com) or teaching computer coding.

I’ve amassed a lot of material over the years, and I wanted to share it with people who may not have had the same access to education as people living in my country are lucky enough to have. If you want to change the world, become a teacher.

As the the teaching of coding seems to be coming back into fashion, I’ve also included my thoughts on the pedagogy of this subject.

All comments are gratefully received.

No Charge, No Adverts. If you’d like to show your appreciation, please follow me on Twitter @TonyBallantyne

All Materials Copyright (c) Tony Ballantyne 2020

Categories
Emacs Emacs Lisp

Pattern Matching: pcase

Haskell allows pattern matching. The following function counts one, two or many objects

simpleCount 1 = "One"
simpleCount 2 = "Two"
simpleCount _ = "Many"

You can use pattern matching to set base cases in recursive functions.

factorial 0 = 1
factorial n = n * factorial (n-1)

Haskell also allows guards. This if statement checks if someone is old enough to drive in the UK

canDrive x = if x<18 then  "Too young to drive" else "Old enough to drive"

Here it is using guards:

canDrive x
          | x<18 = "Too young to drive"       |
          | otherwise = "Old enough to drive" |

pcase

Emacs Lisp offers similar functionality with the pcase macro. It took me some time to understand the documentation, so here are few examples to get you going. They only scratch the surface, make sure you go back and read up properly afterwards.

(defun simple-count (x)
  (pcase x
    (1 "one")
    (2 "two")
    (_ "many")))

(mapcar #'simple-count '(1 2 5))
=> ("one" "two" "many")

Note that _ is used for the don’t care or wildcard case, rather than the more traditional t.

(defun can-drive (x)
  (pcase x
    ((guard (< x 18)) "Too young to drive")
    (_ "Old enough to drive")))

(can-drive 12)
=> "Too young to drive"

The following converts a test mark into a grade. Note the use of and to evaluate (pred stringp). If non nil, it binds x to msg. In other words, pcase can distinguish between marks and teacher comments.

(defun student-grade (x)
  (pcase x
    ((and (pred stringp) msg) msg)
    ((guard (< x 10)) "Fail")
    ((guard (< x 20)) "C")
    ((guard (< x 30)) "B")
    (_ "A")))

(mapcar #'student-grade '("Absent" 23 12 "off roll" 9 35))
=> ("Absent" "B" "C" "off roll" "Fail" "A")

Take a look at this example from the documentation. Again, it uses and to evaluate (pred stringp). If non nil, it binds x to msg.

So, if x is a string, print it; if x is a recognised symbol, print the associated message; otherwise print unknown return code.

(defun my-errors (x)
  (pcase x
    ;; string
    ((and (pred stringp) msg)
     (message "%s" msg))
    ;; symbol
    ('success       (message "Done!"))
    ('would-block   (message "Sorry, can't do it now"))
    ('read-only     (message "The shmliblick is read-only"))
    ('access-denied (message "You do not have the needed rights"))
    ;; default
    (code           (message "Unknown return code %S" code))))

(mapcar #'my-errors '(1 read-only "hello"))
=> ("Unknown return code 1" "The shmliblick is read-only" "hello")
Categories
Emacs Emacs Lisp

Really Simple Scrivener Mode

Here’s a screenshot of a really simple Scrivener type view for org mode files. I set this up following my simple sidebar set up.

Scriv Sample

I’ve copied the code below (I’ve also joined the 21st Century and started uploading code to GitHub)

The code is actually very simple. To make notes appear in a side window, simply put the letters TR (for top right), BR (for bottom right) or HD (for heading) at the start of a title and then call org-tree-to-indirect-buffer on those headings. I’ve added a key binding to M-s i to make this easy. I like to have certain notes always visible while I’m typing, this system allows me to vary just which notes they are.

And that’s it. Very simple, but I’ve found this very useful when writing.

(defun my-sidebars()
  (setq fit-window-to-buffer-horizontally t)
  (setq window-resize-pixelwise t)

  (setq display-buffer-alist
        `(("\\*Occur\\*" display-buffer-in-side-window
           (side . left) (slot . 0)
           (window-width . fit-window-to-buffer)
           (preserve-size . (t . nil)) 
           (window-parameters . ((no-delete-other-windows . t))))
          (".*\\.org-HD." display-buffer-in-side-window
           (side . top) (slot . 0) 
           (preserve-size . (t . nil)) 
           (window-parameters . ((no-delete-other-windows . t))))
          (".*\\.org-TR." display-buffer-in-side-window
           (side . right) (slot . -1) 
           (preserve-size . (t . nil)) 
           (window-parameters . ((no-delete-other-windows . t))))
          (".*\\.org-BR." display-buffer-in-side-window
           (side . right) (slot . 1) 
           (preserve-size . (t . nil)) 
           (window-parameters . ((no-delete-other-windows . t)))))))

(defun my-indirect-buffer ()
  (interactive)
  (let ((current-prefix-arg 4))                       ;; emulate C-u
    (call-interactively 'org-tree-to-indirect-buffer)))

(defun scriv()
  (interactive)
  (when (require 'wc-mode nil t)
    (wc-mode))
  (toggle-frame-maximized)
  (my-sidebars)
  (global-set-key (kbd "M-s i") 'my-indirect-buffer))
Categories
Emacs Emacs Lisp Emacs Setup

Sidebar for Emacs Org Mode

It would be nice to have a sidebar when using org mode. The sidebar would display the headlines of an org file. When a headline is selected, the subheadings and text would be displayed in another buffer. 

You can currently do this by using C-c C-x b which is bound to (org-tree-to-indirect-buffer). The command opens a subtree in an indirect buffer which is sort of what I’m looking for, but you have to enter the command each time you land on a new headline.

You can make the process automatic by adding a hook as follows:

(add-hook 'post-command-hook #'org-tree-to-indirect-buffer nil :local)

The solution works, but it’s not quite there.

Searching the internet I found a useful suggestion from the delightfully named My Other Soup’s a Borscht:

M-x occur then search for the regexp "*+ " (note the space at the end)

This gives more of the functionality I want and has the advantage of being customizable. One problem: I wanted the sidebar to appear on the left hand side.

So I looked a little further and discovered side windows

My first thought was so what? I can already do that by splitting windows. The advantage of side windows is that you can set them to stay in position and to fix the buffer they display. No more losing your layout when you hit C-x 1.

If the above seems a little confusing (and it did to me at first) there’s an example of what you can do here in the Emacs Manual 

So I combined the two things I’d learned and came up with the following function:

(defun my-sidebar-occur()
 (interactive)
 (setq fit-window-to-buffer-horizontally t)
        (setq window-resize-pixelwise t)

        (setq
       display-buffer-alist
       `(("\\*Occur\\*" display-buffer-in-side-window
          (side . left) (slot . 0) (window-width . fit-window-to-buffer)
          (preserve-size . (t . nil)) 
          (window-parameters . ((no-delete-other-windows . t)))))))

Here’s a video of the process in action.

One last thing. org-sidebar appears to solve my problem, but at the time of writing it’s still a little buggy. It’s nicely done though and could well become the standard in the future. Until then, I’ll use my workaround.

Categories
99 Python Problems

– List Solutions

breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
palindromic = ["Sausage", "Eggs", "Beans", "Beans", "Eggs", "Sausage"]
nums = [1,1,3,3,3,2,2,2,1,1,1,1,4,4,4,4]
letters = ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']

def print_list(list):
    for item in list:
        print(item)

def last_element(list):
    return (list[-1])

def last_but_one(list):
    return (list[-2])

# Using reversed function
def my_reverse(list):
    new_list = []
    for item in reversed(list):
        new_list.append(item)
    return new_list

# Using for loop
def my_reverse2(list):
    new_list = []
    for i in range (len(list)-1, -1, -1):
        new_list.append(list[i])
    return new_list

# Using list comprehension
def my_reverse3(list): 
    return [item for item in reversed(list)] 

# Using slicing
def my_reverse4(list): 
    return list[::-1]
  
    
def is_palindrome(list):
    if list == my_reverse(list):
        return True
    else:
        return False

def compress(list):
    new_list = []
    last_item = list[0] + 1 # so first number is different to itself
    for num in list:
        if num != last_item:
            new_list.append(num)
        last_item = num
    return new_list

def pack(list):
    pack_list = []
    last_item = list[0]
    word = ""
    for item in list:
        if item == last_item:
            word = word + item
        else:
            pack_list.append(word)
            word = item
        last_item = item
    pack_list.append(word)
    return pack_list
Categories
99 Python Problems

3: Lists

3.1 Print List

Write a function that prints out a list, one element per line

3.1.1 Example

 1: breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
 2: 
 3: print_list(breakfast)
 4:  *** Output ***
 5: Sausage
 6: Eggs
 7: Beans
 8: Bacon
 9: Tomatoes
10: Mushrooms

3.2 Last Element of Array

Write a function that returns the last element of a string array

3.2.1 Example

1: breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
2: 
3: print(last_element(breakfast));
4:  *** Output ***
5: Mushrooms

3.3 Last But One Element of Array

Write a function that returns the last but one element of a string array

3.3.1 Example

1: breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
2: 
3: print(last_but_one(breakfast));
4:  *** Output ***
5: Tomatoes

3.4 Reverse a list, leaving original intact

Return a list in reverse order, while leaving the original list intact.

3.4.1 Example

 1: breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
 2: 
 3: print(my_reverse(breakfast))
 4: print(breakfast)
 5:  *** Output ***
 6: : Mushrooms
 7: : Tomatoes
 8: : Bacon
 9: : Beans
10: : Eggs
11: : Sausage
12: : Sausage
13: : Eggs
14: : Beans
15: : Bacon
16: : Tomatoes
17: : Mushrooms

3.5 Palindromic lists

Write a function that tests to see if a list is palindromic, i.e. the elements are the same when reversed.

3.5.1 Example

1: palindromic = ["Sausage", "Eggs", "Beans", "Beans", "Eggs", "Sausage"]
2: breakfast = ["Sausage", "Eggs", "Beans", "Bacon", "Tomatoes", "Mushrooms"]
3: 
4: print(is_palindrome(palindromic))
5: print(is_palindrome(breakfast))
6:  *** Output ***
7: True
8: False

3.6 Consecutive Duplicates

Write a function to print out list of integers with consecutive duplicates eliminated

1: nums = [1,1,3,3,3,2,2,2,1,1,1,1,4,4,4,4]
2: 
3: compress(nums)
4:  *** Output ***
5: : 1
6: : 3
7: : 2
8: : 1
9: : 4

3.7 Pack Duplicates

Pack consecutive duplicates of a char list into Strings

1: letters = ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']
2: 
3: pack(letters)
4:  *** Output ***
5: : aaaa, b, cc, aa, d, eeee

Categories
Be a Better Coder

Recursion Explained Using Sandwiches

  • If you put a piece of toast between two slices of bread, you have a toast sandwich.
  • If you put a piece of bread between two slices of bread, you have a bread sandwich.
  • If you put a piece of bread between two pieces of toast you have a toasted bread sandwich.

It would be nice to have a program that identifies what sort of sandwich we have.

If we’re going to do this we’ll need a way to represent the make up of our sandwich. One way would be to use lists, as follows

  • [B,T,B] Toast sandwich
  • [B,B,B] Bread sandwich
  • [T,B,T] Toasted bread sandwich

We can now represent more complicated sandwiches such as the following:

  • [B,T,B,T,B] Toasted bread sandwich sandwich
  • [T,T,B,T,T] Toasted toasted bread sandwich sandwich

Now we have a sandwich data structure, we can write a program that will accept a list such as [B,T,B] as input and then output “Toast sandwich”.

… but before we start reaching for a for loop to traverse that list, let’s just to a moment to notice something. Sandwiches have sandwiches inside them.

If you look at [B,T,B,T,B], a toasted bread sandwich sandwich, you’ll notice that it’s really just a [T,B,T] or toasted bread sandwich wrapped in bread. And in fact, a [T,B,T] is just a piece of bread wrapped in toast.

Let’s do the above backwards

  • [B] – A piece of bread
  • [T,B,T] – A toasted bread sandwich
  • [B,T,B,T,B] – A toasted bread sandwich wrapped in bread, in other words, a toasted bread sandwich sandwich

To check you’ve understood this, try deconstructing a [T,B,T,B,T,B,T]. You should get a toasted toasted bread sandwich sandwich sandwich.

The fact that we can repeatedly reduce this problem to simpler sandwich, two slices at a time, tells us that this problem could be solved by recursion. We’re going to write a recursive function that strips away the sandwich, two slices at a time.

Start by defining a function called SNS (sandwich name service). This function will use python slicing to find the base, top and filling of the sandwich.

If the sandwich contains only one item it will simply be a piece of bread or a piece of toast. A one item sandwich will be the base case or escape clause for our recursive function.

If the sandwich contains more than one item, we’ll remove the outer layers and then call the SNS function again with the filling.

Here are a couple of examples

Input [T]

This is a one item sandwich, so SNS outputs “toast”

Input [B,B,T,B,B]

This is not a one item sandwich, so SNS strips the outer bread layers and then calls itself with the filling:

SNS([B,T,B]) + “sandwich”

Here’s the code:

B = "bread"
T = "toast"

def SNS(sandwich):
    base = sandwich[0]
    top = sandwich[-1]
    filling = sandwich[1:-1]

    if len(sandwich) == 1:
       return sandwich[0]
    if base == top:
       if base == B:
          return SNS(filling) + " sandwich"
    else:
          return "toasted " + SNS(filling) + " sandwich"


print(SNS([T,B,B,B,T]))

And there we have it. Sandwiches identified recursively.

There are problems with this code. It doesn’t check for incorrect input. It doesn’t identify even numbered lists correctly as open faced sandwiches or things on toast. Perhaps you could fix that…

Categories
Emacs Emacs Workout

Chessboards

Here’s a chessboard. Each square is 4×4 characters

    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX

What’s the most Emacsy way of producing the above?

First Line

Let’s start with the first line

XXXX    XXXX    XXXX    XXXX

You could do the following: 

C-4 <space> 4 Spaces
C-4 X       4 Xs
C-a         Jump to start of line
C-k         Kill line
C-y         Yank
C-x z z z   Repeat last command three times

Another way is to use a macro:

F3          Start recording
C-4 <space> 
C-4 X       
F4          Stop recording
F4 F4 F4    Run the macro three times

Once you have one line, you could copy it and then yank it three times to get the first line of squares.

Here’s another way to get a line of squares, this time using rectangles. See this post to remind yourself about rectangles.

Start with just the black squares:

C-16 X 
Kill and yank to get the following:

XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX

Now insert the white squares:

Go to start of the pattern

Set the region to cover the first square
C-x r o to insert blank space to fill the space of the region-rectangle

    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXX

Now move the point forward 8 so its at the correct position to open the next square

C-8 C-f

You can record a macro of the above and then run it 3 times. Don’t forget to add the C-8 C-f at the end to move the point to the correct starting position.

2 The Second Line

Once you have the first line of squares, the second is quite easy. Copy one line of squares beneath itself to get the following:

    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX

And then use C-x r k to kill the white square at the start of the second line.

    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
    XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX
XXXX    XXXX    XXXX    XXXX

Now you can just kill and yank four times to get the complete chessboard.

Of course, you could just do it in LISP:

(defun one-line(pattern)
   "Insert PATTERN 4 times"
   (dotimes (count 4)
     (insert pattern)))

 (defun four-lines(pattern)
   "Insert 4 lines of PATTERN"
   (dotimes (count 4)
     (one-line pattern)
     (insert "\n")))

 (defun chess-board()
   (interactive)
   (dotimes (count 4)
     (four-lines "    XXXX")
     (four-lines "XXXX    ")))

M-x chess-board

Can you think of a more efficient method than the ones above? Why not post it below?

Categories
Emacs Emacs Workout

Emacs Characters 3

I never thought I would write three posts about entering characters in Emacs.

Emacs Characters demonstrates the quickest way to insert characters such as è and ä by using the C-x 8 key combination. So, for example:

C-x 8 ' e prints é
C-x 8 `e prints è
C-x 8 ^ e prints ê
C-x 8 " u prints ü
C-x 8 / / prints ÷
C-x 8 C prints © copyright

Emacs Characters 2 shows how C-x 8 [return] allows you to type in the description of a character, so C-x 8 [return] LEFT ARROW gives ←

It’s time for another way. This post demonstrates toggle-input-method. Emacs has a number of input methods, used for entering such things as Arabic characters. You can see the full list using

 M-x list-input-methods 

Use C-\ to enable the input method. The first time you do this you’ll be prompted for a method. For the purposes of this post, enter TeX. If you don’t know TeX, this post gives you a flavour.

You can now enter characters using TeX. Here are some examples

\pir^2 → πr²
Z\"urich → Zürich
Caf\'e  → café

I used \rightarrow to get the → used above, by the way.

When you’re done using TeX, use C-\ to disable the current input method

That’s three different methods for entering text. Which one is best? For me, it’s whichever is the most convenient. If I want to type the acute accent in café I’d probably use C-x 8 ‘e. When I was writing my novel Dream Paris I used TeX input for typing in the French dialogue.

As this is the Emacs workout, why not think of the ways you could type the following in Emacs?

Einstein wrote E=mc² on the table whilst eating a rösti in a café in Zürich. As easy as πr², he thought.

If you get stuck

M-x describe-input-method 

will give a list of key sequences.

Categories
Emacs Emacs Lisp

Common Lisp Loops

I can’t think why you wouldn’t use the Common Lisp loop macro in Emacs. Don’t forget to (require ‘cl-lib)

Simple Loops

;; keywords: to, upto, below, downto, above, by
;; keywords: collect, append, nconc, count, sum, maximize, minimize

(cl-loop
    do (princ 1))
=> 111111... infinite loop

(cl-loop repeat 5
     do (princ 1)
     (princ 2))
=> 1212121212

(cl-loop for i from 1 below 10
     maximize i)
=> 9

(cl-loop for x from 9 downto 1
     collect x)
=> (9 8 7 6 5 4 3 2 1)

(cl-loop for i from 10 above 1 by 2
     collect i)
=> (10 8 6 4 2)

Looping over Sets and Arrays

;; keywords: in, on, across, by
;; Remember in for lists
;; across for vectors

(cl-loop for l in '(1 2 3 4 5)
     do (princ l))
=> 12345

(cl-loop for l in '(1 2 3 4 5) by #'cddr
     collect l)
=> (1 3 5)

(cl-loop for l on '(1 2 3 4 5)
     collect l)
=> ((1 2 3 4 5) (2 3 4 5) (3 4 5) (4 5) (5))

(cl-loop for l on '(1 2 3 4 5) by #'cddr
     collect l)
=> ((1 2 3 4 5) (3 4 5) (5))

;; Remember that a string is an array in lisp, so...
;; Add up the digits in 90125
(cl-loop for d across "90125"
    sum (- d 48))
=> 17

Destructuring

(cl-loop for (a nil) in '((1 2) (2 3) (3 4))
     collect a)
=> (1 2 3)

(cl-loop for (a b) in '((1 2) (2 3) (3 4))
     collect (* a b))
=> (2 6 12)

(cl-loop for (a b) on '(1 2 3 4 5) while b
      collect (+ a b))
=> (3 5 7 9)

(cl-loop for (a b) on '(1 2 3 4 5) by #'cddr while b
     collect (+ a b))
=> (3 7)

Hashtables

(cl-loop for key being the hash-keys of myhashtable
        using (hash-value value)
        do (princ value))

Parallel fors

(cl-loop for i from 1 to 5
     for l in '(a b c d)
     collect (list i l))
=> ((1 a) (2 b) (3 c) (4 d))

(cl-loop for i from 1 to 5
     for j from 2 to 10 by 2
     collect (* i j))
=> (2 8 18 32 50)

Nested fors

(cl-loop for i from 1 to 5
     collect (cl-loop for j from 1 to 5
             collect (* i j)))
=> ((1 2 3 4 5) (2 4 6 8 10) (3 6 9 12 15) (4 8 12 16 20) (5 10 15 20 25))

(cl-loop for i from 1 to 5
     append (cl-loop for j from 1 to 5
             collect (* i j)))
=> (1 2 3 4 5 2 4 6 8 10 3 6 ...)

(cl-loop for i from 1 to 5
     collect (cl-loop for j from 1 to 5
             sum (* i j)))
=> (15 30 45 60 75)

(cl-loop for i from 1 to 5
     sum (cl-loop for j from 1 to 5
             sum (* i j)))
=> 225

Selection

;; if, when, unless

(cl-loop for i from 1 to 20
     unless (cl-evenp i) collect i)
=> (1 3 5 7 9 11 13 15 17 19)

(cl-loop for i from 1 to 20
     when (= (% i 3) 0) collect i into fizz
     when (= (% i 5) 0) collect i into buzz
     finally return (list fizz buzz))
=> ((3 6 9 12 15 18) (5 10 15 20))

(cl-loop for i from 1 to 20
     if (and (= (% i 3) 0) (= (% i 5) 0)) collect i into fizzbuzz
     else if (= (% i 3) 0) collect i into fizz
     else if (= (% i 5) 0) collect i into buzz
     finally return (list fizz buzz fizzbuzz))
=> ((3 6 9 12 18) (5 10 20) (15))

(cl-loop for i from 1 to 10
     if (cl-evenp i)
     collect i into evens
     and sum i into evensum
     else
     collect i into odds
     and sum i into oddsum
     finally return (list evens evensum odds oddsum))
=> ((2 4 6 8 10) 30 (1 3 5 7 9) 25)

Find c from comp where diff is never a member of squares
(cl-loop for c in comp
     if  (cl-loop for p in pri
              for diff = (/ (- c p) 2)
              never (member diff squares))
     collect c)

Then Iteration

(cl-loop for i from 1 to 5
     for square = (* i i)
     collect square)

;; Though you'd be better with
(cl-loop for i from 1 to 5
     collect (* i i))

;; However, this leads to Triangle Numbers
(cl-loop for n from 1 to 10
     for triangle = 1 then (+ triangle n)
     collect triangle)
=> (1 3 6 10 15 21 28 36 45 55)

(cl-loop for x = 0 then y
     for y = 1 then (+ x y)
     while (< y 30)
     collect y)
=> (1 2 4 8 16)

;; Fibonacci Sequence (note the and)
(cl-loop for x = 0 then y
     and y = 1 then (+ x y)
     while (< y 30)
     collect y)
=> (1 1 2 3 5 8 13 21)

Termination

;; while, until, always, never, and thereis

while and until are straightforward

(cl-loop for n from 1
for tri = 1 then (+ tri n)
until (> (divs tri) 500)
finally return tri)

never, thereis and always are shorthand for a combination of when-return

(defun isprime(n)
  (cond
   ((< n 2) nil)
   ((= n 2) t)
   ((cl-evenp n) nil)
   (t
    (cl-loop for i from 3 to (sqrt n) by 2
         never (= (% n i) 0)))))
Categories
Python Adventure Game Uncategorized

Adventure Game 8: Making a Playable Game

Now we have a working game engine, we need to make the game more interesting.

We can do this in a number of ways.

  1. Think of an interesting setting: in a castle, on a spaceship, in a school for witches and wizards…
  2. What quest are we setting the player? To find the gold? Escape from the space station before it explodes? To find the spy?
  3. How about adding some characters: dragons, vampires, aliens, zombies?
  4. What sort of objects could we use? Magic wands, rayguns, teleporters?
  5. What sort of puzzles and riddles could we add?

Exercise

  1. Think of the setting for your game. What does the player have to do (what’s their quest?)
  2. Draw a map for your game (see lesson 1 for an example) Don’t add too many locations – 16 is more then enough.
  3. Think of the objects the player will have to use and add them to the map.
  4. Make a note of the game play. What will the player have to do to complete the game.
  5. Now modify the code of the game engine to write your own game.
  6. Get your partner to play the game and feedback.
  7. Make any improvements to the game.