The Third Dynasty of pokes: helper code
Jump to navigation
Jump to search
The schema of a sqlite database with gamestate information:
CREATE TABLE player (
name text primary key,
slush integer,
active integer,
integrity integer,
money integer
);
CREATE TABLE client (
name text primary key,
shortname text unique,
attorney text,
villainy integer,
worth integer,
type text
);
CREATE TABLE cases (
id integer,
open integer,
plaintiff text,
defendant text,
accusation text,
p_guilt integer,
d_guilt integer,
foreign key(plaintiff) references client(name),
foreign key(defendant) references client(name)
);
CREATE TABLE representation (
client text,
player text, active,
foreign key(client) references client(name),
foreign key(player) references player(name)
);
CREATE VIEW active_representation as select client, player from representation inner join player
where player.name = representation.player and player.active = 1 and representation.active = 1;
The final version of pokes-iii.lisp. "If either Party of the Case is represented by an Attorney who is already representing a Party in another Open Case, skip the rest of this atomic action" is not implemented; I did this step by hand.
(defpackage #:pokes-iii
(:use #:cl))
(in-package #:pokes-iii)
(defvar *crimes*
'("Arson" "Burglary" "Murder" "Perjury" "Jaywalking"))
(defvar *complaints*)
(setf *complaints*
'("Personal Injury" "Defamation" "Negligence" "Malpractice" "Probate" "Unpaid Debt"))
(defun prompt-gndt (options)
"Pick a random option from the GNDT. Substitutable for SECRETLY-RANDOM."
(loop :for opt :in options :do
(progn (princ opt) (princ " ")))
(princ "DICE") (princ (length options))
(terpri)
(princ ">>> ")
(- (read) 1))
(defun secretly-random (options)
"Pick a random option secretly. Substitutable for PROMPT-GNDT."
(format t "[random of: ~a] " options)
(let* ((n (length options))
(c (random n)))
(format t "~a/~a~%" c n)
c))
;;(random (length options)))
(defun is-business-p (db name)
"Check if NAME is a business, for the purposes of transforming complaint to unpaid debt."
(< 0 (sqlite:execute-single
db "select count(*) from client where name=? and type='business';" name)))
(defun verify-integrity (db)
"Find player/client pairs that have current representation and the player is mistrusted."
(let ((reps (sqlite:execute-to-list
db "select p.name, c.name, p.integrity, c.villainy from player as p inner join active_representation as r inner join client as c where r.player = p.name and r.client = c.name;"))
(ok t))
(loop :for r :in reps :do
(when (> 5 (+ (third r) (fourth r)))
(setf ok nil)
(format t "*** ~a mistrusts ~a~%" (second r) (first r))))
(if ok (format t "everything is okay~%"))))
(defun set-client-worth-by-name (db name worth)
(format t "*** update the worth of ~a: ~a~%" name worth)
(sqlite:execute-non-query
db "update client set worth=? where name=?;" worth name))
(defun get-client-worth-by-name (db name)
(sqlite:execute-single db "select worth from client where name=?;" name))
(defun increase-client-worth-by-name (db name inc)
(let* ((worth (get-client-worth-by-name db name))
(new-worth (+ worth inc)))
(format t "*** increasing the worth of ~a: ~a -> ~a~%" name worth new-worth)
(sqlite:execute-non-query
db "update client set worth=? where name=?;" new-worth name)))
(defun increase-player-money-loudly (db player inc)
(let* ((money (sqlite:execute-single db "select money from player where name=?;" player))
(new-money (max 0 (+ money inc))))
(format t "*** increase the public money of ~a: ~a -> ~a~%" player money new-money)
(sqlite:execute-non-query
db "update player set money=? where name=?;" new-money player)))
(defun increase-player-money-quietly (db player inc)
(let* ((slush (sqlite:execute-single db "select slush from player where name=?;" player))
(new-slush (+ slush inc)))
(format t "*** notify ~a of slush fund increase: ~a -> ~a~%" player slush new-slush)
(sqlite:execute-non-query
db "update player set slush=? where name=?;" new-slush player)))
(defun attorneys-of (db client)
"Get the (string) names of all players representing CLIENT."
(mapcar #'first
(sqlite:execute-to-list
db "select player from active_representation where client=?;" client)))
(defun is-represented-p (db client)
"Test if CLIENT has any representation."
(if (= 0 (length (attorneys-of db client))) nil t))
(defun is-represented-by-p (db client player)
"Test if CLIENT is represented by PLAYER."
(if (= 0 (sqlite:execute-single
db "select count(*) from active_representation where player=? and client=?;"
player client))
nil t))
(defun decrease-player-integrity-loudly (db player decrement)
(let* ((integrity (sqlite:execute-single db "select integrity from player where name=?;" player))
(new-integrity (max 0 (- integrity decrement))))
(format t "*** integrity of player ~a decreases: ~a -> ~a~%" player integrity new-integrity)
(sqlite:execute-non-query db "update player set integrity=? where name=?;" new-integrity player)))
(defun adjust-guilt-by-votes (db guilt party other-party
votes-for votes-against votes-veto)
(let ((adj-guilt guilt))
(loop :for vote :in votes-for :do
(when (is-represented-by-p db party vote)
(format t "adjusting guilt of ~a via FOR vote from ~a: ~a -> ~a~%" party vote
adj-guilt (- adj-guilt 2))
(increase-player-money-loudly db vote -2000)
(decf adj-guilt 2)))
(setf adj-guilt (max 0 adj-guilt))
(loop :for vote :in votes-against :do
(when (is-represented-by-p db other-party vote)
(format t "adjusting guilt of ~a via AGAINST vote from ~a: ~a -> ~a~%" party vote
adj-guilt (+ adj-guilt 1))
(decrease-player-integrity-loudly db vote 1)
(incf adj-guilt 1)))
(loop :for vote :in votes-veto :do
(when (is-represented-by-p db party vote)
(format t "adjusting guilt of ~a via VETO vote from ~a: ~a -> ~a~%" party vote
adj-guilt (+ adj-guilt 10))
(decrease-player-integrity-loudly db vote 2)
(incf adj-guilt 10)))
adj-guilt))
(defun check-spelling (db player)
(if (= 0 (sqlite:execute-single db "select count(*) from player where name=?;" player))
(error "player ~a wasn't found in the database" player)))
(defun check-all-spellings (db players)
(loop :for p :in players :do (check-spelling db p)))
(defun generate-case (db)
(sqlite:with-transaction db
(when (< 2 (sqlite:execute-single
db "select count(*) from cases where open=1;"))
(format t "aborting: 2 open cases already~%")
(return-from generate-case nil))
(let* ((clients
(sqlite:execute-to-list
db "select name, shortname, villainy, type from client;"))
;;(nclients (length clients))
(plaintiff-id
(secretly-random (mapcar #'second clients))) ;; formerly prompt-gndt
(plaintiff (nth plaintiff-id clients))
(defendants
(remove-if (lambda (c) (or (eq c plaintiff)
(equal (fourth c) "state"))) clients))
(defendant-id
(secretly-random (mapcar #'second defendants)))
(defendant (nth defendant-id defendants)))
(format t "preliminary: ~a v ~a~%" (first plaintiff) (first defendant))
(when (or (< 0 (length (intersection (attorneys-of db (first plaintiff))
(attorneys-of db (first defendant))
:test #'equal)))
(not (is-represented-p db (first plaintiff)))
(not (is-represented-p db (first defendant))))
(format t "aborting: no or bad representation~%")
(return-from generate-case nil))
(let* ((complaint
(if (equal (fourth plaintiff) "state")
(nth (prompt-gndt *crimes*) *crimes*)
(nth (prompt-gndt *complaints*) *complaints*)))
(plaintiff-guilt (random (1+ (* 2 (third plaintiff)))))
(defendant-guilt (random (1+ (* 2 (third defendant)))))
(case-id (progn (princ "case id>>> ") (read))))
(if (and (equal complaint "Probate")
(or (is-business-p db (first plaintiff)) (is-business-p db (first defendant))))
(setf complaint "Unpaid Debt"))
(if (= plaintiff-guilt defendant-guilt)
(if (= (random 2) 0) (incf plaintiff-guilt) (incf defendant-guilt)))
(format t "... plaintiff: ~a (guilt ~a) defendant: ~a (guilt ~a) complaint: ~a~%"
(first plaintiff) plaintiff-guilt
(first defendant) defendant-guilt
complaint)
(sqlite:execute-non-query
db "insert into cases values (?, 1, ?, ?, ?, ?, ?);"
case-id (first plaintiff) (first defendant) complaint
plaintiff-guilt defendant-guilt)
(loop :for rep :in (attorneys-of db (first plaintiff))
:do (format t "*** notify attorney ~a of plaintiff ~a guilt ~a~%"
rep (first plaintiff) plaintiff-guilt))
(loop :for rep :in (attorneys-of db (first defendant))
:do (format t "*** notify attorney ~a of defendant ~a guilt ~a~%"
rep (first defendant) defendant-guilt))
(list plaintiff defendant plaintiff-guilt defendant-guilt complaint)))))
(defun resolve-case (db case-id votes-for votes-against votes-veto)
(sqlite:with-transaction db
(check-all-spellings db votes-for)
(check-all-spellings db votes-against)
(check-all-spellings db votes-veto)
(multiple-value-bind
(plaintiff-name defendant-name p-guilt d-guilt)
(sqlite:execute-one-row-m-v
db "select plaintiff, defendant, p_guilt, d_guilt from cases where id=?" case-id)
(setf p-guilt (adjust-guilt-by-votes db p-guilt plaintiff-name defendant-name
votes-for votes-against votes-veto))
(setf d-guilt (adjust-guilt-by-votes db d-guilt defendant-name plaintiff-name
votes-for votes-against votes-veto))
(let* ((plaintiff-won (< p-guilt d-guilt))
(defendant-worth (get-client-worth-by-name db defendant-name))
(winner-name (if plaintiff-won plaintiff-name defendant-name))
(loser-name (if plaintiff-won defendant-name plaintiff-name))
(winner-attorneys
(mapcar #'first
(sqlite:execute-to-list
db "select player from active_representation where client=?;"
winner-name)))
(fee (if plaintiff-won (floor (* defendant-worth 0.3)) 0)))
(format t "the fine is: ~a~%" fee)
(increase-client-worth-by-name db winner-name (floor (* fee 0.9)))
(increase-client-worth-by-name db loser-name (- fee))
(loop :for player :in winner-attorneys :do
(let ((repped (< 0 (count-if (lambda (v) (equal v player)) votes-for))))
(if repped
(increase-player-money-loudly db player (floor (* fee 0.1)))
(increase-player-money-quietly db player (floor (* fee 0.1))))))
(sqlite:execute-non-query db "update cases set open=0 where id=?;" case-id)))))