valtech-components 4.0.424 → 4.0.425

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -58,7 +58,7 @@ import fixWebmDuration from 'fix-webm-duration';
58
58
  * Current version of valtech-components.
59
59
  * This is automatically updated during the publish process.
60
60
  */
61
- const VERSION = '4.0.424';
61
+ const VERSION = '4.0.425';
62
62
 
63
63
  // Control de estado de refresco (singleton a nivel de módulo)
64
64
  let isRefreshing = false;
@@ -61029,18 +61029,66 @@ const CHESSIMALS_BOT_PROFILES = [
61029
61029
  labelKey: 'chessimalsBotSentinel',
61030
61030
  descriptionKey: 'chessimalsBotSentinelBody',
61031
61031
  },
61032
+ {
61033
+ id: 'oracle',
61034
+ difficulty: 'hard',
61035
+ avatar: '🔮',
61036
+ labelKey: 'chessimalsBotOracle',
61037
+ descriptionKey: 'chessimalsBotOracleBody',
61038
+ },
61039
+ {
61040
+ id: 'ambusher',
61041
+ difficulty: 'hard',
61042
+ avatar: '🪤',
61043
+ labelKey: 'chessimalsBotAmbusher',
61044
+ descriptionKey: 'chessimalsBotAmbusherBody',
61045
+ },
61046
+ {
61047
+ id: 'locksmith',
61048
+ difficulty: 'hard',
61049
+ avatar: '🔐',
61050
+ labelKey: 'chessimalsBotLocksmith',
61051
+ descriptionKey: 'chessimalsBotLocksmithBody',
61052
+ },
61053
+ {
61054
+ id: 'storm',
61055
+ difficulty: 'hard',
61056
+ avatar: '🌩️',
61057
+ labelKey: 'chessimalsBotStorm',
61058
+ descriptionKey: 'chessimalsBotStormBody',
61059
+ },
61060
+ {
61061
+ id: 'matriarch',
61062
+ difficulty: 'hard',
61063
+ avatar: '👑',
61064
+ labelKey: 'chessimalsBotMatriarch',
61065
+ descriptionKey: 'chessimalsBotMatriarchBody',
61066
+ },
61067
+ {
61068
+ id: 'endgame',
61069
+ difficulty: 'hard',
61070
+ avatar: '⌛',
61071
+ labelKey: 'chessimalsBotEndgame',
61072
+ descriptionKey: 'chessimalsBotEndgameBody',
61073
+ },
61032
61074
  ];
61033
61075
  const BOT_STYLES = {
61034
- explorer: { advancement: 1.05, capture: 0.82, safety: 0.62, power: 0.8, center: 1.15, unlock: 1.05, reply: 0.7, randomness: 260, spread: 0.68 },
61035
- impulsive: { advancement: 0.9, capture: 1.45, safety: 0.48, power: 1.15, center: 0.8, unlock: 0.9, reply: 0.55, randomness: 290, spread: 0.62 },
61036
- runner: { advancement: 1.55, capture: 0.78, safety: 0.5, power: 0.95, center: 0.7, unlock: 1.1, reply: 0.55, randomness: 250, spread: 0.6 },
61037
- hunter: { advancement: 0.95, capture: 1.45, safety: 0.9, power: 1.05, center: 0.95, unlock: 0.95, reply: 1, randomness: 90, spread: 0.3 },
61038
- guardian: { advancement: 0.88, capture: 1, safety: 1.45, power: 0.85, center: 1.05, unlock: 1, reply: 1.15, randomness: 70, spread: 0.26 },
61039
- jumper: { advancement: 1.12, capture: 1, safety: 0.92, power: 1.42, center: 1.18, unlock: 1.08, reply: 0.95, randomness: 95, spread: 0.32 },
61040
- strategist: { advancement: 1.05, capture: 1.08, safety: 1.22, power: 1.08, center: 1.16, unlock: 1.1, reply: 1.25, randomness: 22, spread: 0.14 },
61041
- predator: { advancement: 0.98, capture: 1.68, safety: 1.02, power: 1.34, center: 1, unlock: 1, reply: 1.12, randomness: 28, spread: 0.16 },
61042
- sprinter: { advancement: 1.72, capture: 0.9, safety: 0.95, power: 1.08, center: 0.86, unlock: 1.18, reply: 1, randomness: 26, spread: 0.15 },
61043
- sentinel: { advancement: 0.9, capture: 1.12, safety: 1.72, power: 0.95, center: 1.28, unlock: 1.05, reply: 1.38, randomness: 18, spread: 0.12 },
61076
+ explorer: { advancement: 1.05, capture: 0.82, safety: 0.62, power: 0.8, center: 1.15, unlock: 1.05, reply: 0.7, randomness: 260, spread: 0.68, mobility: 0.75, trap: 0.5, endgame: 0.55 },
61077
+ impulsive: { advancement: 0.9, capture: 1.45, safety: 0.48, power: 1.15, center: 0.8, unlock: 0.9, reply: 0.55, randomness: 290, spread: 0.62, mobility: 0.85, trap: 0.62, endgame: 0.5 },
61078
+ runner: { advancement: 1.55, capture: 0.78, safety: 0.5, power: 0.95, center: 0.7, unlock: 1.1, reply: 0.55, randomness: 250, spread: 0.6, mobility: 0.72, trap: 0.45, endgame: 1.1 },
61079
+ hunter: { advancement: 0.95, capture: 1.45, safety: 0.9, power: 1.05, center: 0.95, unlock: 0.95, reply: 1, randomness: 90, spread: 0.3, mobility: 0.95, trap: 0.82, endgame: 0.76 },
61080
+ guardian: { advancement: 0.88, capture: 1, safety: 1.45, power: 0.85, center: 1.05, unlock: 1, reply: 1.15, randomness: 70, spread: 0.26, mobility: 0.82, trap: 0.72, endgame: 0.72 },
61081
+ jumper: { advancement: 1.12, capture: 1, safety: 0.92, power: 1.42, center: 1.18, unlock: 1.08, reply: 0.95, randomness: 95, spread: 0.32, mobility: 1.15, trap: 0.9, endgame: 0.82 },
61082
+ strategist: { advancement: 1.05, capture: 1.08, safety: 1.22, power: 1.08, center: 1.16, unlock: 1.1, reply: 1.25, randomness: 22, spread: 0.14, mobility: 1.08, trap: 1.06, endgame: 1 },
61083
+ predator: { advancement: 0.98, capture: 1.68, safety: 1.02, power: 1.34, center: 1, unlock: 1, reply: 1.12, randomness: 28, spread: 0.16, mobility: 1.02, trap: 1.18, endgame: 0.82 },
61084
+ sprinter: { advancement: 1.72, capture: 0.9, safety: 0.95, power: 1.08, center: 0.86, unlock: 1.18, reply: 1, randomness: 26, spread: 0.15, mobility: 0.95, trap: 0.78, endgame: 1.42 },
61085
+ sentinel: { advancement: 0.9, capture: 1.12, safety: 1.72, power: 0.95, center: 1.28, unlock: 1.05, reply: 1.38, randomness: 18, spread: 0.12, mobility: 0.86, trap: 1.04, endgame: 0.84 },
61086
+ oracle: { advancement: 1, capture: 1.12, safety: 1.42, power: 1.1, center: 1.18, unlock: 1.08, reply: 1.8, randomness: 8, spread: 0.08, mobility: 1.06, trap: 1.22, endgame: 1.08 },
61087
+ ambusher: { advancement: 0.9, capture: 1.48, safety: 1.08, power: 1.46, center: 1.05, unlock: 1.02, reply: 1.32, randomness: 14, spread: 0.1, mobility: 1.12, trap: 1.72, endgame: 0.92 },
61088
+ locksmith: { advancement: 0.88, capture: 1.04, safety: 1.55, power: 1.02, center: 1.48, unlock: 1.12, reply: 1.52, randomness: 12, spread: 0.1, mobility: 1.58, trap: 1.24, endgame: 0.86 },
61089
+ storm: { advancement: 1.18, capture: 1.38, safety: 0.98, power: 1.62, center: 1.08, unlock: 1.18, reply: 1.22, randomness: 18, spread: 0.13, mobility: 1.36, trap: 1.28, endgame: 1.02 },
61090
+ matriarch: { advancement: 0.96, capture: 1.18, safety: 1.64, power: 1.18, center: 1.22, unlock: 1.08, reply: 1.66, randomness: 10, spread: 0.08, mobility: 1.02, trap: 1.36, endgame: 1 },
61091
+ endgame: { advancement: 1.46, capture: 1, safety: 1.28, power: 1.04, center: 0.94, unlock: 1.08, reply: 1.44, randomness: 10, spread: 0.09, mobility: 0.98, trap: 1.02, endgame: 1.86 },
61044
61092
  };
61045
61093
  const DEFAULT_BOT_PROFILE_BY_DIFFICULTY = {
61046
61094
  easy: 'explorer',
@@ -61325,7 +61373,7 @@ function getPowerMoves(state, piece, animal) {
61325
61373
  const directions = getPowerDirections(animal);
61326
61374
  const moves = [];
61327
61375
  for (const direction of directions) {
61328
- for (let distance = 1; distance <= 3; distance += 1) {
61376
+ for (let distance = 1; distance < state.boardSize; distance += 1) {
61329
61377
  const target = {
61330
61378
  row: piece.position.row + direction.row * distance,
61331
61379
  col: piece.position.col + direction.col * distance,
@@ -61412,6 +61460,9 @@ function scoreBotMove(state, move, difficulty, style) {
61412
61460
  score += 14 * style.power;
61413
61461
  if (wouldUnlockPower(state, color, move.to))
61414
61462
  score += 90 * style.unlock;
61463
+ score += countPowerReachAfterMove(state, move, color) * (difficulty === 'hard' ? 8 : 4) * style.mobility;
61464
+ score += countProtectedThreatsAfterMove(state, move, color) * (difficulty === 'hard' ? 36 : 18) * style.trap;
61465
+ score += scoreEndgamePressure(state, move, color) * style.endgame;
61415
61466
  if (difficulty === 'hard' && isSquareVulnerableAfterMove(state, move)) {
61416
61467
  score -= (targetPiece ? 80 : 140) * style.safety;
61417
61468
  }
@@ -61448,12 +61499,65 @@ function scoreBotMoveWithLookahead(state, move, difficulty, style) {
61448
61499
  const replyWeight = difficulty === 'easy' ? 0.12 : difficulty === 'normal' ? 0.32 : 0.48;
61449
61500
  score -= opponentBestReply * replyWeight * style.reply;
61450
61501
  }
61502
+ if (difficulty === 'hard') {
61503
+ score += scoreBestCounterplay(afterMove, state.currentTurn, style) * 0.28;
61504
+ }
61451
61505
  }
61452
61506
  catch {
61453
61507
  score -= 1000;
61454
61508
  }
61455
61509
  return score;
61456
61510
  }
61511
+ function countPowerReachAfterMove(state, move, color) {
61512
+ try {
61513
+ const afterMove = applyChessimalsMove(state, move);
61514
+ const evaluationState = { ...afterMove, currentTurn: color };
61515
+ return getChessimalsAllLegalMoves(evaluationState, color).filter((nextMove) => nextMove.kind === 'power').length;
61516
+ }
61517
+ catch {
61518
+ return 0;
61519
+ }
61520
+ }
61521
+ function countProtectedThreatsAfterMove(state, move, color) {
61522
+ try {
61523
+ const afterMove = applyChessimalsMove(state, move);
61524
+ const evaluationState = { ...afterMove, currentTurn: color };
61525
+ const ourMoves = getChessimalsAllLegalMoves(evaluationState, color);
61526
+ const enemyPieces = activePieces(afterMove).filter((piece) => piece.color !== color && !piece.captured);
61527
+ return enemyPieces.filter((piece) => ourMoves.some((nextMove) => nextMove.capturesPieceId === piece.id)).length;
61528
+ }
61529
+ catch {
61530
+ return 0;
61531
+ }
61532
+ }
61533
+ function scoreEndgamePressure(state, move, color) {
61534
+ const remainingEnemyPieces = activePieces(state).filter((piece) => piece.color !== color && !piece.captured).length;
61535
+ const urgency = remainingEnemyPieces <= Math.max(2, Math.floor(state.boardSize / 2)) ? 1.6 : 1;
61536
+ const distanceToPromotion = color === 'white' ? move.to.row : state.boardSize - 1 - move.to.row;
61537
+ return Math.max(0, state.boardSize - distanceToPromotion) * 14 * urgency;
61538
+ }
61539
+ function scoreBestCounterplay(afterMove, color, style) {
61540
+ const opponentMoves = getChessimalsAllLegalMoves(afterMove);
61541
+ if (opponentMoves.length === 0)
61542
+ return 900;
61543
+ const replies = opponentMoves.slice(0, 16).map((opponentMove) => {
61544
+ try {
61545
+ const afterReply = applyChessimalsMove(afterMove, opponentMove);
61546
+ if (afterReply.status === 'finished')
61547
+ return -6000;
61548
+ const counterState = { ...afterReply, currentTurn: color };
61549
+ const counterMoves = getChessimalsAllLegalMoves(counterState, color);
61550
+ const bestCounter = counterMoves
61551
+ .map((counterMove) => scoreBotMove(counterState, counterMove, 'hard', style))
61552
+ .sort((a, b) => b - a)[0] ?? 0;
61553
+ return bestCounter;
61554
+ }
61555
+ catch {
61556
+ return -1000;
61557
+ }
61558
+ });
61559
+ return Math.min(...replies);
61560
+ }
61457
61561
  function pickNoisyBotMove(scored, spread) {
61458
61562
  if (scored.length === 0)
61459
61563
  return undefined;
@@ -62486,10 +62590,10 @@ const MINI_GAMES_I18N = {
62486
62590
  chessimalsRulePowersTitle: 'Cuándo se activan los poderes',
62487
62591
  chessimalsRulePowersBody: 'Tus cartas se desbloquean cuando uno de tus peones cruza la línea central o cuando un peón rival entra en tu mitad del tablero.',
62488
62592
  chessimalsRuleCardsTitle: 'Cartas de animales',
62489
- chessimalsRuleEagle: 'Águila: se mueve hasta 3 casillas en diagonal, hacia adelante o atrás.',
62490
- chessimalsRuleBull: 'Toro: se mueve hasta 3 casillas en línea recta, incluso hacia los lados.',
62593
+ chessimalsRuleEagle: 'Águila: se mueve en diagonal por todo el tablero, hacia adelante o atrás, sin entrar a la última fila.',
62594
+ chessimalsRuleBull: 'Toro: se mueve en línea recta por todo el tablero, incluso hacia los lados, sin entrar a la última fila.',
62491
62595
  chessimalsRuleKangaroo: 'Canguro: salta en L, como el caballo del ajedrez. Puede saltar por encima de piezas y caer libre o capturar una pieza rival.',
62492
- chessimalsRuleLion: 'León: se mueve hasta 3 casillas en cualquier dirección.',
62596
+ chessimalsRuleLion: 'León: se mueve en cualquier dirección por todo el tablero, sin entrar a la última fila.',
62493
62597
  chessimalsRuleLimitsTitle: 'Reglas de equilibrio',
62494
62598
  chessimalsRuleLimitsBody: 'Cada carta se usa una sola vez por partida. Ningún poder puede entrar directamente a la última fila: el paso final para ganar siempre debe ser un avance normal.',
62495
62599
  chessimalsBoardSize: 'Tamaño del tablero',
@@ -62602,6 +62706,18 @@ const MINI_GAMES_I18N = {
62602
62706
  chessimalsBotSprinterBody: 'Optimiza rutas de promoción.',
62603
62707
  chessimalsBotSentinel: 'Centinela',
62604
62708
  chessimalsBotSentinelBody: 'Defiende sólido y castiga errores.',
62709
+ chessimalsBotOracle: 'Oráculo',
62710
+ chessimalsBotOracleBody: 'Lee respuestas y evita trampas profundas.',
62711
+ chessimalsBotAmbusher: 'Emboscador',
62712
+ chessimalsBotAmbusherBody: 'Prepara capturas dobles con poderes largos.',
62713
+ chessimalsBotLocksmith: 'Cerrajero',
62714
+ chessimalsBotLocksmithBody: 'Cierra el centro y reduce tus rutas.',
62715
+ chessimalsBotStorm: 'Tormenta',
62716
+ chessimalsBotStormBody: 'Usa poderes largos para presionar todo el tablero.',
62717
+ chessimalsBotMatriarch: 'Matriarca',
62718
+ chessimalsBotMatriarchBody: 'Protege su estructura y gana por desgaste.',
62719
+ chessimalsBotEndgame: 'Finalista',
62720
+ chessimalsBotEndgameBody: 'Convierte ventajas pequeñas en promoción.',
62605
62721
  chessimalsBotExplorerTendency: 'Tiende a variar rutas, probar el centro y cometer errores suaves.',
62606
62722
  chessimalsBotImpulsiveTendency: 'Tiende a capturar rápido, incluso cuando puede quedar expuesto.',
62607
62723
  chessimalsBotRunnerTendency: 'Tiende a avanzar hacia la promoción antes que defender.',
@@ -62612,6 +62728,12 @@ const MINI_GAMES_I18N = {
62612
62728
  chessimalsBotPredatorTendency: 'Tiende a forzar capturas y usar poderes agresivos.',
62613
62729
  chessimalsBotSprinterTendency: 'Tiende a encontrar caminos rápidos de promoción.',
62614
62730
  chessimalsBotSentinelTendency: 'Tiende a defender sólido y castigar errores.',
62731
+ chessimalsBotOracleTendency: 'Tiende a anticipar respuestas y elegir jugadas difíciles de refutar.',
62732
+ chessimalsBotAmbusherTendency: 'Tiende a dejar piezas bajo amenaza múltiple antes de capturar.',
62733
+ chessimalsBotLocksmithTendency: 'Tiende a cortar rutas por el centro y dejarte sin buenas casillas.',
62734
+ chessimalsBotStormTendency: 'Tiende a convertir poderes largos en presión desde varios ángulos.',
62735
+ chessimalsBotMatriarchTendency: 'Tiende a conservar piezas y cambiar solo cuando queda mejor.',
62736
+ chessimalsBotEndgameTendency: 'Tiende a simplificar y correr hacia la promoción cuando ve ventaja.',
62615
62737
  chessimalsBotReportTitle: 'Reporte del bot',
62616
62738
  chessimalsBotReportVs: 'Contra {bot}',
62617
62739
  chessimalsBotReportBody: '{outcome}. Hizo {captures} capturas y usó {powers} poderes. {style}',
@@ -62659,7 +62781,7 @@ const MINI_GAMES_I18N = {
62659
62781
  chessimalsTutorialStep4Title: 'Devuelve el turno',
62660
62782
  chessimalsTutorialStep4Body: 'Mueve el peón negro de la columna F una casilla hacia abajo para continuar.',
62661
62783
  chessimalsTutorialStep5Title: 'Usa el poder Canguro',
62662
- chessimalsTutorialStep5Body: 'Selecciona la carta Canguro y salta en L para capturar el peón negro.',
62784
+ chessimalsTutorialStep5Body: 'Selecciona la carta Canguro y salta en L para capturar el peón negro. Las otras cartas pueden cruzar todo el tablero, pero ningún poder puede entrar a la última fila.',
62663
62785
  chessimalsTutorialStep6Title: 'Prepara la llegada',
62664
62786
  chessimalsTutorialStep6Body: 'Mueve el último peón negro hacia abajo. Después tendrás camino para ganar.',
62665
62787
  chessimalsTutorialStep7Title: 'Llega a la última fila',
@@ -62847,10 +62969,10 @@ const MINI_GAMES_I18N = {
62847
62969
  chessimalsRulePowersTitle: 'When powers unlock',
62848
62970
  chessimalsRulePowersBody: 'Your cards unlock when one of your pawns crosses the center line, or when a rival pawn enters your half of the board.',
62849
62971
  chessimalsRuleCardsTitle: 'Animal cards',
62850
- chessimalsRuleEagle: 'Eagle: moves up to 3 squares diagonally, forward or backward.',
62851
- chessimalsRuleBull: 'Bull: moves up to 3 squares in a straight line, including sideways.',
62972
+ chessimalsRuleEagle: 'Eagle: moves diagonally across the whole board, forward or backward, without entering the final row.',
62973
+ chessimalsRuleBull: 'Bull: moves in a straight line across the whole board, including sideways, without entering the final row.',
62852
62974
  chessimalsRuleKangaroo: 'Kangaroo: jumps in an L shape, like a chess knight. It can jump over pieces and land on an empty square or capture a rival piece.',
62853
- chessimalsRuleLion: 'Lion: moves up to 3 squares in any direction.',
62975
+ chessimalsRuleLion: 'Lion: moves in any direction across the whole board, without entering the final row.',
62854
62976
  chessimalsRuleLimitsTitle: 'Balance rules',
62855
62977
  chessimalsRuleLimitsBody: 'Each card can be used once per game. No power can land directly on the final row: the winning step must always be a normal forward move.',
62856
62978
  chessimalsBoardSize: 'Board size',
@@ -62963,6 +63085,18 @@ const MINI_GAMES_I18N = {
62963
63085
  chessimalsBotSprinterBody: 'Optimizes promotion routes.',
62964
63086
  chessimalsBotSentinel: 'Sentinel',
62965
63087
  chessimalsBotSentinelBody: 'Defends solidly and punishes mistakes.',
63088
+ chessimalsBotOracle: 'Oracle',
63089
+ chessimalsBotOracleBody: 'Reads replies and avoids deep traps.',
63090
+ chessimalsBotAmbusher: 'Ambusher',
63091
+ chessimalsBotAmbusherBody: 'Sets up double captures with long powers.',
63092
+ chessimalsBotLocksmith: 'Locksmith',
63093
+ chessimalsBotLocksmithBody: 'Closes the center and reduces your routes.',
63094
+ chessimalsBotStorm: 'Storm',
63095
+ chessimalsBotStormBody: 'Uses long powers to pressure the whole board.',
63096
+ chessimalsBotMatriarch: 'Matriarch',
63097
+ chessimalsBotMatriarchBody: 'Protects structure and wins by attrition.',
63098
+ chessimalsBotEndgame: 'Endgame',
63099
+ chessimalsBotEndgameBody: 'Turns small edges into promotion.',
62966
63100
  chessimalsBotExplorerTendency: 'Tends to vary routes, test the center, and make soft mistakes.',
62967
63101
  chessimalsBotImpulsiveTendency: 'Tends to capture quickly, even when it can become exposed.',
62968
63102
  chessimalsBotRunnerTendency: 'Tends to push toward promotion before defending.',
@@ -62973,6 +63107,12 @@ const MINI_GAMES_I18N = {
62973
63107
  chessimalsBotPredatorTendency: 'Tends to force captures and use aggressive powers.',
62974
63108
  chessimalsBotSprinterTendency: 'Tends to find fast promotion paths.',
62975
63109
  chessimalsBotSentinelTendency: 'Tends to defend solidly and punish mistakes.',
63110
+ chessimalsBotOracleTendency: 'Tends to anticipate replies and choose hard-to-refute moves.',
63111
+ chessimalsBotAmbusherTendency: 'Tends to leave pieces under multiple threats before capturing.',
63112
+ chessimalsBotLocksmithTendency: 'Tends to close central routes and leave you without good squares.',
63113
+ chessimalsBotStormTendency: 'Tends to turn long powers into pressure from several angles.',
63114
+ chessimalsBotMatriarchTendency: 'Tends to preserve pieces and trade only when it improves.',
63115
+ chessimalsBotEndgameTendency: 'Tends to simplify and race toward promotion when ahead.',
62976
63116
  chessimalsBotReportTitle: 'Bot report',
62977
63117
  chessimalsBotReportVs: 'Against {bot}',
62978
63118
  chessimalsBotReportBody: '{outcome}. It made {captures} captures and used {powers} powers. {style}',
@@ -63020,7 +63160,7 @@ const MINI_GAMES_I18N = {
63020
63160
  chessimalsTutorialStep4Title: 'Return the turn',
63021
63161
  chessimalsTutorialStep4Body: 'Move the black pawn on file F one square downward to continue.',
63022
63162
  chessimalsTutorialStep5Title: 'Use the Kangaroo power',
63023
- chessimalsTutorialStep5Body: 'Select the Kangaroo card and jump in an L shape to capture the black pawn.',
63163
+ chessimalsTutorialStep5Body: 'Select the Kangaroo card and jump in an L shape to capture the black pawn. The other cards can cross the whole board, but no power can enter the final row.',
63024
63164
  chessimalsTutorialStep6Title: 'Prepare the finish',
63025
63165
  chessimalsTutorialStep6Body: 'Move the last black pawn downward. Then your path to win is open.',
63026
63166
  chessimalsTutorialStep7Title: 'Reach the last row',