Author Topic: DS blackjack bot  (Read 3287 times)

Offline toninno

  • Acquaintance
  • *
  • Posts: 16
    • View Profile
DS blackjack bot
« on: March 24, 2010, 10:53:43 AM »
Hello, this blackjack bot is based on charles/charlie of DS (/domains/campus/npc/charles.c). But unfortunately the blackjack table is a little bit buggy, so they doesn't interact well, but I believe it will interact well with a bug free black jack table. So, here's the code:
Code: [Select]
#include <lib.h>
#include <save.h>
#include <privs.h>

inherit LIB_NPC;

static object ww;
static string printvar,vv,mm;
static int playing;
int runs=0;
int minWager=1;
int nextWager=minWager;
int wins=0,losses=0;
static string SaveFile = save_file("/domains/town/save/bjbot");
static int *myCards;

string GetSaveFile(){
    return SaveFile;
}

static string SetSaveFile(string str){
    return (SaveFile = str);
}

void myIssueCommand(string cmd)
 {
  debug("cmd: "+cmd);
  eventForce(cmd);
 }

static void create() {
    npc::create();
    SetKeyName("black jack bot");
    SetId(({"bot"}));
    SetShort("Black jack bot");
    SetLong("This is a real BJTech branded smart black jack bot. "
            "Plays in real money. Adorable workpiece.");
    SetLevel(5);
    SetRace("human");
    SetGender("male");
    SetNoClean(1);
    if(sizeof(SaveFile)) RestoreObject(SaveFile);
    if(GetCurrency("silver")<1024) AddCurrency("silver",1024-GetCurrency("silver"));
    playing = 0;
    SetAutoStand(1);
    SetPacifist(1);
}

int eventBeginPlay(){
    int run;
    SaveObject(SaveFile,1);
    if(!clonep()) return 0;
    run = runs+1;
    playing = 1;
    if(nextWager==minWager)
     myIssueCommand("say I won, now I have "+GetCurrency("silver")+" silver coins.");
    myIssueCommand("say If successful, this will be run "+run+".");
    myCards=({});
    //debug("myCardsSize="+sizeof(myCards));
    myIssueCommand("deal "+nextWager);
    //debug("myCardsSize="+sizeof(myCards));

    return 1;
}

int eventDecide(int pt,int a)
 {
  int prb;
  //those numbers are experimental:
  mixed *prbs=
   ({ //   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20   21
      ({  -1,  -1,  -1,  -1, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,  10,   0,   0,   0,   0,   0,   0 }),
      ({  -1,  -1, 100, 100, 100, 100,  40,   9,   7,   5,   0,   0, 100, 100,  30,  15,   0,   0,   0,   0,   0,   0 })
   });
   
  if(pt>21) return 0;
  if(pt<0) return 0;

  prb=prbs[a][pt];
  if(prb<0) return 0;
 
  if((prb>0)&&((prb==100)||(random(100)<prb)))
    {
     myIssueCommand("hit");
    }
   else
    {
     if((pt<21)&&((pt!=11)||(a!=1))) call_out((: myIssueCommand("stand pat") :),1);
    }
  return 1;
 }

int eventReceiveCard(string str)
 {
  int val,pt,a,cc;
  string sdebug="";
  //debug("Card: +++"+str+"+++");
  if(!str || str == "") return 0;
  val=member_array(str,({"ace","2","3","4","5","6","7","8","9","10","jack","queen","king"}));
  if(val<0) return 0;
  ++val;
  if(val>10) val=10;
  myCards=myCards+({ val });
  debug("val="+val);
  //debug("myCardsSize="+sizeof(myCards));
  pt=0;
  a=0;
  cc=0;
  foreach(int c in myCards)
   {
    sdebug+=c+" ";
    ++cc;
    pt+=c;
    if(c==1) a=1;
   }
  debug("my cards: "+sdebug+"("+pt+","+a+")");
  if(cc>1) eventDecide(pt,a);
  return 1;
 }

void playFinished()
 {
  playing=0;
  ++runs;
 }

void eventWin()
 {
  nextWager=minWager;
  ++wins;
  playFinished();
 }

void eventLose()
 {
  nextWager*=2;
  ++losses;
  playFinished();
 }

int eventFirstPass(string str){
    string s1;
    debug(str);
    if(!str || str == "") return 0;
    if(sscanf(str,"%*sYou get a %s %*s",s1) > 0){
        //debug(str);
        eventReceiveCard(lower_case(s1));
        return 0;
    }
    if(sscanf(str,"%*sYou %s",s1) > 0)
    {
     str=s1;
     if(sscanf(s1,"win!%*s") > 0)
      {
       eventWin();
       return 0;
      }
     if(sscanf(s1,"lose%*s") > 0)
      {
       eventLose();
       return 0;
      }
     if((sscanf(s1,"don't have that many silver!%*s") > 0)&&(nextWager>1))
      {
       nextWager=1;
       myIssueCommand("deal 1");
      }
     debug(str);
     return 0;
    }
    debug(str);
    return 0;
}

private void eventPrint(string str1, string str2);
void init(){
    ::init();
    set_heart_beat(5);
    SetNoClean(1);
}

void receive_message(mixed x, string string2){
    eventFirstPass(string2);
}

varargs mixed eventHearTalk(object who, object target, int cls, string verb,
        string msg, string lang) {
    ww=who;
    vv=verb;
    mm=msg;
    unguarded((: this_object()->receive_message("me",ww->GetName()+" "+vv+"s: "+mm) :));
    return;
}
int eventPrint(string msg, string msg_class){
    printvar=msg;
    unguarded((: this_object()->receive_message("me again",printvar) :));
}

void heart_beat(){
    if(!environment() || !clonep()){
        set_heart_beat(0);
        return;
    }
    if(!playing){
        eventBeginPlay();
    }
}

Offline Atomic

  • BFF
  • ***
  • Posts: 115
  • To infinity and beyond!
    • View Profile
Re: DS blackjack bot
« Reply #1 on: March 31, 2010, 04:45:58 AM »
Appreciated!  8)
Always remember that the early bird gets the worm first, but the fi...*SNAP*...second mouse gets the cheese.

Offline toninno

  • Acquaintance
  • *
  • Posts: 16
    • View Profile
Re: DS blackjack bot
« Reply #2 on: March 17, 2013, 09:22:39 AM »
This patch against /domains/town/obj/btable.c (ds3.6) makes my bot run, but I suspect that the score computation in the blackjack table is flawed in corner cases:

Code: [Select]
--- btable.c.orig 2013-03-17 12:18:37.904474320 +0100
+++ btable.c 2013-03-16 18:57:05.000000000 +0100
@@ -168,7 +168,14 @@
     player=this_player();
     playername=player->GetName();
     here=environment(this_object());
-    if(oldplayer) plidle=query_idle(oldplayer);
+    if(oldplayer)
+    {
+      //to make the table interact well with non-interactive ... players:
+      if(interactive(oldplayer))
+        plidle=query_idle(oldplayer);//this one would fail if the player isn't interactive
+      else
+        plidle=2;
+    }
 
     if (!args) {
         write("%^YELLOW%^Please try that again, including the amount of money you want to wager.");

Offline toninno

  • Acquaintance
  • *
  • Posts: 16
    • View Profile
Re: DS blackjack bot
« Reply #3 on: March 22, 2013, 09:46:29 PM »
Here's the recent changes, the only relevant chunk is at the bottom:

Code: [Select]
--- bjbot.c.orig 2013-03-23 00:31:06.492734512 +0100
+++ bjbot.c 2013-03-23 00:37:10.878333307 +0100
@@ -2,7 +2,8 @@
 #include <save.h>
 #include <privs.h>
 
-inherit LIB_NPC;
+//In order to make him capable of replying:
+inherit LIB_SENTIENT;
 
 static object ww;
 static string printvar,vv,mm;
@@ -28,8 +29,23 @@
   eventForce(cmd);
  }
 
+int donateWinnings(object who, mixed foo, string message, mixed bar)
+{
+  int myCash=GetCurrency("silver");
+  if(myCash<=65536)
+    eventForce("say Sorry, I can't afford to give you any amount of money right now.");
+  else
+  {
+    myCash-=65536;
+    eventForce("say I can spare "+myCash+" silver coins for you.");
+    eventForce("give "+myCash+" silvers to "+who->GetName());
+  }
+
+  return 1;
+}
+
 static void create() {
-    npc::create();
+    sentient::create();
     SetKeyName("black jack bot");
     SetId(({"bot"}));
     SetShort("Black jack bot");
@@ -40,21 +56,35 @@
     SetGender("male");
     SetNoClean(1);
     if(sizeof(SaveFile)) RestoreObject(SaveFile);
+    //make sure he'll be able to carry a considerable amount of money:
+    SetStat("strength",4000);
     if(GetCurrency("silver")<1024) AddCurrency("silver",1024-GetCurrency("silver"));
     playing = 0;
     SetAutoStand(1);
     SetPacifist(1);
+    SetLanguage("common",100);
+    SetTalkResponses( ([
+                         ({"lose","losing","afraid" }) : "Yeah, it's possible I'll lose all my money, but I'm designed to take te risk.",
+                         ({"give me money","give me some money","giving me money","giving me some money", "please" }) : (: donateWinnings :),
+                      ]) );
 }
 
 int eventBeginPlay(){
     int run;
+    string blah;
     SaveObject(SaveFile,1);
     if(!clonep()) return 0;
     run = runs+1;
     playing = 1;
-    if(nextWager==minWager)
-     myIssueCommand("say I won, now I have "+GetCurrency("silver")+" silver coins.");
-    myIssueCommand("say If successful, this will be run "+run+".");
+    if(run>1)
+    {
+      if(nextWager==minWager)
+        blah="I won, now I have "+GetCurrency("silver")+" silver coins. ";
+      else
+        blah="I've lost, I'll wager "+nextWager+" silver coins next time. ";
+    }
+    else blah="";
+    myIssueCommand("say "+blah+"If successful, this will be run "+run+".");
     myCards=({});
     //debug("myCardsSize="+sizeof(myCards));
     myIssueCommand("deal "+nextWager);
@@ -183,6 +213,8 @@
     eventFirstPass(string2);
 }
 
+#if 0
+interferes with eventHearTalk, and my bot works just fine without this func, so let's remove it:
 varargs mixed eventHearTalk(object who, object target, int cls, string verb,
         string msg, string lang) {
     ww=who;
@@ -191,6 +223,8 @@
     unguarded((: this_object()->receive_message("me",ww->GetName()+" "+vv+"s: "+mm) :));
     return;
 }
+#endif
+
 int eventPrint(string msg, string msg_class){
     printvar=msg;
     unguarded((: this_object()->receive_message("me again",printvar) :));
@@ -204,4 +238,19 @@
     if(!playing){
         eventBeginPlay();
     }
+    //The only relevant change is this, circumvents black jack table bugs:
+    else
+    {
+      ++playing;
+      if(playing>60)
+      {
+        myIssueCommand("stand pat");
+      }
+      if(playing>120)
+      {
+        //I've never seen the code to reach this branch:
+        myIssueCommand("say seems like we're terribly stuck, entering standby mode");
+        set_heart_beat(0);
+      }
+    }
 }