#! /bin/bash ############################################################################# # FreeCell Card Game Propositional Model # ############################################################################# # Copyright (C) 2006 by Muhammad Abdul Hakim Newton mahnewton@gmail.com # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation; either version 2 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the # # Free Software Foundation, Inc., # # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################# # See Originally written by Nolan Andres and Robert HillHouse # Typed version adapted by Derek Long # Adapted from TLPLAN to STRIPS. In particular removed all functions # This encoding has less actions, each having less arity # global variables declare PROGRAM=$0 # program name declare -i COUNT=$# # parameter count declare DOMAIN=$(basename $0 | sed -r s/\.[[:alnum:]_-]+$//) # domain and file names are same declare OPTION=$1 # generate the domain (-d) or a problem (-p) or usage () # global functions declare -f explain declare -f domain declare -f problem # explain usage and game rules function explain { echo echo "Usage for domain:" echo " $PROGRAM -d [ey|en iy|in]" echo " ey : use object equality (default)" echo " en : do not use object equality" echo " iy : use type inheritance (default)" echo " in : do not use type inheritance, use (either ...) if needed" echo "Usage for problem:" echo " $PROGRAM -p #suit #rank #cell #pile [#seed]" echo " #suit : number of card suits (even, ceiled if not) e.g. clubs, spades, diamonds, hearts" echo " #rank : number of ranks per suit e.g. A 2 3 4 5 6 7 8 9 10 J K Q" echo " #cell : number of free cells that take one card each" echo " #pile : number of piles where cards are stacked during the game" echo " #seed : optional seed for random number generation" echo "Description:" echo " > This is a generalised version of the FreeCell game that comes with Windows." echo " > There are #suit suits, #rank ranks per suit, #cell free cells and #suit home cells." echo " > The cards start randomly in the #pile piles." echo " > A card that is on top of a pile can be moved to a free cell if contains no card but only a dummy card." echo " > A card from a free cell or from top of a column can be moved to a home cell if that home cell contains a card of the same suit and is one lower in value. For convenience, a dummy card with rank 0 in each suit is already home." echo " > A card from the top of a pile or from a free cell can be moved to the top of another pile if that pile currently holds a card with an opposite colour suit but has one higher value. For convenience, each pile has a dummy card always in its bottom." echo "Observations:" echo " > Planners (e.g. SatPlan) might not support object equality or type inheritance. Use respective switches while generating the domain" echo return 2 } # generate the domain function domain { echo echo "(define" echo " (domain $DOMAIN)" echo " (:requirements" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " :strips :typing :equality" else echo " :strips :typing" fi echo " )" echo " (:types" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " real dummy - card" else echo " real dummy" fi echo " )" echo " (:predicates" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " (card-at-home ?c - card)" echo " (card-at-pile ?c - card)" echo " (card-at-cell ?c - card)" echo " (card-on-card ?c1 - real ?c2 - card)" echo " (can-home-on ?c1 - real ?c2 - card)" echo " (can-pile-on ?c1 - real ?c2 - card)" else echo " (card-at-home ?c - (either dummy real))" echo " (card-at-pile ?c - (either dummy real))" echo " (card-at-cell ?c - (either dummy real))" echo " (card-on-card ?c1 - real ?c2 - (either dummy real))" echo " (can-home-on ?c1 - real ?c2 - (either dummy real))" echo " (can-pile-on ?c1 - real ?c2 - (either dummy real))" fi echo " )" echo " (:action pile-to-pile" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " :parameters (?c1 - real ?c2 ?c3 - card)" else echo " :parameters (?c1 - real ?c2 ?c3 - (either dummy real))" fi echo " :precondition" echo " (and" echo " (card-at-pile ?c1)" echo " (card-on-card ?c1 ?c2)" echo " (card-at-pile ?c3)" echo " (can-pile-on ?c1 ?c3)" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " (not (= ?c1 ?c2))" echo " (not (= ?c1 ?c3))" echo " (not (= ?c2 ?c3))" fi echo " )" echo " :effect" echo " (and" echo " (not (card-on-card ?c1 ?c2))" echo " (not (card-at-pile ?c3))" echo " (card-at-pile ?c2)" echo " (card-on-card ?c1 ?c3)" echo " )" echo " )" echo " (:action pile-to-cell" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " :parameters (?c1 - real ?c2 - card ?c3 - dummy)" else echo " :parameters (?c1 - real ?c2 - (either dummy real) ?c3 - dummy)" fi echo " :precondition" echo " (and" echo " (card-at-pile ?c1)" echo " (card-on-card ?c1 ?c2)" echo " (card-at-cell ?c3)" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " (not (= ?c1 ?c2))" echo " (not (= ?c2 ?c3))" fi echo " )" echo " :effect" echo " (and" echo " (not (card-at-pile ?c1))" echo " (not (card-on-card ?c1 ?c2))" echo " (not (card-at-cell ?c3))" echo " (card-at-cell ?c1)" echo " (card-at-pile ?c2)" echo " (card-on-card ?c1 ?c3)" echo " )" echo " )" echo " (:action cell-to-pile" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " :parameters (?c1 - real ?c2 - dummy ?c3 - card)" else echo " :parameters (?c1 - real ?c2 - dummy ?c3 - (either dummy real))" fi echo " :precondition" echo " (and" echo " (card-at-cell ?c1)" echo " (card-on-card ?c1 ?c2)" echo " (card-at-pile ?c3)" echo " (can-pile-on ?c1 ?c3)" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " (not (= ?c1 ?c3))" echo " (not (= ?c2 ?c3))" fi echo " )" echo " :effect" echo " (and" echo " (not (card-at-cell ?c1))" echo " (not (card-on-card ?c1 ?c2))" echo " (not (card-at-pile ?c3))" echo " (card-at-pile ?c1)" echo " (card-at-cell ?c2)" echo " (card-on-card ?c1 ?c3)" echo " )" echo " )" echo " (:action pile-to-home" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " :parameters (?c1 - real ?c2 ?c3 - card)" else echo " :parameters (?c1 - real ?c2 ?c3 - (either dummy real))" fi echo " :precondition" echo " (and" echo " (card-at-pile ?c1)" echo " (card-on-card ?c1 ?c2)" echo " (card-at-home ?c3)" echo " (can-home-on ?c1 ?c3)" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " (not (= ?c1 ?c2))" echo " (not (= ?c1 ?c3))" echo " (not (= ?c2 ?c3))" fi echo " )" echo " :effect" echo " (and" echo " (not (card-at-pile ?c1))" echo " (not (card-on-card ?c1 ?c2))" echo " (not (card-at-home ?c3))" echo " (card-at-home ?c1)" echo " (card-at-pile ?c2)" echo " (card-on-card ?c1 ?c3)" echo " )" echo " )" echo " (:action cell-to-home" if [[ -z $INHERITANCE || $INHERITANCE == "iy" ]] then echo " :parameters (?c1 - real ?c2 - dummy ?c3 - card)" else echo " :parameters (?c1 - real ?c2 - dummy ?c3 - (either dummy real))" fi echo " :precondition" echo " (and" echo " (card-at-cell ?c1)" echo " (card-on-card ?c1 ?c2)" echo " (card-at-home ?c3)" echo " (can-home-on ?c1 ?c3)" if [[ -z $EQUALITY || $EQUALITY == "ey" ]] then echo " (not (= ?c1 ?c3))" echo " (not (= ?c2 ?c3))" fi echo " )" echo " :effect" echo " (and" echo " (not (card-at-cell ?c1))" echo " (not (card-on-card ?c1 ?c2))" echo " (not (card-at-home ?c3))" echo " (card-at-home ?c1)" echo " (card-at-cell ?c2)" echo " (card-on-card ?c1 ?c3)" echo " )" echo " )" echo ")" echo return 0 } function problem { if (( SEED != 0 )); then RANDOM=$SEED fi echo echo "(define" echo " (problem $DOMAIN-$SUIT-$RANK-$CELL-$PILE)" echo " (:domain $DOMAIN)" echo " (:objects" for (( i = 1; i <= SUIT; i++ )) do echo -e " d-$i-0" # dummy cards for homes done for (( i = 1; i <= CELL; i++ )) do echo -e " d-0-$i" # dummy cards for cells done for (( i = 1; i <= PILE ; i++ )) do echo -e " d-$((SUIT + 1))-$((RANK + i))" # dummy cards for piles done echo -e " - dummy" for (( i = 1; i <= SUIT; i++ )) do for (( j = 1; j <= RANK; j++ )) do echo -e " r-$i-$j" # real cards for different suits and ranks done done echo -e " - real" echo -e " )" echo -e " (:init" for (( i = 1; i <= SUIT; i++ )) do echo -e " (card-at-home d-$i-0)" # dummy home cards done for (( i = 1; i <= CELL; i++ )) do echo -e " (card-at-cell d-0-$i)" # dummy cell cards done for (( i = 1; i <= SUIT; i++ )) do echo -e " (can-home-on r-$i-1 d-$i-0)" # sequence of same suit dummy and real cards for ((j = 2; j <= RANK; j++ )) do echo -e " (can-home-on r-$i-$j r-$i-$((j - 1)))" # sequence of same suit cards done done for (( i = 1; i <= SUIT; i++ )) do for ((j = 1; j <= RANK; j++ )) do for (( k = 1; k <= PILE; k++ )) do echo -e " (can-pile-on r-$i-$j d-$((SUIT + 1))-$((RANK + k)))" # dummy cards are alternate to all cards done for (( k = 0; j < RANK && k < SUIT / 2; k++ )) do echo -e " (can-pile-on r-$i-$j r-$(((i + 2*k) % SUIT + 1))-$((j + 1)))" # alternate color cards and successive ranks done done done # generate a random starting state declare -a PILES # all real cards are in sorted order first for (( i = 1; i <= SUIT; i++ )) do for ((j = 1; j <= RANK; j++ )) do k=$(((i - 1) * RANK + j - 1)) PILES[$k]=r-$i-$j done done for (( i = 0; i < SUIT * RANK; i++ )) # random shuffling of the real cards do j=$(($RANDOM % (SUIT * RANK - i) + i)) # swap cards at i and a random j position k=${PILES[$i]} PILES[$i]=${PILES[$j]} PILES[$j]=$k done # arrange cards in piles if (( SUIT * RANK < PILE )) then for (( k = 0; k < SUIT * RANK; k++ )) do echo " (card-on-card ${PILES[$k]} d-$((SUIT + 1))-$((RANK + k + 1)))" done for (( k = SUIT * RANK; k < PILE; k++)) do echo " (card-at-pile d-$((SUIT + 1))-$((RANK + k + 1)))" done else for (( k = 0; k < PILE; k++ )) do echo " (card-on-card ${PILES[$k]} d-$((SUIT + 1))-$((RANK + k + 1)))" done for (( k = PILE; k < SUIT * RANK; k++ )) do echo " (card-on-card ${PILES[$k]} ${PILES[$k - $PILE]})" done for (( k = SUIT * RANK - PILE; k < SUIT * RANK; k++)) do echo " (card-at-pile ${PILES[$k]})" done fi echo " )" echo " (:goal" echo " (and" for (( i = 1; i <= SUIT; i++ )) do echo " (card-on-card r-$i-1 d-$i-0)" for (( j = 2; j <= RANK; j++ )) do echo " (card-on-card r-$i-$j r-$i-$((j - 1)))" done echo " (card-at-home r-$i-$RANK)" done echo " )" echo " )" echo ")" echo return 0 } # main body if [[ $OPTION == "-p" ]] then declare -i SUIT=$2 # number of suits (even) e.g. clubs, diamonds, spades, hearts declare -i RANK=$3 # ranks per suit e.g. A 2 3 4 5 6 7 8 9 10 J K Q declare -i CELL=$4 # number of free cells declare -i PILE=$5 # number of piles declare -i SEED=$6 # optional seed for random number generation if (( SUIT % 2 != 0 )) then SUIT=$((SUIT+1)) # if number of suits is odd, make it even fi if (( ($COUNT == 5 || $COUNT == 6) && $SUIT > 0 && $RANK > 0 && $CELL > 0 && $PILE > 0 )) then problem else echo echo " Error in parameter count or parameter values." echo explain fi elif [[ $OPTION == "-d" ]] then declare EQUALITY=$2 # optional equality (ey) no-equality en declare INHERITANCE=$3 # optional type inheritance (iy) no-inheritance/either (in) if [[ $COUNT -eq 1 || $COUNT -eq 3 && $EQUALITY == e[yn] && $INHERITANCE == i[yn] ]] then domain else echo echo " Error in parameter count or parameter values." echo explain fi else explain fi exit $?