5 function sp_init(cards, tmp0, tmp1)
8 cards ="As Ks Qs Js 10s 9s 8s 7s 6s 5s 4s 3s 2s "\
9 "Ah Kh Qh Jh 10h 9h 8h 7h 6h 5h 4h 3h 2h "\
10 "Ac Kc Qc Jc 10c 9c 8c 7c 6c 5c 4c 3c 2c "\
11 "Ad Kd Qd Jd 10d 9d 8d 7d 6d 5d 4d 3d 2d"
13 for (i=1; i<=length(tmp0); i++)
17 function sp_reset(type)
21 sp_suit = "" # The lead suit {s,h,d,c}
22 sp_piles = "" # [x] Played cards this turn
23 delete sp_pile # [x] Played cards this turn
28 sp_state = "bid" # {new,join,bid,pass,play}
29 sp_broken = 0 # Whether spades are broken
30 delete sp_looked # [i] Whether a player has looked a their cards
31 delete sp_bids # [i] Each players bid
32 delete sp_nil # [i] Nil multiplier 0=regular, 1=nil, 2=blind
33 delete sp_pass # [i] Cards to pass
34 delete sp_tricks # [i] Tricks this round
39 sp_channel = "" # channel to play in
40 sp_state = "new" # {new,join,bid,play}
41 sp_owner = "" # Who started the game
42 sp_playto = 0 # Score the game will go to
43 sp_dealer =-1 # Who is dealing this round
44 sp_turn = 0 # Index of who's turn it is
45 sp_player = "" # Who's turn it is
46 sp_valid = 0 # Message sent from sp_player
47 delete sp_hands # [p] Each players cards
48 delete sp_players # [p] Player names players["name"] -> i
49 delete sp_order # [i] Player order order[i] -> "name"
50 delete sp_scores # [i] Teams score
54 function sp_acopy(dst, src, key)
58 json_copy(dst, key, src[key])
61 function sp_save(file, game)
64 game["suit"] = sp_suit;
65 game["piles"] = sp_piles;
66 json_copy(game, "pile", sp_pile);
69 game["state"] = sp_state;
70 game["broken"] = sp_broken;
71 json_copy(game, "looked", sp_looked);
72 json_copy(game, "bids", sp_bids);
73 json_copy(game, "nil", sp_nil);
74 json_copy(game, "pass", sp_pass);
75 json_copy(game, "tricks", sp_tricks);
78 game["channel"] = sp_channel;
79 game["owner"] = sp_owner;
80 game["playto"] = sp_playto;
81 game["dealer"] = sp_dealer;
82 game["turn"] = sp_turn;
83 game["player"] = sp_player;
84 game["valid"] = sp_valid;
85 json_copy(game, "hands", sp_hands);
86 json_copy(game, "players", sp_players);
87 json_copy(game, "order", sp_order);
88 json_copy(game, "scores", sp_scores);
91 json_save(file, game);
95 function sp_load(file, game)
98 json_load(file, game);
101 sp_suit = game["suit"];
102 sp_piles = game["piles"];
103 sp_acopy(sp_pile, game["pile"]);
106 sp_state = game["state"];
107 sp_broken = game["broken"];
108 sp_acopy(sp_looked, game["looked"]);
109 sp_acopy(sp_bids, game["bids"]);
110 sp_acopy(sp_nil, game["nil"]);
111 sp_acopy(sp_pass, game["pass"]);
112 sp_acopy(sp_tricks, game["tricks"]);
115 sp_channel = game["channel"];
116 sp_owner = game["owner"];
117 sp_playto = game["playto"];
118 sp_dealer = game["dealer"];
119 sp_turn = game["turn"];
120 sp_player = game["player"];
121 sp_valid = game["valid"];
122 sp_acopy(sp_hands, game["hands"]);
123 sp_acopy(sp_players, game["players"]);
124 sp_acopy(sp_order, game["order"]);
125 sp_acopy(sp_scores, game["scores"]);
129 function sp_pretty(cards, who)
132 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
133 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
134 gsub(/s/, "\002♠", cards)
135 gsub(/h/, "\002♥", cards)
136 gsub(/d/, "\002♦", cards)
137 gsub(/c/, "\002♣", cards)
142 function sp_next(who, prev)
145 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
146 if (length(sp_order) == 4)
147 sp_player = sp_order[sp_turn]
151 function sp_deal( shuf)
153 say("/me deals the cards")
154 asorti(sp_deck, shuf, "sp_usort")
155 for (i=1; i<=52; i++)
156 sp_hands[sp_order[i%4]][shuf[i]] = 1
158 sp_dealer = (sp_dealer+1)%4
160 sp_player = sp_order[sp_turn]
161 say("Bidding starts with " sp_player "!")
164 function sp_hand(who, sort, str)
166 asorti(sp_hands[who], sort, "sp_csort")
167 for (i=0; i<length(sort); i++)
168 str = str "" sprintf("%4s", sort[i])
169 gsub(/^ +| +$/, "", str)
170 return sp_pretty(str, who)
173 function sp_hasa(who, expr)
175 for (c in sp_hands[who]) {
182 function sp_type(card)
184 return substr(card, length(card))
187 function sp_usort(a,b,c,d) {
191 function sp_csort(i1,v1,i2,v2) {
192 return sp_deck[i1] > sp_deck[i2] ? +1 :
193 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
196 function sp_winner( card, tmp)
198 for (card in sp_pile)
199 if (card !~ sp_suit && card !~ /s/)
201 asorti(sp_pile, tmp, "sp_csort")
202 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
208 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
209 return sp_order[i+0] "/" sp_order[i+2]
212 function sp_bags(i, bags)
214 bags = sp_scores[i] % 10
220 function sp_score( bids, tricks)
222 for (i=0; i<2; i++) {
223 bids = sp_bids[i] + sp_bids[i+2]
224 tricks = sp_tricks[i] + sp_tricks[i+2]
226 if (sp_bags(i) + bags >= 10) {
227 say(sp_team(i) " bag out")
230 if (tricks >= bids) {
231 say(sp_team(i) " make their bid: " tricks "/" bids)
232 sp_scores[i] += bids*10 + bags;
234 say(sp_team(i) " go bust: " tricks "/" bids)
235 sp_scores[i] -= bids*10;
238 for (i=0; i<4; i++) {
241 say(sp_order[i] " " \
242 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
243 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
244 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
245 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
247 sp_scores[i%2] += 100 * sp_nil[i] * \
248 (sp_tricks[i] == 0 ? 1 : -1)
252 function sp_play(card, winner, pi)
254 delete sp_hands[FROM][card]
255 sp_pile[card] = sp_player
256 sp_piles = sp_piles (sp_piles?",":"") card
263 if (length(sp_pile) == 1)
264 sp_suit = sp_type(card)
267 if (length(sp_pile) == 4) {
269 pi = sp_players[sp_pile[winner]]
271 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
272 " (" sp_pretty(sp_piles, FROM) ")")
273 sp_next(sp_pile[winner])
278 if (sp_tricks[0] + sp_tricks[1] + \
279 sp_tricks[2] + sp_tricks[3] == 13) {
282 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
283 sp_scores[0] != sp_scores[1]) {
285 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
287 say(sp_team(winner) " wins the game " \
288 sp_scores[winner] " to " sp_scores[looser])
289 say(sp_order[winner+0] "++")
290 say(sp_order[winner+2] "++")
291 say(sp_order[looser+0] "--")
292 say(sp_order[looser+2] "--")
296 if (sp_scores[0] == sp_scores[1] &&
297 sp_scores[0] >= sp_playto)
298 say("It's tie! Playing an extra round!");
307 cmd = "od -An -N4 -td4 /dev/random"
316 sp_valid = (FROM && FROM == sp_player)
321 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
326 sp_save("var/spades.json");
331 sp_load("var/spades.json");
335 /^\.help [Ss]pades$/ {
336 say("Spades -- play a game of spades")
338 say(".newgame [score] -- start a game to <score> points, default 500")
339 say(".endgame -- abort the current game")
340 say(".savegame -- save the current game to disk")
341 say(".loadgame -- load the previously saved game")
342 say(".join -- join the current game")
343 say(".look -- look at your cards")
344 say(".bid n -- bid for <n> tricks")
345 say(".play [card] -- play a card")
346 say(".score -- check the score")
347 say(".tricks -- check how many trick have been taken")
348 say(".bids -- check what everyone bid")
354 /^\.deal (\w+) (.*)/ {
356 for (i=3; i<=NF; i++)
358 say(sp_channel, FROM " is cheating for " $2)
363 /^\.newgame ?([0-9]+)?/ {
364 if (sp_state != "new") {
365 reply("There is already a game in progress.")
368 sp_playto = $2 ? $2 : 200
371 say(sp_owner " starts a game of Spades to " sp_playto "!")
372 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
376 (FROM == sp_owner || FROM == OWNER) &&
378 if (sp_state == "new") {
379 reply("There is no game in progress.")
381 say(FROM " ends the game")
387 if (sp_state == "new") {
388 reply("There is no game in progress")
390 else if (sp_state == "play") {
391 reply("The game has already started")
393 else if (sp_state == "join" && FROM in sp_players) {
394 reply("You are already playing")
396 else if (sp_state == "join") {
400 say(FROM " joins the game!")
402 if (sp_state == "join" && sp_turn == 0)
407 (sp_state "bid" || sp_state == "play") &&
409 if (FROM in sp_players)
410 say(".slap " FROM ", it is not your turn.")
412 say(".slap " FROM ", you are not playing.")
418 if ($2 < 0 || $2 > 13) {
419 say("You can only bid from 0 to 13")
423 if ($2 == 0 && !sp_looked[i]) {
424 say(FROM " goes blind nil!")
426 } else if ($2 == 0) {
427 say(FROM " goes nil!")
432 if (sp_turn != sp_dealer) {
433 say("Bidding goes to " sp_player "!")
435 for (p in sp_players)
436 say(p, "You have: " sp_hand(p))
438 for (i=0; i<2; i++) {
439 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
440 say(sp_team(i) ": select a card to pass " \
441 "(/msg " NICK " .pass <card>)")
445 if (sp_state == "play")
446 say("Play starts with " sp_player "!")
451 sp_state == "pass" &&
454 team = sp_players[FROM] % 2
455 if (!(FROM in sp_players)) {
456 say(".slap " FROM ", you are not playing.")
458 else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
459 reply("Your team did not go blind")
461 else if (sp_pass[sp_players[FROM]]) {
462 reply("You have already passed a card")
464 else if (!(card in sp_deck)) {
465 reply("Invalid card")
467 else if (!(card in sp_hands[FROM])) {
468 reply("You do not have that card")
471 sp_pass[sp_players[FROM]] = $2
472 say(sp_channel, FROM " passes a card")
474 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
475 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
479 delete sp_hands[sp_order[i]][card]
480 sp_hands[sp_order[partner]][card] = 1
482 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
483 for (p in sp_players)
484 say(p, "You have: " sp_hand(p))
489 sp_state ~ "(play|bid)" &&
491 if (!(FROM in sp_players)) {
492 say(".slap " FROM ", you are not playing.")
494 sp_looked[sp_players[FROM]] = 1
495 say(FROM, "You have: " sp_hand(FROM))
500 sp_state == "play" &&
503 if (!(card in sp_deck)) {
504 reply("Invalid card")
506 else if (!(card in sp_hands[FROM])) {
507 reply("You do not have that card")
509 else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
510 reply("You must follow suit (" sp_suit ")")
512 else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
513 reply("You cannot trump on the first hand")
515 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
516 reply("Spades have not been broken")
520 if (sp_state == "play") {
521 if (length(sp_hands[FROM]))
522 say(FROM, "You have: " sp_hand(FROM))
524 say(sp_player ": it is your turn! " \
525 "(" sp_pretty(sp_piles, sp_player) ")")
527 say(sp_player ": it is your turn!")
532 /^\.bids$/ && sp_state == "play" {
533 say(sp_order[0] " bid " sp_bids[0] ", " \
534 sp_order[2] " bid " sp_bids[2] ", " \
535 "total: " sp_bids[0] + sp_bids[2])
536 say(sp_order[1] " bid " sp_bids[1] ", " \
537 sp_order[3] " bid " sp_bids[3] ", " \
538 "total: " sp_bids[1] + sp_bids[3])
541 /^\.tricks$/ && sp_state == "play" {
542 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
543 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
544 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
545 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
548 (TO == NICK || DST == sp_channel) &&
549 /^\.(score|status)$/ {
550 if (sp_state == "new") {
551 say("There is no game in progress")
553 if (sp_state == "join") {
554 say("Waiting for players: " \
555 sp_order[0] " " sp_order[1] " " \
556 sp_order[2] " " sp_order[3])
558 if (sp_state == "bid" || sp_state == "play") {
559 say(sp_team(0) ": " \
560 int(sp_scores[0]) " points, " \
561 int(sp_bags(0)) " bags")
562 say(sp_team(1) ": " \
563 int(sp_scores[1]) " points, " \
564 int(sp_bags(1)) " bags")
569 #/^\.playfor [^ ]*$/ {
572 #/^\.standin [^ ]*$/ {
573 # if (p in sp_players) {
575 # for (p in sp_standin) {
576 # if ($2 in sp_standin)
577 # say(here " is already playing for " sp_standin[p]);
579 # sp_standin[away] = here