#!/pkg/gnu/bin/gawk -f BEGIN { # # this script regulates the play of ronald loui's and anne jump's game # which is intended to model the following aspects of negotiation # which are absent in game-theoretic approaches: # # re: search # the creation of focal points through dialogue and search # interplay of individual and social search # joint problem-solving through resource exchange and search # cost of search and heuristic/satisficing search # multidimensionality of settlement options generated, not predefined # # re: language # explicit threats and queries # unrestricted language # # re: purpose # multiplicity of winning conditions # # re: method # importance of design not analysis # importance of process not outcome # importance of player input to a process, not equilibria # # this game was developed during the summer of 1997 by ronald p. loui # and anne h. jump, a consultant, funded by the national science foundation # program on information technology and organizations within the # information, robotics, and intelligent systems division of the # computer and information systems engineering directorate. # version 4.3 of 1/98 rpl # 1.0 attempts as clean code as possible for basic functionality # 2.0 MAJOR REVISION: permits programs to be used to generate commands # 2.1 can pipe output to /dev/stdout and file for programs to read # 2.2 implements otake # 2.3 puts limit on how long to negotiate # 2.4 implements the verbose option # 2.5 fixes a bug that lets you accept your own proposals # 2.6 contains all the code needed to run as a tournament # 3.0 of 12/97 permits gui monitoring of negotiation # 4.0 MAJOR REVISION sends output to the web # 4.1 MAJOR REVISION reads, processes a single command, then saves # 4.2 cleaner HTML table, input mostly separate from payoff presentation # 4.3 MAJOR REVISION abstracts players' names (anne --> playerA) # 5.0 MAJOR REVISION to rules of the game: pilecardmin verbose = 1 gui = 0 webout = 1 cgidebug = 1 print "
"
playerAprog = ARGV[1]
playerBprog = ARGV[2]
pairing = ARGV[3]
# each program takes a view.playerB or view.playerA and generates a move
# assume these programs are executable, and paired with X.howhappy, which is also executable
if (playerAprog ~ "---") playerAprog = ""
if (playerBprog ~ "---") playerBprog = ""
if (playerAprog) { playerAcom = playerAprog " playerA" }
if (playerBprog) { playerBcom = playerBprog " playerB" }
# this may need to be set differently for tournament or cgi
PATH = "/home/cs/faculty/loui/.www-docs/313f97/"
PATH = "./"
savefile = PATH "anne.save"
dialoguefile = PATH "anne.dialogue"
srand()
if (restore()) {
print "restoring"
} else {
print "reinitializing"
if (rand() < .5) whoseturn = "playerA"
else whoseturn = "playerB"
init()
deal()
revealsomecards()
save()
if (webout) viewweb()
# don't process input on a reinitialization
exit
}
if (negotiate(1)) {
revealremaining()
if (webout) finalweb()
if (verbose) view("playerA and playerB","/dev/stdout")
traderesources()
doexchanges()
if (verbose) view("playerA and playerB","/dev/stdout")
sumcells()
reportsums()
reportvalue(finalrow,finalcol)
askhowhappy()
score()
makesocialrecord()
} else save()
if (cgidebug) print "CGIDEBUG normal exit"
}
function finalweb( i) {
prhtml("A Better Negotiation Game, designed by R.P. Loui and A.H. Jump, Summer 1997.")
prhtml("
")
prhtml("FINAL OUTCOME
")
prhtml("EXPLANATION")
prhtml(" ")
viewwebhow("playerA",1)
viewwebhow("playerB",1)
# don't close because values will be reported
# erase the savefile
close(savefile)
print "" > savefile
close(savefile)
}
function save( i,j,ntemp) {
# rows, cols
# playerA, playerB
# annresources
# playerBresources
# count:
# resources
# count:
# proposals
# count:
# sidepayments
# count:
# sidetakings
# whoseturn
# forcingperson
# finalrow
# finalcol
# plies
# search stats
print rows, cols > savefile
for (i=1; i<=rows; i++) for (j=1; j<=cols; j++) print playerA[i,j], playerB[i,j] > savefile
print playerAresources > savefile
print playerBresources > savefile
ntemp = 0
for (i in resources) if (resources[i]) ntemp++
print ntemp, "resources" > savefile
for (i in resources) if (resources[i]) print i,resources[i] > savefile
ntemp = 0
for (i in activeprop) if (activeprop[i]) ntemp++
print ntemp, "activeprop" > savefile
for (i in activeprop) if (activeprop[i]) print i,activeprop[i] > savefile
ntemp = 0
for (i in sidepay) ntemp++
print ntemp, "sidepay" > savefile
for (i in sidepay) print i,sidepay[i] > savefile
ntemp = 0
for (i in sidetake) ntemp++
print ntemp, "sidetake" > savefile
for (i in sidetake) print i,sidetake[i] > savefile
print whoseturn, "whoseturn" > savefile
print forcingperson > savefile
print finalrow > savefile
print finalcol > savefile
print plies > savefile
print maxplies > savefile
print playerAfree > savefile
print playerAfreeused > savefile
print playerAcost > savefile
print playerAcostused > savefile
print playerBfree > savefile
print playerBfreeused > savefile
print playerBcost > savefile
print playerBcostused > savefile
close(savefile)
}
function restore( i,j,ntemp) {
if ((getline < savefile) == -1) return 0
# actually, need an empty file to save write-permissions
if (!$0) return 0
rows = $1; cols = $2
for (i=1; i<=rows; i++) for (j=1; j<=cols; j++) {
getline < savefile
playerA[i,j] = $1; playerB[i,j] = $2
}
getline playerAresources < savefile
getline playerBresources < savefile
getline < savefile
ntemp = $1
for (i=1; i<=ntemp; i++) {
getline < savefile
resources[$1] = $2
}
getline < savefile
ntemp = $1
for (i=1; i<=ntemp; i++) {
getline < savefile
activeprop[$1] = $2
}
getline < savefile
ntemp = $1
for (i=1; i<=ntemp; i++) {
getline < savefile
sidepay[$1] = $2
}
getline < savefile
ntemp = $1
for (i=1; i<=ntemp; i++) {
getline < savefile
sidetake[$1] = $2
}
getline < savefile
whoseturn = $1
getline forcingperson < savefile
getline finalrow < savefile
getline finalcol < savefile
getline plies < savefile
getline maxplies < savefile
getline playerAfree < savefile
getline playerAfreeused < savefile
getline playerAcost < savefile
getline playerAcostused < savefile
getline playerBfree < savefile
getline playerBfreeused < savefile
getline playerBcost < savefile
getline playerBcostused < savefile
close(savefile)
return 1
}
function report(x) {
print x
violation = x
}
function negotiate(oneturn) {
# the oneturn flag restricts this to one input
# returns 1 if agreement/breakdown
# if (rand() < .5) whoseturn = "playerA"
# else whoseturn = "playerB"
do {
plies++
if (plies > maxplies) {
print "negotiation too long... exiting!", plies
exit
}
if (verbose) {
print "\t\t\t\t_______________"
print "\n\t\t\t\t "whoseturn"'s turn"
print "\t\t\t\t_______________"
view(whoseturn,"/dev/stdout")
}
if (cgidebug) print "CGIDEBUG beginning program views"
if (playerAprog || playerBprog) view(whoseturn,outfile(whoseturn))
# if (verbose) if (++turn <= 2) printmenu()
if (gui) viewgui()
if (forcingperson == whoseturn) {
print whoseturn" has left the negotiation with "
print lastforce
$0 = lastforce
savecommand = $0
} else if (playerAprog && whoseturn ~ /playerA/) {
playerAcom | getline
savecommand = $0
close(playerAcom)
# protect from spies
# system("rm -f "outfile(whoseturn))
violation = ""
command()
} else if (playerBprog && whoseturn ~ /playerB/) {
playerBcom | getline
savecommand = $0
close(playerBcom)
# protect from spies
# system("rm -f "outfile(whoseturn))
violation = ""
command()
} else {
printf "\t\t\t"whoseturn"'s action (or 'menu' or 'redraw')?"; getline
savecommand = $0
if ($0 ~ /menu/) {
printmenu()
printf "\t\t\t\t"whoseturn"'s action (or 'redraw')?"; getline
}
if ($0 ~ /redraw/) {
continue
} else {
resultingview = 0; # could be set to 1 in command
violation = ""
command()
}
}
if (cgidebug) print "CGIDEBUG updating dialogue"
addtodialogue(savecommand)
if (cgidebug) print "CGIDEBUG updated dialogue"
if (verbose) if (resultingview) view(whoseturn,"/dev/stdout")
if (whoseturn == "playerA") whoseturn = "playerB"
else whoseturn = "playerA"
if (forcingperson) whoseturn = otherplayer(forcingperson)
if (cgidebug) print "CGIDEBUG updating webout"
if (webout) viewweb()
if (cgidebug) print "CGIDEBUG updated webout"
} while ((!agreement && !oneturn) || savecommand ~ /redraw/)
if (cgidebug) print "CGIDEBUG normal return from negotiate"
return agreement
}
function outfile(x) {
if (x ~ /playerB/) return PATH "view.playerB"
if (x ~ /playerA/) return PATH "view.playerA"
}
function command(new,n,cards,i) {
if (cgidebug) print "\nCGIDEBUG entering command processing of "$0
if (playerAprog && whoseturn ~ /playerA/) printf playerAprog" "
if (playerBprog && whoseturn ~ /playerB/) printf playerBprog" "
print whoseturn": "$0
# only response to a force is a force
if (forcingperson) {
if ($1 !~ /fo/) report( "PROTOCOL VIOLATION: only response to force is force" )
}
# accept
if ($1 ~ /^ac/) {
if (activeprop[$2,$3,otherplayer(whoseturn)]) {
finalrow = $2
finalcol = $3
agreement = 1
} else report( "PROTOCOL VIOLATION: accept only proposed offers" )
}
# propose
if ($1 ~ /^pr/) if (kosher($2,$3)) {
activeprop[$2,$3,whoseturn] = 1
specialmarks[$2,$3] = "***"
}
# rescind proposal, unpropose
if ($1 ~ /^unpr/) if (kosher($2,$3)) {
if (!activeprop[$2,$3,whoseturn]) report( "PROTOCOL VIOLATION: propose before you rescind" )
else delete activeprop[$2,$3,whoseturn]
for (i in sidepay)
split(i,temp,"\034")
if (temp[1] == $2 && temp[2] == $3 && temp[4] == whoseturn) {
delete sidepay[i]
print "deleting sidepayment "i" with the proposal."
}
for (i in sidetake)
split(i,temp,"\034")
if (temp[1] == $2 && temp[2] == $3 && temp[4] == whoseturn) {
delete sidetake[i]
print "deleting sidetaking "i" with the proposal."
}
}
# search
if ($1 ~ /^se/) if (kosher($2,$3)) {
if (!chargeto(whoseturn)) return
new = getcard()
if (whoseturn == "playerA") {
psrc[$2,$3] = psrc[$2,$3] "a"
specialmarks[$2,$3] = "+++"
n = sub(/\?/,new,playerA[$2,$3])
}
if (whoseturn == "playerB") {
psrc[$2,$3] = psrc[$2,$3] "b"
specialmarks[$2,$3] = "+++"
n = sub(/\?/,new,playerB[$2,$3])
}
if (!n) report( "PROTOCOL VIOLATION: no more cards to reveal" )
resultingview = 1
}
# generate substitution
if ($1 ~ /^su/) if (kosher($2,$3)) {
if (!chargeto(whoseturn)) continue
n = $4
if (whoseturn == "playerA") cards = playerA[$2,$3]
if (whoseturn == "playerB") cards = playerB[$2,$3]
parsetotemp(cards)
if (temp[n] ~ /[rb]/) {
new = getcard()
temp[n] = temp[n]">"new
} else report( "PROTOCOL VIOLATION: no such card to substitute" )
cards = ""
for (i=1; i<=nt; i++) {
cards = cards temp[i]
}
if (whoseturn == "playerA") playerA[$2,$3] = cards
if (whoseturn == "playerB") playerB[$2,$3] = cards
resultingview = 1
}
# threaten row or col for playerA or playerB
if ($1 ~ /^fo/) {
if (whoseturn == "playerA") {
threat = $2
if ($3 != ".") {
report( "PROTOCOL VIOLATION: use . for column" )
return
}
if (!kosher(threat,1)) {
report( "PROTOCOL VIOLATION: no such row" )
return
}
}
if (whoseturn == "playerB") {
threat = $3
if ($2 != ".") {
report( "PROTOCOL VIOLATION: use . for row" )
return
}
if (!kosher(1,threat)) {
report( "PROTOCOL VIOLATION: no such column" )
return
}
}
}
# ask what's wplayerBg with a proposal, whynot
if ($1 ~ /^wh/) {
if (!activeprop[$2,$3,whoseturn]) {
report( "PROTOCOL VIOLATION: propose before you ask" )
return
}
}
# ask if other has a card, haveyou
if ($1 ~ /^ha/) {
if (!iscard($2)) {
report( "PROTOCOL VIOLATION: resource must be a card" )
return
}
}
# offer a card as sidepayment to a proposal
if ($1 ~ /^of/) {
if (!(resources[whoseturn,$4])) {
report( "PROTOCOL VIOLATION: offer only what you have" )
return
}
sidepay[$2,$3,$4,whoseturn] = 1
}
# offer to take a card as sidepayment to a proposal
if ($1 ~ /^ot/) {
sidetake[$2,$3,$4,whoseturn] = 1
}
# retract an offer a card as sidepayment to a proposal, unoffer
if ($1 ~ /^unof/) {
if (!sidepay[$2,$3,$4,whoseturn] && !sidepay[$2,$3,$4,whoseturn]) {
report( "PROTOCOL VIOLATION: no such sidepayment offered" )
return
}
if (!activeprop[$2,$3,whoseturn]) {
report( "PROTOCOL VIOLATION: no such proposal active")
return
}
delete sidepay[$2,$3,$4,whoseturn]
delete sidetake[$2,$3,$4,whoseturn]
}
# warn that breakdown is imminent
if ($1 ~ /^wa/) {
# nothing to do here
}
# force breakdown for playerA or playerB
if ($1 ~ /^fo/) {
if (whoseturn == "playerA") {
threat = $2
if ($3 != ".") {
report( "PROTOCOL VIOLATION: use . for column" )
return
}
if (!kosher(threat,1)) {
report( "PROTOCOL VIOLATION: no such row" )
return
}
finalrow = $2
}
if (whoseturn == "playerB") {
threat = $3
if ($2 != ".") {
report( "PROTOCOL VIOLATION: use . for row" )
return
}
if (!kosher(1,threat)) {
report( "PROTOCOL VIOLATION: no such column" )
return
}
finalcol = $3
}
if (forcingperson) {
# this is the response to a force
agreement = 1
}
forcingperson = whoseturn
lastforce = $0
}
if (cgidebug) print "CGIDEBUG normal return from command function"
}
function iscard(x) {
if (x ~ /^[rb][0-9]$/) return 1
if (x ~ /^[rb]10$/) return 1
if (x ~ /^[rb]11$/) return 1
if (x ~ /^[rb]12$/) return 1
if (x ~ /^[rb]13$/) return 1
return 0
}
function otherplayer(x) {
if (x == "playerA") return "playerB"
if (x == "playerB") return "playerA"
}
function addtodialogue(x) {
print whoseturn,x,violation >> dialoguefile
if (cgidebug) print "CGIDEBUG closing dialogue file"
close(dialoguefile)
if (cgidebug) print "CGIDEBUG dialogue file closed"
system("chmod ogu+r " dialoguefile)
}
function revealsomecards(n,maxreveal) {
maxreveal = int(10*rand())
for (n=1; n<=maxreveal; n++) {
revealplayerA(int(rand()*rows)+1, int(rand()*cols)+1)
revealplayerB(int(rand()*rows)+1, int(rand()*cols)+1)
}
}
function revealplayerA(i,j) { sub(/\?/,getcard(),playerA[i,j]) }
function revealplayerB(i,j) { sub(/\?/,getcard(),playerB[i,j]) }
function chargeto(x) {
if (x ~ /playerA/) {
if (playerAfreeused < playerAfree) { playerAfreeused++; return 1 }
if (playerAcostused < playerAcost) { playerAcostused++; return 1 }
report( "PROTOCOL VIOLATION: sorry, no search left" )
return 0
}
if (x ~ /playerB/) {
if (playerBfreeused < playerBfree) { playerBfreeused++; return 1 }
if (playerBcostused < playerBcost) { playerBcostused++; return 1 }
report( "PROTOCOL VIOLATION: sorry, no search left" )
return 0
}
}
function kosher(x,y,res) {
res = 1
if (x != int(x) || y != int(y)) res = 0
if (x < 1 || y < 1) res = 0
if (x > rows || y > cols) res = 0
if (!res) report( "PROTOCOL VIOLATION: no such row and column" )
return res
}
function printmenu() {
print "accept x y accept the proposal "
print "prop x y make (or repeat) a proposal"
print "unprop x y rescind a proposal"
print "search x y reveal more about a payoff"
print "sub x y n generate substitution for the nth card of a payoff"
print "whynot x y ask why not a proposal"
print "threaten . y threaten breakdown with column y (playerB only)"
print "threaten x . threaten breakdown with row x (playerA only)"
print "warnbreak warn that breakdown is imminent"
print "force . y unilaterally breakdown (playerB only)"
print "force x . unilaterally breakdown (playerA only)"
print "haveyou c ask for the resource, c"
print "idohave c confirm having c"
print "idonthave c deny having c"
print "offer x y c offer a resource, conditional on agreeing to "
print "otake x y c offer to take a resource, conditional on "
print "unoffer x y c retract an offered resource"
}
function init() {
rows = int(6*rand())+3
cols = int(3*rand())+3
maxplies = int(500*rand()+20.5)
system("clear")
print "\t\t\tA BETTER NEGOTIATION GAME"
print ""
print ""
print ""
if (playerAprog) { print "program for playerA is "playerAprog }
if (playerBprog) { print "program for playerB is "playerBprog }
print "rows " rows " (playerA controls under breakdown)"
print "cols " cols " (playerB controls under breakdown)"
playerAfree = int(10*rand())+1
playerAcost = int(10*rand())+1
playerAcount = int(20*rand())+1
playerAfreeused = 0; playerAcostused = 0
playerBfree = int(10*rand())+1
playerBcost = int(10*rand())+1
playerBcount = int(10*rand())+1
playerBfreeused = 0; playerBcostused = 0
# system("rm -f anne.dialogue")
# rewrite file from top, thus saving read/write permissions
print playerAprog " AND " playerBprog" ROUND "pairing > dialoguefile
print "rows",rows,"cols",cols,"a new game!" > dialoguefile
close(dialoguefile)
}
function deal(i,j,new) {
basic = "???"
for (i=1; i<=rows; i++) {
for (j=1; j<=cols; j++) {
playerA[i,j] = basic
playerB[i,j] = basic
}
}
augment(1,1)
augment(2,2)
augment(2,3)
augment(3,3)
augment(4,1)
playerAresources = " "
for (i=1; i<=playerAcount; i++) {
new = getcard()
if (!index(playerAresources," "new" ")) playerAresources = playerAresources new " "
resources["playerA",new] = 1
}
gsub("^ ","",playerAresources)
gsub(" $","",playerAresources)
playerBresources = " "
for (i=1; i<=playerBcount; i++) {
new = getcard()
if (!index(playerBresources," "new" ")) playerBresources = playerBresources new " "
resources["playerB",new] = 1
}
gsub("^ ","",playerBresources)
gsub(" $","",playerBresources)
}
function getcard(rank,color) {
if (rand() < .5) color = "r"
else color = "b"
rank = int(rand()*13)+1
return color rank
}
function augment(x,y, i,j) {
for (i=1; i<=x; i++) {
for (j=1; j<=y; j++) {
playerA[i,j] = playerA[i,j] "?"
playerB[rowrev(i),colrev(j)] = playerB[rowrev(i),colrev(j)] "?"
}
}
}
function rowrev(i) { return rows-i+1 }
function colrev(i) { return cols-i+1 }
function makesearch(x,y, i,result) {
result = ""
for (i=1; i<=x; i++) result = result "0"
for (i=1; i<=y; i++) result = result "1"
return result
}
function prhtml(x) {
print x > PATH "test.html"
}
function viewweb() {
if (whoseturn ~ /A/) prhtml("")
else prhtml("")
prhtml("EXPLANATION")
viewwebhow(whoseturn,0)
prhtml("
")
prhtml("A Better Negotiation Game, designed by R.P. Loui and A.H. Jump, Summer 1997.")
close(PATH "test.html")
}
function viewwebhow(whose,finalview, i,j,k,cards) {
prhtml("")
prhtml("")
if (!finalview) dolastmove(otherplayer(whose))
prhtml(" ")
}
function timestampthisform() {
"date" | getline date
close("date")
prhtml("
")
}
function dosearch(whose) {
if (whose == "playerA") {
prhtml("")
prhtml(makesearch(playerAfreeused,playerAcostused))
prhtml("")
prhtml(" ")
prhtml(makesearch(playerAfree-playerAfreeused,playerAcost-playerAcostused))
}
if (whose == "playerB") {
prhtml("")
prhtml(makesearch(playerBfreeused,playerBcostused))
prhtml("")
prhtml(" ")
prhtml(makesearch(playerBfree-playerBfreeused,playerBcost-playerBcostused))
}
}
function doresources(whose, temp,i) {
prhtml("")
if (whose == "playerA") split(playerAresources,temp," ")
if (whose == "playerB") split(playerBresources,temp," ")
for (i=1; i in temp; i++) {
if (substr(temp[i],1,1) == "b") prhtml("")
else prhtml("")
prhtml(substr(temp[i],2))
#prhtml("
")
#textbutton("offer w/",temp[i])
#prhtml("
")
#prhtml("")
#prhtml("
")
#prhtml("")
#prhtml("")
prhtml("
")
}
prhtml("
")
}
function makerowoptions( i,j) {
prhtml("