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 sp_limit = 10 # Bag out limit
48 delete sp_hands # [p] Each players cards
49 delete sp_players # [p] Player names players["name"] -> i
50 delete sp_order # [i] Player order order[i] -> "name"
51 delete sp_scores # [i] Teams score
55 function sp_acopy(dst, src, key)
59 json_copy(dst, key, src[key])
62 function sp_save(file, game)
65 game["suit"] = sp_suit;
66 game["piles"] = sp_piles;
67 json_copy(game, "pile", sp_pile);
70 game["state"] = sp_state;
71 game["broken"] = sp_broken;
72 json_copy(game, "looked", sp_looked);
73 json_copy(game, "bids", sp_bids);
74 json_copy(game, "nil", sp_nil);
75 json_copy(game, "pass", sp_pass);
76 json_copy(game, "tricks", sp_tricks);
79 game["channel"] = sp_channel;
80 game["owner"] = sp_owner;
81 game["playto"] = sp_playto;
82 game["dealer"] = sp_dealer;
83 game["turn"] = sp_turn;
84 game["player"] = sp_player;
85 game["limit"] = sp_limit;
86 json_copy(game, "hands", sp_hands);
87 json_copy(game, "players", sp_players);
88 json_copy(game, "order", sp_order);
89 json_copy(game, "scores", sp_scores);
92 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_limit = game["limit"];
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"]);
128 function sp_pretty(cards, who)
131 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
132 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
133 gsub(/s/, "\002♠", cards)
134 gsub(/h/, "\002♥", cards)
135 gsub(/d/, "\002♦", cards)
136 gsub(/c/, "\002♣", cards)
141 function sp_next(who, prev)
144 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
145 if (length(sp_order) == 4)
146 sp_player = sp_order[sp_turn]
150 function sp_deal( shuf)
152 say("/me deals the cards")
153 asorti(sp_deck, shuf, "sp_usort")
154 for (i=1; i<=52; i++)
155 sp_hands[sp_order[i%4]][shuf[i]] = 1
157 sp_dealer = (sp_dealer+1)%4
159 sp_player = sp_order[sp_turn]
160 say("Bidding starts with " sp_player "!")
163 function sp_hand(who, sort, str)
165 asorti(sp_hands[who], sort, "sp_csort")
166 for (i=0; i<length(sort); i++)
167 str = str "" sprintf("%4s", sort[i])
168 gsub(/^ +| +$/, "", str)
169 return sp_pretty(str, who)
172 function sp_hasa(who, expr)
174 for (c in sp_hands[who]) {
181 function sp_type(card)
183 return substr(card, length(card))
186 function sp_usort(a,b,c,d) {
190 function sp_csort(i1,v1,i2,v2) {
191 return sp_deck[i1] > sp_deck[i2] ? +1 :
192 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
195 function sp_winner( card, tmp)
197 for (card in sp_pile)
198 if (card !~ sp_suit && card !~ /s/)
200 asorti(sp_pile, tmp, "sp_csort")
201 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
207 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
208 return sp_order[i+0] "/" sp_order[i+2]
211 function sp_bags(i, bags)
213 bags = sp_scores[i] % sp_limit
219 function sp_bidders( i, turn, bid, bids)
221 for (i = 0; i < 4; i++) {
222 turn = (sp_dealer + i) % 4
223 if (sp_bids[turn] && !sp_nil[turn]) {
224 bid = sp_order[turn] ":" sp_bids[turn]
228 gsub(/^ +| +$/, "", bids)
232 function sp_score( bids, tricks)
234 for (i=0; i<2; i++) {
235 bids = sp_bids[i] + sp_bids[i+2]
236 tricks = sp_tricks[i] + sp_tricks[i+2]
238 if (sp_bags(i) + bags >= sp_limit) {
239 say(sp_team(i) " bag out")
240 sp_scores[i] -= sp_limit * 10
242 if (tricks >= bids) {
243 say(sp_team(i) " make their bid: " tricks "/" bids)
244 sp_scores[i] += bids*10 + bags;
246 say(sp_team(i) " go bust: " tricks "/" bids)
247 sp_scores[i] -= bids*10;
250 for (i=0; i<4; i++) {
253 say(sp_order[i] " " \
254 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
255 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
256 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
257 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
259 sp_scores[i%2] += 100 * sp_nil[i] * \
260 (sp_tricks[i] == 0 ? 1 : -1)
264 function sp_play(card, winner, pi)
266 delete sp_hands[FROM][card]
267 sp_pile[card] = sp_player
268 sp_piles = sp_piles (sp_piles?",":"") card
275 if (length(sp_pile) == 1)
276 sp_suit = sp_type(card)
279 if (length(sp_pile) == 4) {
281 pi = sp_players[sp_pile[winner]]
283 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
284 " (" sp_pretty(sp_piles, FROM) ")")
285 sp_next(sp_pile[winner])
290 if (sp_tricks[0] + sp_tricks[1] + \
291 sp_tricks[2] + sp_tricks[3] == 13) {
294 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
295 sp_scores[0] != sp_scores[1]) {
297 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
299 say(sp_team(winner) " wins the game " \
300 sp_scores[winner] " to " sp_scores[looser])
301 say(sp_order[winner+0] "++")
302 say(sp_order[winner+2] "++")
303 say(sp_order[looser+0] "--")
304 say(sp_order[looser+2] "--")
308 if (sp_scores[0] == sp_scores[1] &&
309 sp_scores[0] >= sp_playto)
310 say("It's tie! Playing an extra round!");
319 cmd = "od -An -N4 -td4 /dev/random"
325 sp_load("var/sp_cur.json");
327 say(sp_channel, "Game restored.")
331 sp_valid = (FROM && FROM == sp_player)
336 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
341 sp_save("var/sp_save.json");
347 sp_load("var/sp_save.json");
352 /^\.help [Ss]pades$/ {
353 say("Spades -- play a game of spades")
355 say(".newgame [score] -- start a game to <score> points, default 500")
356 say(".endgame -- abort the current game")
357 say(".savegame -- save the current game to disk")
358 say(".loadgame -- load the previously saved game")
359 say(".join -- join the current game")
360 say(".look -- look at your cards")
361 say(".bid n -- bid for <n> tricks")
362 say(".play [card] -- play a card")
363 say(".score -- check the score")
364 say(".tricks -- check how many trick have been taken")
365 say(".bids -- check what everyone bid")
371 /^\.deal (\w+) (.*)/ {
373 for (i=3; i<=NF; i++)
375 say(sp_channel, FROM " is cheating for " $2)
380 /^\.newgame ?([0-9]+)?/ {
381 if (sp_state != "new") {
382 reply("There is already a game in progress.")
385 sp_playto = $2 ? $2 : 200
386 sp_limit = sp_playto > 200 ? 10 : 5;
389 say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
390 #say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
394 (FROM == sp_owner || FROM == OWNER) &&
396 if (sp_state == "new") {
397 reply("There is no game in progress.")
399 say(FROM " ends the game")
405 if (sp_state == "new") {
406 reply("There is no game in progress")
408 else if (sp_state == "play") {
409 reply("The game has already started")
411 else if (sp_state == "join" && FROM in sp_players) {
412 reply("You are already playing")
414 else if (sp_state == "join") {
418 say(FROM " joins the game!")
420 if (sp_state == "join" && sp_turn == 0)
425 (sp_state "bid" || sp_state == "play") &&
427 if (FROM in sp_players)
428 say(".slap " FROM ", it is not your turn.")
430 say(".slap " FROM ", you are not playing.")
436 if ($2 < 0 || $2 > 13) {
437 say("You can only bid from 0 to 13")
441 if ($2 == 0 && !sp_looked[i]) {
442 say(FROM " goes blind nil!")
444 } else if ($2 == 0) {
445 say(FROM " goes nil!")
450 if (sp_turn != sp_dealer) {
451 say("Bidding goes to " sp_player "!")
453 for (p in sp_players)
454 say(p, "You have: " sp_hand(p))
456 for (i=0; i<2; i++) {
457 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
458 say(sp_team(i) ": select a card to pass " \
459 "(/msg " NICK " .pass <card>)")
463 if (sp_state == "play")
464 say("Play starts with " sp_player "!")
469 sp_state == "pass" &&
472 team = sp_players[FROM] % 2
473 if (!(FROM in sp_players)) {
474 say(".slap " FROM ", you are not playing.")
476 else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
477 reply("Your team did not go blind")
479 else if (sp_pass[sp_players[FROM]]) {
480 reply("You have already passed a card")
482 else if (!(card in sp_deck)) {
483 reply("Invalid card")
485 else if (!(card in sp_hands[FROM])) {
486 reply("You do not have that card")
489 sp_pass[sp_players[FROM]] = $2
490 say(sp_channel, FROM " passes a card")
492 if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
493 ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
497 delete sp_hands[sp_order[i]][card]
498 sp_hands[sp_order[partner]][card] = 1
500 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
501 for (p in sp_players)
502 say(p, "You have: " sp_hand(p))
507 sp_state ~ "(play|bid)" &&
509 if (!(FROM in sp_players)) {
510 say(".slap " FROM ", you are not playing.")
512 sp_looked[sp_players[FROM]] = 1
513 say(FROM, "You have: " sp_hand(FROM))
518 sp_state == "play" &&
521 if (!(card in sp_deck)) {
522 reply("Invalid card")
524 else if (!(card in sp_hands[FROM])) {
525 reply("You do not have that card")
527 else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
528 reply("You must follow suit (" sp_suit ")")
530 else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
531 reply("You cannot trump on the first hand")
533 else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
534 reply("Spades have not been broken")
538 if (sp_state == "play") {
539 if (length(sp_hands[FROM]))
540 say(FROM, "You have: " sp_hand(FROM))
542 say(sp_player ": it is your turn! " \
543 "(" sp_pretty(sp_piles, sp_player) ")")
545 say(sp_player ": it is your turn!")
550 /^\.bids$/ && sp_state == "play" {
551 say(sp_order[0] " bid " sp_bids[0] ", " \
552 sp_order[2] " bid " sp_bids[2] ", " \
553 "total: " sp_bids[0] + sp_bids[2])
554 say(sp_order[1] " bid " sp_bids[1] ", " \
555 sp_order[3] " bid " sp_bids[3] ", " \
556 "total: " sp_bids[1] + sp_bids[3])
559 /^\.tricks$/ && sp_state == "play" {
560 say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
561 sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
562 say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
563 sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
566 /^\.turn/ && sp_state ~ "(play|bid)" {
568 _pile = sp_pretty(sp_piles, FROM)
569 if (sp_state == "bid" && !_bids)
570 say("It is " sp_player "'s bid!")
571 if (sp_state == "bid" && _bids)
572 say("It is " sp_player "'s bid! (" _bids ")")
573 if (sp_state == "play" && !_pile)
574 say("It is " sp_player "'s turn!")
575 if (sp_state == "play" && _pile)
576 say("It is " sp_player "'s turn! (" _pile ")")
579 (TO == NICK || DST == sp_channel) &&
580 /^\.(score|status)$/ {
581 if (sp_state == "new") {
582 say("There is no game in progress")
584 if (sp_state == "join") {
585 say("Waiting for players: " \
586 sp_order[0] " " sp_order[1] " " \
587 sp_order[2] " " sp_order[3])
589 if (sp_state == "bid" || sp_state == "play") {
590 say(sp_team(0) ": " \
591 int(sp_scores[0]) " points, " \
592 int(sp_bags(0)) " bags")
593 say(sp_team(1) ": " \
594 int(sp_scores[1]) " points, " \
595 int(sp_bags(1)) " bags")
599 /^\.((new|end|load)game|join|look|bid|play)/ {
600 sp_save("var/sp_cur.json");
604 #/^\.playfor [^ ]*$/ {
607 #/^\.standin [^ ]*$/ {
608 # if (p in sp_players) {
610 # for (p in sp_standin) {
611 # if ($2 in sp_standin)
612 # say(here " is already playing for " sp_standin[p]);
614 # sp_standin[away] = here