home

100% Human

Worked Example:

Accordion Solitaire

Rules

The player deals out the cards one by one face up, in a row from left to right, as many at a time as space allows.
Any card may be placed on top of the next card at its left, or the third card at its left, if the cards are of the same suit or of the same rank.
The goal is to get all the cards in one pile.

Rules Reference: bicyclecards

screenshot of accordion game

Code

This is all the code needed for the game, as you can see it's very short.

Paperlang was designed exclusively for card-games, so common mechanics such as moving cards between stacks of cards are very easy to express.

game accordion start

    #use "deck"

    shuffle deck
    stacklist row[20]

    setup start end

    turn start
        pickone start
            pick row /> row[:-1:-3] top all where from{from.size > 0}, to{(from.top.v == to.top.v) || (from.top.suit == to.top.suit)} then
            pick deck -> deck top 0 then
                auto deck -> row{|[]} top 1
        end

        every row /> row[:-1] top all where to{(to.size == 0) && (from.size > 0)}

        if (row[0]).size == 52 start
            winneris currentPlayer
        end

    end
end
    

Explanation

As this is the first example, we'll start with some basics.
the whole game is contained within the game start & end lines:

The Game Block


game accordion start
        ...
end
        

You will see a lot of start ... end pairs, together they define a 'block' of code.
This is similar in many ways to other programming languages if you are familiar with software development (variable scope, for instance)


#use "..."

#use "deck"

This simply means that we are going to use the standard 52 card deck of paying cards. They come with all the properly configured card sprites too.

Shuffling

shuffle deck

The previous line actually gave us access to a 'stack' of cards called "deck". You can shuffle any stack of cards, meaning to randomly re-order the cards in the stack.
By default, the deck is structured in order of Rank,Suit.

The Setup Block

setup start end

A setup block is something that runs once at the start of every game. We could have put the shuffle command into the setup block, but this would have made no difference to the game
Any code that is placed directly under the

game accordion start end

blocks will run once at the start of the game too, the only difference is that no animations will be triggered for code that runs outside of the setup block. As this code runs before the game renders for the first time. So if you want any opening setup of your game to be animated, put that code into the setup block.

There is nothing between the

start ... end

in this setup block, meaning the block is empty.

The Turn Block

turn start
    ...
end
    

Anything inside the turn block will run every single turn. Once a turn is over, the next turn will automatically begin. At the moment this autoplay behaviour cannot be changed.

The Pick Block

pickone start
    pick row /> row[:-1:-3] top all where from{from.size > 0}, to{(from.top.v == to.top.v) || (from.top.suit == to.top.suit)} then
    pick deck -> deck top 0 then
        auto deck -> row{|[]} top 1
end
    

This is a "pick block". The pick block is used whenever the player must choose between moving cards from multiple stacks.
There's quite a lot going on here so lets break it down line by line.

pick row /> row[:-1:-3] top all . . . then
    

Give the user the option to pick a card from any stack in the stacklist defined above as row and place that card in the stack imeediately before it, or three spaces before it (row[:-1:-3]) the : before the number here means that we are selecting a position in the stacklist relative to where the cards are being moved from.
top means move cards from the top of the selected stack, and all means move all of the cards from the selected stack. (all could have been replaced by a number 5, or a variable X for instance)

the where clause specifies constraints on what can be selected, we will cover this later.
Importantly, anything after the then and before the next pick or end of the pick block will run after the player has selected that option.
You must always write the word then even if nothing will run. In this case, the first thing after then is the next pick option, so nothing will run after the user selects this option.

Moving & Cutting

There are two ways of moving cards between stacks. Cutting /> and moving ->. Cutting preserves the order of the cards, where as moving reverses them.

Imagine taking a card from one stack and placing it ontop of another stack. Then repeat that 3 times. The top three cards from the source stack are now in the destination stack in the opposite order than they were in before. This is a move ->.

Now imagine you had taken the same three cards from the source stack together, and moved them all at once to the destination stack. The same three cards are now in the same order. This is a cut />.

This is the difference between moving and cutting.

The 'where' Clause

Let's focus on the where clause in the pick block above

 pick ... where from{from.size > 0}, to{(from.top.v == to.top.v) || (from.top.suit == to.top.suit)} ...

This might be more obvious to you if you are familiar with SQL. The where clause constrains what stacks the user can select as the source (from) and destination (to) stacks.
in a where clause, the variable from references the source stack, while the variable to references the destination stack.

from{from.size > 0}

This means, constrain the source stack to stacks that contain at least one card (more than 0 cards)

to{(from.top.v == to.top.v) || (from.top.suit == to.top.suit)}

This means, constrain the set of possible destination stacks to stacks where the top card has either the same v value (from.top.v == to.top.v) OR (||) the same suit value (from.top.suit == to.top.suit)

Note the comma ... > 0}, to{ ... that must separate the two clauses

auto

auto simply means that the move or cut will happen without needing any user input.

... -> row{|[]}

Notice in the second pick block, in the then block (gets executed after the user selects the deck -> deck top 0 option)

we move the top card (top 1) from deck to one of the stacks in row

The {...} means select a stack from this stacklist that satisfies the follwing condition.

The condition we specify is: |[] - meaning the first stack | that matches this sequence []. [] is an empty sequence.

So what this means is, move the top card from deck to the first empty stack in row.

every

after the end of the pick block, we have another /> cut command.

every row /> row[:-1] top all where to{(to.size == 0) && (from.size > 0)}
    

When the source of a move is a stacklist, we can use the every keyword to specify that the move must happen for every stack in the stacklist

We always want to make sure that there are no empty gaps in our accordion, that is, there cannot be an empty stack in between two stacks with cards in them.

This line says: For every stack in the stacklist row, if there are any cards in that stack, and no cards in the stack immediately to the left of it row[:-1], cut all of it's cards one stack to the left.

The 'winneris' clause

the next section should be self explanetory if you are at all familiar with programming.

if (row[0]).size == 52 start
    winneris currentPlayer
end
    

If the first stack in the row contains all 52 cards, then the player has won.

The game code does not detect when there are no moves available to the player, but if it did it could set a loosing state with looseris currentPlayer

The currentPlayer variable simply refurs to the player whos turn it is now. For a single player game, this is always the same player.