

'''simple docstring'''






# Author: OMKAR PATHAK, Nwachukwu Chidiebere

# Use a Python dictionary to construct the graph.
from __future__ import annotations

from pprint import pformat
from typing import Generic, TypeVar

lowerCAmelCase__   		=      TypeVar('''T''')






class      lowercase_      (Generic[T] ):




  """simple docstring"""




  def __init__( self  :	int   ,lowercase__  :	bool = True     ):
   __lowercase				    =					{}  # dictionary of lists
   __lowercase				    =					directed






  def    SCREAMING_SNAKE_CASE ( self  :	List[str]   ,lowercase__  :	T   ,lowercase__  :	T     ):

   if not self.directed:  # For undirected graphs
    # if both source vertex and destination vertex are both present in the
    # adjacency list, add destination vertex to source vertex list of adjacent
    # vertices and add source vertex to destination vertex list of adjacent
    # vertices.
    if source_vertex in self.adj_list and destination_vertex in self.adj_list:
     self.adj_list[source_vertex].append(lowercase__     )
     self.adj_list[destination_vertex].append(lowercase__     )
    # if only source vertex is present in adjacency list, add destination vertex
    # to source vertex list of adjacent vertices, then create a new vertex with
    # destination vertex as key and assign a list containing the source vertex
    # as it's first adjacent vertex.
    elif source_vertex in self.adj_list:
     self.adj_list[source_vertex].append(lowercase__     )
     __lowercase				    =					[source_vertex]
    # if only destination vertex is present in adjacency list, add source vertex
    # to destination vertex list of adjacent vertices, then create a new vertex
    # with source vertex as key and assign a list containing the source vertex
    # as it's first adjacent vertex.
    elif destination_vertex in self.adj_list:
     self.adj_list[destination_vertex].append(lowercase__     )
     __lowercase				    =					[destination_vertex]
    # if both source vertex and destination vertex are not present in adjacency
    # list, create a new vertex with source vertex as key and assign a list
    # containing the destination vertex as it's first adjacent vertex also
    # create a new vertex with destination vertex as key and assign a list
    # containing the source vertex as it's first adjacent vertex.
    else:
     __lowercase				    =					[destination_vertex]
     __lowercase				    =					[source_vertex]
   else:  # For directed graphs
    # if both source vertex and destination vertex are present in adjacency
    # list, add destination vertex to source vertex list of adjacent vertices.
    if source_vertex in self.adj_list and destination_vertex in self.adj_list:
     self.adj_list[source_vertex].append(lowercase__     )
    # if only source vertex is present in adjacency list, add destination
    # vertex to source vertex list of adjacent vertices and create a new vertex
    # with destination vertex as key, which has no adjacent vertex
    elif source_vertex in self.adj_list:
     self.adj_list[source_vertex].append(lowercase__     )
     __lowercase				    =					[]
    # if only destination vertex is present in adjacency list, create a new
    # vertex with source vertex as key and assign a list containing destination
    # vertex as first adjacent vertex
    elif destination_vertex in self.adj_list:
     __lowercase				    =					[destination_vertex]
    # if both source vertex and destination vertex are not present in adjacency
    # list, create a new vertex with source vertex as key and a list containing
    # destination vertex as it's first adjacent vertex. Then create a new vertex
    # with destination vertex as key, which has no adjacent vertex
    else:
     __lowercase				    =					[destination_vertex]
     __lowercase				    =					[]

   return self






  def __repr__( self  :	Optional[int]     ):
   return pformat(self.adj_list     )







class 							UpperCamelCase_       :  # Public class to implement a graph

    '''simple docstring'''






    def __init__(     self :      str   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      list[list[bool]])		->None:





           '''simple docstring'''

           A__ 					=       row
           A__ 					=       col
           A__ 					=       graph


    def 			SCREAMING_SNAKE_CASE				(     self :      Any   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      list[list[bool]])		->bool:





           '''simple docstring'''

           return (
               0 <= i < self.ROW
               and 0 <= j < self.COL
               and not visited[i][j]
               and self.graph[i][j]
           )


    def 			SCREAMING_SNAKE_CASE				(     self :      Optional[int]   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      int   ,					UpperCAmelCase__ :      list[list[bool]])		->None:





           '''simple docstring'''

           A__ 					=       [-1, -1, -1, 0, 0, 1, 1, 1]  # Coordinate order
           A__ 					=       [-1, 0, 1, -1, 1, -1, 0, 1]
           A__ 					=       True  # Make those cells visited
           for k in range(8):
                  if self.is_safe(i + row_nbr[k]   ,					j + col_nbr[k]   ,					UpperCAmelCase__):
                         self.diffs(i + row_nbr[k]   ,					j + col_nbr[k]   ,					UpperCAmelCase__)





    def 			SCREAMING_SNAKE_CASE				(     self :      Optional[Any])		->int:  # And finally, count all islands.





           '''simple docstring'''

           A__ 					=       [[False for j in range(self.COL)] for i in range(self.ROW)]
           A__ 					=       0
           for i in range(self.ROW):
                  for j in range(self.COL):
                         if visited[i][j] is False and self.graph[i][j] == 1:
                                self.diffs(UpperCAmelCase__   ,					UpperCAmelCase__   ,					UpperCAmelCase__)
                                count += 1
           return count


