Paula Cazali

Modelacion y Simulacion 1

Los numeros de las cartas se iran tomando desde \(2\) a \(14\). Donde \(14\) representa el valor mas alto de las cartas que en este caso seria el A.

library(plyr)
library(dplyr)

Se declaran los vectores con los numeros de cartas y un vector con los suits.

ranks_order_weight <- c('2'=2, '3'=3, '4'=4, '5'=5, '6'=6, '7'=7, '8'=8, '9'=9, 'T'=10, J=11, Q=12, K=13, A=14)
ranks <- names(ranks_order_weight)
ranks
 [1] "2" "3" "4" "5" "6" "7" "8" "9" "T" "J" "Q" "K" "A"
suit = c('E','C','T','D')
suit
[1] "E" "C" "T" "D"

Se define una funcion que genere el mazo completo de cartas. El proposito de esto es que no se generen dos cartas iguales de forma aleatoria.

newMazo <- function(ranks, suit){
  mazo <- c()
  for(rank in ranks){
    for(suitItem in suit){
      mazo <- c(mazo,paste(rank, suitItem, sep = "", collapse = NULL))
    }
  }
  return(mazo)
}

Generando el mazo de cartas:

mazo <- newMazo(ranks, suit)
mazo
 [1] "2E" "2C" "2T" "2D" "3E" "3C" "3T" "3D" "4E" "4C" "4T" "4D" "5E" "5C" "5T" "5D" "6E" "6C" "6T" "6D" "7E" "7C" "7T" "7D"
[25] "8E" "8C" "8T" "8D" "9E" "9C" "9T" "9D" "TE" "TC" "TT" "TD" "JE" "JC" "JT" "JD" "QE" "QC" "QT" "QD" "KE" "KC" "KT" "KD"
[49] "AE" "AC" "AT" "AD"

Funcion que genera cartas elegidas del mazo al azar.

#Funcion que genera una lista de n cantidad de cartas al azar
cardGenerator <- function(mazo, cantCards){
  listCards <- sample(mazo, cantCards, replace = FALSE)
  return(listCards)
}

Probando la funcion cardGenerator() para una mano de poker:

cards <- cardGenerator(mazo, 5)
cards
[1] "TD" "QC" "6C" "7D" "9C"

Esta funcion devuelve el valor de la carta: * pos = 1 se obtiene el rank de la carta * pos = 2 se obtiene el suit de la carta

getRankSuitCard <- function(hand, pos){
  h1 <- c()
  for(h in hand){
    h1 <- c(h1, substr(h, pos, pos))
  }
  return(h1)
}

Probando la funcion getRankSuitCard():

getRankSuitCard(cards, 1)
[1] "T" "Q" "6" "7" "9"
getRankSuitCard(cards, 2)
[1] "D" "C" "C" "D" "C"

Funcion que verifica si la mano de poker es Flush:

isFlush <- function(hand){
  suitValue <- getRankSuitCard(hand, 2)
  if(length(union(suitValue, suitValue)) == 1){
    return(TRUE)
  }
  return(FALSE)
}

Probando la funcion isFlush()

prueba <- c("4E","5E","2E","QE","AE")
isFlush(prueba)
[1] TRUE
prueba <- c("4C","4E","2E","QE","AE")

Funcion que genera una lista con la respectiva cantidad de repeticiones de elementos:

CounterF <- function(list){
  return(plyr::count(list))
}

Funcion que devuelve los valores de la cantidad de veces que se repite esa carta.

getCounterValue <- function(counter){
  return(counter$freq)
}

Devuelve el arreglo de las veces que se repite una determinada carta, con este ejemplo se puede ver que hay un par en prueba:

getCounterValue(CounterF(getRankSuitCard(prueba,1)))
[1] 1 2 1 1

La funcion typeHand() indica que tipo de jugada hay en la mano, no indica flush ni estalera.

typeHand <- function(hand){
  listCant <- CounterF(getRankSuitCard(hand, 1))
  counterHand <- CounterF(getCounterValue(listCant))
  if(counterHand[1,2] > 3){
    return("No hand")
  } else if(counterHand[1,2] > 2){
    return("Pair")
  } else if(counterHand[1,2] > 1){
    return("Three of a Kind")
  } else if(counterHand[2,2] == 2 & counterHand[1,2] == 1){
    return("Two Pairs")
  } else if(counterHand[2,1] == 4){
      return("Four of a Kind")
  }
  else{
    return( "Full House")
  }
}
prueba2 <- c("6D","9E","QD","6E","QT")
typeHand(prueba2)
[1] "Two Pairs"

Funcion que verifica si es escalera:

isStraight <- function(hand){
  rankValue <- getRankSuitCard(hand,1)
  valueCounts <- getCounterValue(CounterF(rankValue))
  weightsV <- c()
  for(i in rankValue){
    weightsV <- c(weightsV, ranks_order_weight[as.character(i)])
  }
  rangeValue <- max(weightsV) - min(weightsV)
  if(length(union(valueCounts, valueCounts)) == 1 & rangeValue == 4){
    return(TRUE)
  }else{
    return(FALSE)
  }
}

Prueba de la funcion isStraight():

prueba3 <- c("4E","6D","5T","3E","7T")
isStraight(prueba3)
[1] TRUE

Funcion que verifica la mano, que juego hay en la mano de poker.

gameHand <- function(hand){
  flushBoolean <- isFlush(hand)
  straightBoolean <- isStraight(hand)
  if(flushBoolean & straightBoolean){
    return("Straight Flush")
  }else if(flushBoolean){
    return("Flush")
  }else if(straightBoolean){
    return("Straight")
  } else{
    return(typeHand(hand))
  }
}

Probando la funcion cardGenerator()

carta_prueba <- cardGenerator(mazo, 5)
carta_prueba
[1] "9D" "6C" "7D" "6E" "9T"
gameHand(carta_prueba)
[1] "Two Pairs"

Se generaran \(50,000\) cartas de poker y se guardara en un dataframe que tipo de juego fue.

card <- cardGenerator(mazo,5)
print(c(card,gameHand(card)))
[1] "9T"   "2T"   "AD"   "QE"   "2D"   "Pair"
cards.df <- data.frame(juego = gameHand(card), stringsAsFactors = FALSE)
for(i in 1:50000){
  card <- cardGenerator(mazo,5)
  #print(c(card,gameHand(card)))
  juego <- gameHand(card)
  cards.df <- rbind(cards.df, juego, stringsAsFactors = FALSE)
}

Se contaran el total de juegos de cada tipo realizados.

cards.df2 <- cards.df
cards.df2 <- 
cards.df2 %>% 
  mutate(cant = 1)
total_juegos <-
cards.df2 %>% 
  group_by(juego) %>% 
  dplyr::summarise(count = n())
total_juegos

Ahora se van a obtener las probabilidades en base a las simulaciones realizadas:

total_juegos <-
  total_juegos %>% 
  mutate(probabilidad = count/50001)
total_juegos

Ahora se hara la simulacion con \(500,000\) manos de poker y se guardaran los juegos en un dataframe.

card2 <- cardGenerator(mazo,5)
print(c(card2,gameHand(card2)))
[1] "3C"      "9T"      "6C"      "7T"      "JC"      "No hand"
cards2.df <- data.frame(juego = gameHand(card2), stringsAsFactors = FALSE)
for(i in 1:500000){
  card2 <- cardGenerator(mazo,5)
  #print(c(card,gameHand(card)))
  juego <- gameHand(card2)
  cards2.df <- rbind(cards2.df, juego, stringsAsFactors = FALSE)
}

Se contaran el total de juegos de cada tipo realizados, ahora se hara con el dataset que tiene \(500000\) simulaciones.

cards2.df2 <- cards2.df
cards2.df2 <- 
cards2.df2 %>% 
  mutate(cant = 1)
total_juegos2 <-
cards2.df2 %>% 
  group_by(juego) %>% 
  dplyr::summarise(count = n())
total_juegos2

Ahora se van a obtener las probabilidades en base a las simulaciones realizadas:

total_juegos2 <-
  total_juegos2 %>% 
  mutate(probabilidad = count/500001)
total_juegos2
LS0tDQp0aXRsZTogIlBva2VyIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMgUGF1bGEgQ2F6YWxpDQojIyBNb2RlbGFjaW9uIHkgU2ltdWxhY2lvbiAxDQoNCg0KTG9zIG51bWVyb3MgZGUgbGFzIGNhcnRhcyBzZSBpcmFuIHRvbWFuZG8gZGVzZGUgJDIkIGEgJDE0JC4gRG9uZGUgJDE0JCByZXByZXNlbnRhIGVsIHZhbG9yIG1hcyBhbHRvIGRlIGxhcyBjYXJ0YXMgcXVlIGVuIGVzdGUgY2FzbyBzZXJpYSBlbCBBLg0KDQoqIEVzcGFkYXM6ICJFIg0KKiBDb3Jhem9uZXM6ICJDIg0KKiBUcmVib2xlczogIlQiDQoqIERpYW1hbnRlczogIkQiDQoNCmBgYHtyfQ0KbGlicmFyeShwbHlyKQ0KbGlicmFyeShkcGx5cikNCmBgYA0KDQoNClNlIGRlY2xhcmFuIGxvcyB2ZWN0b3JlcyBjb24gbG9zIG51bWVyb3MgZGUgY2FydGFzIHkgdW4gdmVjdG9yIGNvbiBsb3Mgc3VpdHMuDQpgYGB7cn0NCnJhbmtzX29yZGVyX3dlaWdodCA8LSBjKCcyJz0yLCAnMyc9MywgJzQnPTQsICc1Jz01LCAnNic9NiwgJzcnPTcsICc4Jz04LCAnOSc9OSwgJ1QnPTEwLCBKPTExLCBRPTEyLCBLPTEzLCBBPTE0KQ0KcmFua3MgPC0gbmFtZXMocmFua3Nfb3JkZXJfd2VpZ2h0KQ0KcmFua3MNCmBgYA0KDQpgYGB7cn0NCnN1aXQgPSBjKCdFJywnQycsJ1QnLCdEJykNCnN1aXQNCmBgYA0KDQoNClNlIGRlZmluZSB1bmEgZnVuY2lvbiBxdWUgZ2VuZXJlIGVsIG1hem8gY29tcGxldG8gZGUgY2FydGFzLiBFbCBwcm9wb3NpdG8gZGUgZXN0byBlcyBxdWUgbm8gc2UgZ2VuZXJlbiBkb3MgY2FydGFzIGlndWFsZXMgZGUgZm9ybWEgYWxlYXRvcmlhLg0KYGBge3J9DQpuZXdNYXpvIDwtIGZ1bmN0aW9uKHJhbmtzLCBzdWl0KXsNCiAgbWF6byA8LSBjKCkNCiAgZm9yKHJhbmsgaW4gcmFua3Mpew0KICAgIGZvcihzdWl0SXRlbSBpbiBzdWl0KXsNCiAgICAgIG1hem8gPC0gYyhtYXpvLHBhc3RlKHJhbmssIHN1aXRJdGVtLCBzZXAgPSAiIiwgY29sbGFwc2UgPSBOVUxMKSkNCiAgICB9DQogIH0NCiAgcmV0dXJuKG1hem8pDQp9DQpgYGANCg0KR2VuZXJhbmRvIGVsIG1hem8gZGUgY2FydGFzOg0KYGBge3J9DQptYXpvIDwtIG5ld01hem8ocmFua3MsIHN1aXQpDQptYXpvDQpgYGANCg0KRnVuY2lvbiBxdWUgZ2VuZXJhIGNhcnRhcyBlbGVnaWRhcyBkZWwgbWF6byBhbCBhemFyLg0KYGBge3J9DQojRnVuY2lvbiBxdWUgZ2VuZXJhIHVuYSBsaXN0YSBkZSBuIGNhbnRpZGFkIGRlIGNhcnRhcyBhbCBhemFyDQpjYXJkR2VuZXJhdG9yIDwtIGZ1bmN0aW9uKG1hem8sIGNhbnRDYXJkcyl7DQogIGxpc3RDYXJkcyA8LSBzYW1wbGUobWF6bywgY2FudENhcmRzLCByZXBsYWNlID0gRkFMU0UpDQogIHJldHVybihsaXN0Q2FyZHMpDQp9DQpgYGANCg0KUHJvYmFuZG8gbGEgZnVuY2lvbiBgY2FyZEdlbmVyYXRvcigpYCBwYXJhIHVuYSBtYW5vIGRlIHBva2VyOg0KYGBge3J9DQpjYXJkcyA8LSBjYXJkR2VuZXJhdG9yKG1hem8sIDUpDQpjYXJkcw0KYGBgDQoNCkVzdGEgZnVuY2lvbiBkZXZ1ZWx2ZSBlbCB2YWxvciBkZSBsYSBjYXJ0YToNCiogcG9zID0gMSBzZSBvYnRpZW5lIGVsIHJhbmsgZGUgbGEgY2FydGENCiogcG9zID0gMiBzZSBvYnRpZW5lIGVsIHN1aXQgZGUgbGEgY2FydGENCg0KYGBge3J9DQpnZXRSYW5rU3VpdENhcmQgPC0gZnVuY3Rpb24oaGFuZCwgcG9zKXsNCiAgaDEgPC0gYygpDQogIGZvcihoIGluIGhhbmQpew0KICAgIGgxIDwtIGMoaDEsIHN1YnN0cihoLCBwb3MsIHBvcykpDQogIH0NCiAgcmV0dXJuKGgxKQ0KfQ0KYGBgDQoNClByb2JhbmRvIGxhIGZ1bmNpb24gYGdldFJhbmtTdWl0Q2FyZCgpYDoNCmBgYHtyfQ0KZ2V0UmFua1N1aXRDYXJkKGNhcmRzLCAxKQ0KZ2V0UmFua1N1aXRDYXJkKGNhcmRzLCAyKQ0KYGBgDQoNCkZ1bmNpb24gcXVlIHZlcmlmaWNhIHNpIGxhIG1hbm8gZGUgcG9rZXIgZXMgRmx1c2g6DQpgYGB7cn0NCmlzRmx1c2ggPC0gZnVuY3Rpb24oaGFuZCl7DQogIHN1aXRWYWx1ZSA8LSBnZXRSYW5rU3VpdENhcmQoaGFuZCwgMikNCiAgaWYobGVuZ3RoKHVuaW9uKHN1aXRWYWx1ZSwgc3VpdFZhbHVlKSkgPT0gMSl7DQogICAgcmV0dXJuKFRSVUUpDQogIH0NCiAgcmV0dXJuKEZBTFNFKQ0KfQ0KYGBgDQoNClByb2JhbmRvIGxhIGZ1bmNpb24gYGlzRmx1c2goKWANCmBgYHtyfQ0KcHJ1ZWJhIDwtIGMoIjRFIiwiNUUiLCIyRSIsIlFFIiwiQUUiKQ0KaXNGbHVzaChwcnVlYmEpDQpgYGANCg0KYGBge3J9DQpwcnVlYmEgPC0gYygiNEMiLCI0RSIsIjJFIiwiUUUiLCJBRSIpDQpgYGANCg0KRnVuY2lvbiBxdWUgZ2VuZXJhIHVuYSBsaXN0YSBjb24gbGEgcmVzcGVjdGl2YSBjYW50aWRhZCBkZSByZXBldGljaW9uZXMgZGUgZWxlbWVudG9zOg0KYGBge3J9DQpDb3VudGVyRiA8LSBmdW5jdGlvbihsaXN0KXsNCiAgcmV0dXJuKHBseXI6OmNvdW50KGxpc3QpKQ0KfQ0KYGBgDQoNCkZ1bmNpb24gcXVlIGRldnVlbHZlIGxvcyB2YWxvcmVzIGRlIGxhIGNhbnRpZGFkIGRlIHZlY2VzIHF1ZSBzZSByZXBpdGUgZXNhIGNhcnRhLg0KYGBge3J9DQpnZXRDb3VudGVyVmFsdWUgPC0gZnVuY3Rpb24oY291bnRlcil7DQogIHJldHVybihjb3VudGVyJGZyZXEpDQp9DQpgYGANCg0KRGV2dWVsdmUgZWwgYXJyZWdsbyBkZSBsYXMgdmVjZXMgcXVlIHNlIHJlcGl0ZSB1bmEgZGV0ZXJtaW5hZGEgY2FydGEsIGNvbiBlc3RlIGVqZW1wbG8gc2UgcHVlZGUgdmVyIHF1ZSBoYXkgdW4gcGFyIGVuIGBwcnVlYmFgOg0KYGBge3J9DQpnZXRDb3VudGVyVmFsdWUoQ291bnRlckYoZ2V0UmFua1N1aXRDYXJkKHBydWViYSwxKSkpDQpgYGANCg0KTGEgZnVuY2lvbiBgdHlwZUhhbmQoKWAgaW5kaWNhIHF1ZSB0aXBvIGRlIGp1Z2FkYSBoYXkgZW4gbGEgbWFubywgbm8gaW5kaWNhIGZsdXNoIG5pIGVzdGFsZXJhLg0KYGBge3J9DQp0eXBlSGFuZCA8LSBmdW5jdGlvbihoYW5kKXsNCiAgbGlzdENhbnQgPC0gQ291bnRlckYoZ2V0UmFua1N1aXRDYXJkKGhhbmQsIDEpKQ0KICBjb3VudGVySGFuZCA8LSBDb3VudGVyRihnZXRDb3VudGVyVmFsdWUobGlzdENhbnQpKQ0KICBpZihjb3VudGVySGFuZFsxLDJdID4gMyl7DQogICAgcmV0dXJuKCJObyBoYW5kIikNCiAgfSBlbHNlIGlmKGNvdW50ZXJIYW5kWzEsMl0gPiAyKXsNCiAgICByZXR1cm4oIlBhaXIiKQ0KICB9IGVsc2UgaWYoY291bnRlckhhbmRbMSwyXSA+IDEpew0KICAgIHJldHVybigiVGhyZWUgb2YgYSBLaW5kIikNCiAgfSBlbHNlIGlmKGNvdW50ZXJIYW5kWzIsMl0gPT0gMiAmIGNvdW50ZXJIYW5kWzEsMl0gPT0gMSl7DQogICAgcmV0dXJuKCJUd28gUGFpcnMiKQ0KICB9IGVsc2UgaWYoY291bnRlckhhbmRbMiwxXSA9PSA0KXsNCiAgICAgIHJldHVybigiRm91ciBvZiBhIEtpbmQiKQ0KICB9DQogIGVsc2V7DQogICAgcmV0dXJuKCAiRnVsbCBIb3VzZSIpDQogIH0NCn0NCmBgYA0KDQpgYGB7cn0NCnBydWViYTIgPC0gYygiNkQiLCI5RSIsIlFEIiwiNkUiLCJRVCIpDQp0eXBlSGFuZChwcnVlYmEyKQ0KYGBgDQoNCkZ1bmNpb24gcXVlIHZlcmlmaWNhIHNpIGVzIGVzY2FsZXJhOg0KYGBge3J9DQppc1N0cmFpZ2h0IDwtIGZ1bmN0aW9uKGhhbmQpew0KICByYW5rVmFsdWUgPC0gZ2V0UmFua1N1aXRDYXJkKGhhbmQsMSkNCiAgdmFsdWVDb3VudHMgPC0gZ2V0Q291bnRlclZhbHVlKENvdW50ZXJGKHJhbmtWYWx1ZSkpDQogIHdlaWdodHNWIDwtIGMoKQ0KICBmb3IoaSBpbiByYW5rVmFsdWUpew0KICAgIHdlaWdodHNWIDwtIGMod2VpZ2h0c1YsIHJhbmtzX29yZGVyX3dlaWdodFthcy5jaGFyYWN0ZXIoaSldKQ0KICB9DQogIHJhbmdlVmFsdWUgPC0gbWF4KHdlaWdodHNWKSAtIG1pbih3ZWlnaHRzVikNCiAgaWYobGVuZ3RoKHVuaW9uKHZhbHVlQ291bnRzLCB2YWx1ZUNvdW50cykpID09IDEgJiByYW5nZVZhbHVlID09IDQpew0KICAgIHJldHVybihUUlVFKQ0KICB9ZWxzZXsNCiAgICByZXR1cm4oRkFMU0UpDQogIH0NCn0NCmBgYA0KDQpQcnVlYmEgZGUgbGEgZnVuY2lvbiBgaXNTdHJhaWdodCgpYDoNCmBgYHtyfQ0KcHJ1ZWJhMyA8LSBjKCI0RSIsIjZEIiwiNVQiLCIzRSIsIjdUIikNCmlzU3RyYWlnaHQocHJ1ZWJhMykNCmBgYA0KDQpGdW5jaW9uIHF1ZSB2ZXJpZmljYSBsYSBtYW5vLCBxdWUganVlZ28gaGF5IGVuIGxhIG1hbm8gZGUgcG9rZXIuDQpgYGB7cn0NCmdhbWVIYW5kIDwtIGZ1bmN0aW9uKGhhbmQpew0KICBmbHVzaEJvb2xlYW4gPC0gaXNGbHVzaChoYW5kKQ0KICBzdHJhaWdodEJvb2xlYW4gPC0gaXNTdHJhaWdodChoYW5kKQ0KICBpZihmbHVzaEJvb2xlYW4gJiBzdHJhaWdodEJvb2xlYW4pew0KICAgIHJldHVybigiU3RyYWlnaHQgRmx1c2giKQ0KICB9ZWxzZSBpZihmbHVzaEJvb2xlYW4pew0KICAgIHJldHVybigiRmx1c2giKQ0KICB9ZWxzZSBpZihzdHJhaWdodEJvb2xlYW4pew0KICAgIHJldHVybigiU3RyYWlnaHQiKQ0KICB9IGVsc2V7DQogICAgcmV0dXJuKHR5cGVIYW5kKGhhbmQpKQ0KICB9DQp9DQpgYGANClByb2JhbmRvIGxhIGZ1bmNpb24gYGNhcmRHZW5lcmF0b3IoKWANCmBgYHtyfQ0KY2FydGFfcHJ1ZWJhIDwtIGNhcmRHZW5lcmF0b3IobWF6bywgNSkNCmNhcnRhX3BydWViYQ0KZ2FtZUhhbmQoY2FydGFfcHJ1ZWJhKQ0KYGBgDQoNClNlIGdlbmVyYXJhbiAkNTAsMDAwJCBjYXJ0YXMgZGUgcG9rZXIgeSBzZSBndWFyZGFyYSBlbiB1biBkYXRhZnJhbWUgcXVlIHRpcG8gZGUganVlZ28gZnVlLg0KYGBge3J9DQpjYXJkIDwtIGNhcmRHZW5lcmF0b3IobWF6byw1KQ0KcHJpbnQoYyhjYXJkLGdhbWVIYW5kKGNhcmQpKSkNCmNhcmRzLmRmIDwtIGRhdGEuZnJhbWUoanVlZ28gPSBnYW1lSGFuZChjYXJkKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KZm9yKGkgaW4gMTo1MDAwMCl7DQogIGNhcmQgPC0gY2FyZEdlbmVyYXRvcihtYXpvLDUpDQogICNwcmludChjKGNhcmQsZ2FtZUhhbmQoY2FyZCkpKQ0KICBqdWVnbyA8LSBnYW1lSGFuZChjYXJkKQ0KICBjYXJkcy5kZiA8LSByYmluZChjYXJkcy5kZiwganVlZ28sIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCn0NCmBgYA0KDQpTZSBjb250YXJhbiBlbCB0b3RhbCBkZSBqdWVnb3MgZGUgY2FkYSB0aXBvIHJlYWxpemFkb3MuDQpgYGB7cn0NCmNhcmRzLmRmMiA8LSBjYXJkcy5kZg0KY2FyZHMuZGYyIDwtIA0KY2FyZHMuZGYyICU+JSANCiAgbXV0YXRlKGNhbnQgPSAxKQ0KdG90YWxfanVlZ29zIDwtDQpjYXJkcy5kZjIgJT4lIA0KICBncm91cF9ieShqdWVnbykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfanVlZ29zDQpgYGANCg0KQWhvcmEgc2UgdmFuIGEgb2J0ZW5lciBsYXMgcHJvYmFiaWxpZGFkZXMgZW4gYmFzZSBhIGxhcyBzaW11bGFjaW9uZXMgcmVhbGl6YWRhczoNCmBgYHtyfQ0KdG90YWxfanVlZ29zIDwtDQogIHRvdGFsX2p1ZWdvcyAlPiUgDQogIG11dGF0ZShwcm9iYWJpbGlkYWQgPSBjb3VudC81MDAwMSkNCnRvdGFsX2p1ZWdvcw0KYGBgDQoNCg0KQWhvcmEgc2UgaGFyYSBsYSBzaW11bGFjaW9uIGNvbiAkNTAwLDAwMCQgbWFub3MgZGUgcG9rZXIgeSBzZSBndWFyZGFyYW4gbG9zIGp1ZWdvcyBlbiB1biBkYXRhZnJhbWUuDQpgYGB7cn0NCmNhcmQyIDwtIGNhcmRHZW5lcmF0b3IobWF6byw1KQ0KcHJpbnQoYyhjYXJkMixnYW1lSGFuZChjYXJkMikpKQ0KY2FyZHMyLmRmIDwtIGRhdGEuZnJhbWUoanVlZ28gPSBnYW1lSGFuZChjYXJkMiksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCmZvcihpIGluIDE6NTAwMDAwKXsNCiAgY2FyZDIgPC0gY2FyZEdlbmVyYXRvcihtYXpvLDUpDQogICNwcmludChjKGNhcmQsZ2FtZUhhbmQoY2FyZCkpKQ0KICBqdWVnbyA8LSBnYW1lSGFuZChjYXJkMikNCiAgY2FyZHMyLmRmIDwtIHJiaW5kKGNhcmRzMi5kZiwganVlZ28sIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCn0NCmBgYA0KDQpTZSBjb250YXJhbiBlbCB0b3RhbCBkZSBqdWVnb3MgZGUgY2FkYSB0aXBvIHJlYWxpemFkb3MsIGFob3JhIHNlIGhhcmEgY29uIGVsIGRhdGFzZXQgcXVlIHRpZW5lICQ1MDAwMDAkIHNpbXVsYWNpb25lcy4NCmBgYHtyfQ0KY2FyZHMyLmRmMiA8LSBjYXJkczIuZGYNCmNhcmRzMi5kZjIgPC0gDQpjYXJkczIuZGYyICU+JSANCiAgbXV0YXRlKGNhbnQgPSAxKQ0KdG90YWxfanVlZ29zMiA8LQ0KY2FyZHMyLmRmMiAlPiUgDQogIGdyb3VwX2J5KGp1ZWdvKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoY291bnQgPSBuKCkpDQpgYGANCg0KYGBge3J9DQp0b3RhbF9qdWVnb3MyDQpgYGANCg0KQWhvcmEgc2UgdmFuIGEgb2J0ZW5lciBsYXMgcHJvYmFiaWxpZGFkZXMgZW4gYmFzZSBhIGxhcyBzaW11bGFjaW9uZXMgcmVhbGl6YWRhczoNCmBgYHtyfQ0KdG90YWxfanVlZ29zMiA8LQ0KICB0b3RhbF9qdWVnb3MyICU+JSANCiAgbXV0YXRlKHByb2JhYmlsaWRhZCA9IGNvdW50LzUwMDAwMSkNCnRvdGFsX2p1ZWdvczINCmBgYA0KDQo=